FFmpeg
d3d12va_encode.c
Go to the documentation of this file.
1 /*
2  * Direct3D 12 HW acceleration video encoder
3  *
4  * Copyright (c) 2024 Intel Corporation
5  *
6  * This file is part of FFmpeg.
7  *
8  * FFmpeg is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * FFmpeg is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with FFmpeg; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21  */
22 
23 #include "libavutil/avassert.h"
24 #include "libavutil/common.h"
25 #include "libavutil/internal.h"
26 #include "libavutil/log.h"
27 #include "libavutil/mem.h"
28 #include "libavutil/pixdesc.h"
31 
32 #include "config_components.h"
33 #include "avcodec.h"
34 #include "d3d12va_encode.h"
35 #include "encode.h"
36 
38  HW_CONFIG_ENCODER_FRAMES(D3D12, D3D12VA),
39  NULL,
40 };
41 
43 {
44  uint64_t completion = ID3D12Fence_GetCompletedValue(psync_ctx->fence);
45  if (completion < psync_ctx->fence_value) {
46  if (FAILED(ID3D12Fence_SetEventOnCompletion(psync_ctx->fence, psync_ctx->fence_value, psync_ctx->event)))
47  return AVERROR(EINVAL);
48 
49  WaitForSingleObjectEx(psync_ctx->event, INFINITE, FALSE);
50  }
51 
52  return 0;
53 }
54 
56 {
58 
59  DX_CHECK(ID3D12CommandQueue_Signal(ctx->command_queue, ctx->sync_ctx.fence, ++ctx->sync_ctx.fence_value));
60  return d3d12va_fence_completion(&ctx->sync_ctx);
61 
62 fail:
63  return AVERROR(EINVAL);
64 }
65 
66 typedef struct CommandAllocator {
67  ID3D12CommandAllocator *command_allocator;
68  uint64_t fence_value;
70 
71 static int d3d12va_get_valid_command_allocator(AVCodecContext *avctx, ID3D12CommandAllocator **ppAllocator)
72 {
73  HRESULT hr;
75  CommandAllocator allocator;
76 
77  if (av_fifo_peek(ctx->allocator_queue, &allocator, 1, 0) >= 0) {
78  uint64_t completion = ID3D12Fence_GetCompletedValue(ctx->sync_ctx.fence);
79  if (completion >= allocator.fence_value) {
80  *ppAllocator = allocator.command_allocator;
81  av_fifo_read(ctx->allocator_queue, &allocator, 1);
82  return 0;
83  }
84  }
85 
86  hr = ID3D12Device_CreateCommandAllocator(ctx->hwctx->device, D3D12_COMMAND_LIST_TYPE_VIDEO_ENCODE,
87  &IID_ID3D12CommandAllocator, (void **)ppAllocator);
88  if (FAILED(hr)) {
89  av_log(avctx, AV_LOG_ERROR, "Failed to create a new command allocator!\n");
90  return AVERROR(EINVAL);
91  }
92 
93  return 0;
94 }
95 
96 static int d3d12va_discard_command_allocator(AVCodecContext *avctx, ID3D12CommandAllocator *pAllocator, uint64_t fence_value)
97 {
99 
100  CommandAllocator allocator = {
101  .command_allocator = pAllocator,
102  .fence_value = fence_value,
103  };
104 
105  av_fifo_write(ctx->allocator_queue, &allocator, 1);
106 
107  return 0;
108 }
109 
111  FFHWBaseEncodePicture *base_pic)
112 {
114  D3D12VAEncodePicture *pic = base_pic->priv;
115  uint64_t completion;
116 
117  av_assert0(base_pic->encode_issued);
118 
119  if (base_pic->encode_complete) {
120  // Already waited for this picture.
121  return 0;
122  }
123 
124  completion = ID3D12Fence_GetCompletedValue(ctx->sync_ctx.fence);
125  if (completion < pic->fence_value) {
126  if (FAILED(ID3D12Fence_SetEventOnCompletion(ctx->sync_ctx.fence, pic->fence_value,
127  ctx->sync_ctx.event)))
128  return AVERROR(EINVAL);
129 
130  WaitForSingleObjectEx(ctx->sync_ctx.event, INFINITE, FALSE);
131  }
132 
133  av_log(avctx, AV_LOG_DEBUG, "Sync to pic %"PRId64"/%"PRId64" "
134  "(input surface %p).\n", base_pic->display_order,
135  base_pic->encode_order, pic->input_surface->texture);
136 
137  av_frame_free(&base_pic->input_image);
138 
139  base_pic->encode_complete = 1;
140  return 0;
141 }
142 
145 {
147  int width = sizeof(D3D12_VIDEO_ENCODER_OUTPUT_METADATA) + sizeof(D3D12_VIDEO_ENCODER_FRAME_SUBREGION_METADATA);
148 #if CONFIG_AV1_D3D12VA_ENCODER
149  if (ctx->codec->d3d12_codec == D3D12_VIDEO_ENCODER_CODEC_AV1) {
150  width += sizeof(D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_SUBREGIONS_LAYOUT_DATA_TILES)
151  + sizeof(D3D12_VIDEO_ENCODER_AV1_POST_ENCODE_VALUES);
152  }
153 #endif
154  D3D12_HEAP_PROPERTIES encoded_meta_props = { .Type = D3D12_HEAP_TYPE_DEFAULT }, resolved_meta_props;
155  D3D12_HEAP_TYPE resolved_heap_type = D3D12_HEAP_TYPE_READBACK;
156  HRESULT hr;
157 
158  D3D12_RESOURCE_DESC meta_desc = {
159  .Dimension = D3D12_RESOURCE_DIMENSION_BUFFER,
160  .Alignment = 0,
161  .Width = ctx->req.MaxEncoderOutputMetadataBufferSize,
162  .Height = 1,
163  .DepthOrArraySize = 1,
164  .MipLevels = 1,
165  .Format = DXGI_FORMAT_UNKNOWN,
166  .SampleDesc = { .Count = 1, .Quality = 0 },
167  .Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR,
168  .Flags = D3D12_RESOURCE_FLAG_NONE,
169  };
170 
171  hr = ID3D12Device_CreateCommittedResource(ctx->hwctx->device, &encoded_meta_props, D3D12_HEAP_FLAG_NONE,
172  &meta_desc, D3D12_RESOURCE_STATE_COMMON, NULL,
173  &IID_ID3D12Resource, (void **)&pic->encoded_metadata);
174  if (FAILED(hr)) {
175  av_log(avctx, AV_LOG_ERROR, "Failed to create metadata buffer.\n");
176  return AVERROR_UNKNOWN;
177  }
178 
179  ctx->hwctx->device->lpVtbl->GetCustomHeapProperties(ctx->hwctx->device, &resolved_meta_props, 0, resolved_heap_type);
180 
181  meta_desc.Width = width;
182 
183  hr = ID3D12Device_CreateCommittedResource(ctx->hwctx->device, &resolved_meta_props, D3D12_HEAP_FLAG_NONE,
184  &meta_desc, D3D12_RESOURCE_STATE_COMMON, NULL,
185  &IID_ID3D12Resource, (void **)&pic->resolved_metadata);
186 
187  if (FAILED(hr)) {
188  av_log(avctx, AV_LOG_ERROR, "Failed to create output metadata buffer.\n");
189  return AVERROR_UNKNOWN;
190  }
191 
192  return 0;
193 }
194 
196  FFHWBaseEncodePicture *base_pic)
197 {
198  FFHWBaseEncodeContext *base_ctx = avctx->priv_data;
200  D3D12VAEncodePicture *pic = base_pic->priv;
201  AVD3D12VAFramesContext *frames_hwctx = base_ctx->input_frames->hwctx;
202  int err, i, j;
203  HRESULT hr;
205  void *ptr;
206  size_t bit_len;
207  ID3D12CommandAllocator *command_allocator = NULL;
208  ID3D12VideoEncodeCommandList2 *cmd_list = ctx->command_list;
209  D3D12_RESOURCE_BARRIER barriers[32] = { 0 };
210  D3D12_VIDEO_ENCODE_REFERENCE_FRAMES d3d12_refs = { 0 };
211  int barriers_ref_index = 0;
212  D3D12_RESOURCE_BARRIER *barriers_ref = NULL;
213 
214  D3D12_VIDEO_ENCODER_SEQUENCE_CONTROL_FLAGS seq_flags = D3D12_VIDEO_ENCODER_SEQUENCE_CONTROL_FLAG_NONE;
215 
216  // Request intra refresh if enabled
217  if (ctx->intra_refresh.Mode != D3D12_VIDEO_ENCODER_INTRA_REFRESH_MODE_NONE) {
218  seq_flags |= D3D12_VIDEO_ENCODER_SEQUENCE_CONTROL_FLAG_REQUEST_INTRA_REFRESH;
219  }
220 
221  D3D12_VIDEO_ENCODER_ENCODEFRAME_INPUT_ARGUMENTS input_args = {
222  .SequenceControlDesc = {
223  .Flags = seq_flags,
224  .IntraRefreshConfig = ctx->intra_refresh,
225  .RateControl = ctx->rc,
226  .PictureTargetResolution = ctx->resolution,
227  .SelectedLayoutMode = D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_FULL_FRAME,
228  .FrameSubregionsLayoutData = ctx->subregions_layout,
229  .CodecGopSequence = ctx->gop,
230  },
231  .pInputFrame = pic->input_surface->texture,
232  .InputFrameSubresource = 0,
233  };
234 
235  D3D12_VIDEO_ENCODER_ENCODEFRAME_OUTPUT_ARGUMENTS output_args = { 0 };
236 
237  D3D12_VIDEO_ENCODER_RESOLVE_METADATA_INPUT_ARGUMENTS input_metadata = {
238  .EncoderCodec = ctx->codec->d3d12_codec,
239  .EncoderProfile = ctx->profile->d3d12_profile,
240  .EncoderInputFormat = frames_hwctx->format,
241  .EncodedPictureEffectiveResolution = ctx->resolution,
242  };
243 
244  D3D12_VIDEO_ENCODER_RESOLVE_METADATA_OUTPUT_ARGUMENTS output_metadata = { 0 };
245 
246  memset(data, 0, sizeof(data));
247 
248  av_log(avctx, AV_LOG_DEBUG, "Issuing encode for pic %"PRId64"/%"PRId64" "
249  "as type %s.\n", base_pic->display_order, base_pic->encode_order,
251  if (base_pic->nb_refs[0] == 0 && base_pic->nb_refs[1] == 0) {
252  av_log(avctx, AV_LOG_DEBUG, "No reference pictures.\n");
253  } else {
254  av_log(avctx, AV_LOG_DEBUG, "L0 refers to");
255  for (i = 0; i < base_pic->nb_refs[0]; i++) {
256  av_log(avctx, AV_LOG_DEBUG, " %"PRId64"/%"PRId64,
257  base_pic->refs[0][i]->display_order, base_pic->refs[0][i]->encode_order);
258  }
259  av_log(avctx, AV_LOG_DEBUG, ".\n");
260 
261  if (base_pic->nb_refs[1]) {
262  av_log(avctx, AV_LOG_DEBUG, "L1 refers to");
263  for (i = 0; i < base_pic->nb_refs[1]; i++) {
264  av_log(avctx, AV_LOG_DEBUG, " %"PRId64"/%"PRId64,
265  base_pic->refs[1][i]->display_order, base_pic->refs[1][i]->encode_order);
266  }
267  av_log(avctx, AV_LOG_DEBUG, ".\n");
268  }
269  }
270 
271  av_assert0(!base_pic->encode_issued);
272  for (i = 0; i < base_pic->nb_refs[0]; i++) {
273  av_assert0(base_pic->refs[0][i]);
274  av_assert0(base_pic->refs[0][i]->encode_issued);
275  }
276  for (i = 0; i < base_pic->nb_refs[1]; i++) {
277  av_assert0(base_pic->refs[1][i]);
278  av_assert0(base_pic->refs[1][i]->encode_issued);
279  }
280 
281  av_log(avctx, AV_LOG_DEBUG, "Input surface is %p.\n", pic->input_surface->texture);
282 
283  pic->recon_surface = (AVD3D12VAFrame *)base_pic->recon_image->data[0];
284  av_log(avctx, AV_LOG_DEBUG, "Recon surface is %p.\n",
285  pic->recon_surface->texture);
286 
287  pic->subresource_index = ctx->is_texture_array ? pic->recon_surface->subresource_index : 0;
288 
289  pic->output_buffer_ref = av_buffer_pool_get(ctx->output_buffer_pool);
290  if (!pic->output_buffer_ref) {
291  err = AVERROR(ENOMEM);
292  goto fail;
293  }
294  pic->output_buffer = (ID3D12Resource *)pic->output_buffer_ref->data;
295  av_log(avctx, AV_LOG_DEBUG, "Output buffer is %p.\n",
296  pic->output_buffer);
297 
298  err = d3d12va_encode_create_metadata_buffers(avctx, pic);
299  if (err < 0)
300  goto fail;
301 
302  if (ctx->codec->init_picture_params) {
303  err = ctx->codec->init_picture_params(avctx, base_pic);
304  if (err < 0) {
305  av_log(avctx, AV_LOG_ERROR, "Failed to initialise picture "
306  "parameters: %d.\n", err);
307  goto fail;
308  }
309  }
310 
311  if (base_pic->type == FF_HW_PICTURE_TYPE_IDR) {
312  if (ctx->codec->write_sequence_header) {
313  bit_len = 8 * sizeof(data);
314  err = ctx->codec->write_sequence_header(avctx, data, &bit_len);
315  if (err < 0) {
316  av_log(avctx, AV_LOG_ERROR, "Failed to write per-sequence "
317  "header: %d.\n", err);
318  goto fail;
319  }
320  pic->header_size = (int)bit_len / 8;
321  pic->aligned_header_size = pic->header_size % ctx->req.CompressedBitstreamBufferAccessAlignment ?
322  FFALIGN(pic->header_size, ctx->req.CompressedBitstreamBufferAccessAlignment) :
323  pic->header_size;
324 
325  hr = ID3D12Resource_Map(pic->output_buffer, 0, NULL, (void **)&ptr);
326  if (FAILED(hr)) {
327  err = AVERROR_UNKNOWN;
328  goto fail;
329  }
330 
331  memcpy(ptr, data, pic->aligned_header_size);
332  ID3D12Resource_Unmap(pic->output_buffer, 0, NULL);
333  }
334  }
335 
336  d3d12_refs.NumTexture2Ds = base_pic->nb_refs[0] + base_pic->nb_refs[1];
337  if (d3d12_refs.NumTexture2Ds) {
338  d3d12_refs.ppTexture2Ds = av_calloc(d3d12_refs.NumTexture2Ds,
339  sizeof(*d3d12_refs.ppTexture2Ds));
340  if (!d3d12_refs.ppTexture2Ds) {
341  err = AVERROR(ENOMEM);
342  goto fail;
343  }
344 
345  if (ctx->is_texture_array) {
346  d3d12_refs.pSubresources = av_calloc(d3d12_refs.NumTexture2Ds,
347  sizeof(*d3d12_refs.pSubresources));
348  if (!d3d12_refs.pSubresources) {
349  err = AVERROR(ENOMEM);
350  goto fail;
351  }
352  }
353 
354  i = 0;
355  for (j = 0; j < base_pic->nb_refs[0]; j++) {
356  d3d12_refs.ppTexture2Ds[i] = ((D3D12VAEncodePicture *)base_pic->refs[0][j]->priv)->recon_surface->texture;
357  if (ctx->is_texture_array)
358  d3d12_refs.pSubresources[i] = ((D3D12VAEncodePicture *)base_pic->refs[0][j]->priv)->subresource_index;
359  i++;
360  }
361  for (j = 0; j < base_pic->nb_refs[1]; j++) {
362  d3d12_refs.ppTexture2Ds[i] = ((D3D12VAEncodePicture *)base_pic->refs[1][j]->priv)->recon_surface->texture;
363  if (ctx->is_texture_array)
364  d3d12_refs.pSubresources[i] = ((D3D12VAEncodePicture *)base_pic->refs[1][j]->priv)->subresource_index;
365  i++;
366  }
367  }
368 
369  input_args.PictureControlDesc.IntraRefreshFrameIndex = ctx->intra_refresh_frame_index;
370  if (base_pic->is_reference)
371  input_args.PictureControlDesc.Flags |= D3D12_VIDEO_ENCODER_PICTURE_CONTROL_FLAG_USED_AS_REFERENCE_PICTURE;
372 
373  input_args.PictureControlDesc.PictureControlCodecData = pic->pic_ctl;
374  input_args.PictureControlDesc.ReferenceFrames = d3d12_refs;
375  input_args.CurrentFrameBitstreamMetadataSize = pic->aligned_header_size;
376 
377  output_args.Bitstream.pBuffer = pic->output_buffer;
378  output_args.Bitstream.FrameStartOffset = pic->aligned_header_size;
379  output_args.ReconstructedPicture.pReconstructedPicture = pic->recon_surface->texture;
380  output_args.ReconstructedPicture.ReconstructedPictureSubresource = ctx->is_texture_array ? pic->subresource_index : 0;
381  output_args.EncoderOutputMetadata.pBuffer = pic->encoded_metadata;
382  output_args.EncoderOutputMetadata.Offset = 0;
383 
384  input_metadata.HWLayoutMetadata.pBuffer = pic->encoded_metadata;
385  input_metadata.HWLayoutMetadata.Offset = 0;
386 
387  output_metadata.ResolvedLayoutMetadata.pBuffer = pic->resolved_metadata;
388  output_metadata.ResolvedLayoutMetadata.Offset = 0;
389 
390  err = d3d12va_get_valid_command_allocator(avctx, &command_allocator);
391  if (err < 0)
392  goto fail;
393 
394  hr = ID3D12CommandAllocator_Reset(command_allocator);
395  if (FAILED(hr)) {
396  err = AVERROR_UNKNOWN;
397  goto fail;
398  }
399 
400  hr = ID3D12VideoEncodeCommandList2_Reset(cmd_list, command_allocator);
401  if (FAILED(hr)) {
402  err = AVERROR_UNKNOWN;
403  goto fail;
404  }
405 
406 #define TRANSITION_BARRIER(res, subres, before, after) \
407  (D3D12_RESOURCE_BARRIER) { \
408  .Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION, \
409  .Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE, \
410  .Transition = { \
411  .pResource = res, \
412  .Subresource = subres, \
413  .StateBefore = before, \
414  .StateAfter = after, \
415  }, \
416  }
417 
418  barriers[0] = TRANSITION_BARRIER(pic->input_surface->texture,
419  D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES,
420  D3D12_RESOURCE_STATE_COMMON,
421  D3D12_RESOURCE_STATE_VIDEO_ENCODE_READ);
422  barriers[1] = TRANSITION_BARRIER(pic->output_buffer,
423  D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES,
424  D3D12_RESOURCE_STATE_COMMON,
425  D3D12_RESOURCE_STATE_VIDEO_ENCODE_WRITE);
426  barriers[2] = TRANSITION_BARRIER(pic->encoded_metadata,
427  D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES,
428  D3D12_RESOURCE_STATE_COMMON,
429  D3D12_RESOURCE_STATE_VIDEO_ENCODE_WRITE);
430  barriers[3] = TRANSITION_BARRIER(pic->resolved_metadata,
431  D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES,
432  D3D12_RESOURCE_STATE_COMMON,
433  D3D12_RESOURCE_STATE_VIDEO_ENCODE_WRITE);
434 
435  ID3D12VideoEncodeCommandList2_ResourceBarrier(cmd_list, 4, barriers);
436 
437  if (ctx->is_texture_array)
438  barriers_ref = av_calloc(base_ctx->recon_frames->initial_pool_size * ctx->plane_count,
439  sizeof(D3D12_RESOURCE_BARRIER));
440  else
441  barriers_ref = av_calloc(MAX_DPB_SIZE, sizeof(D3D12_RESOURCE_BARRIER));
442 
443  if (ctx->is_texture_array) {
444  D3D12_RESOURCE_DESC references_tex_array_desc = { 0 };
445  pic->recon_surface->texture->lpVtbl->GetDesc(pic->recon_surface->texture, &references_tex_array_desc);
446 
447  for (uint32_t reference_subresource = 0; reference_subresource < references_tex_array_desc.DepthOrArraySize;
448  reference_subresource++) {
449 
450  uint32_t array_size = references_tex_array_desc.DepthOrArraySize;
451  uint32_t mip_slice = reference_subresource % references_tex_array_desc.MipLevels;
452  uint32_t array_slice = (reference_subresource / references_tex_array_desc.MipLevels) % array_size;
453 
454  for (uint32_t plane_slice = 0; plane_slice < ctx->plane_count; plane_slice++) {
455  uint32_t outputSubresource = mip_slice + array_slice * references_tex_array_desc.MipLevels +
456  plane_slice * references_tex_array_desc.MipLevels * array_size;
457  if (reference_subresource == pic->subresource_index) {
458  barriers_ref[barriers_ref_index++] = TRANSITION_BARRIER(pic->recon_surface->texture, outputSubresource,
459  D3D12_RESOURCE_STATE_COMMON,
460  D3D12_RESOURCE_STATE_VIDEO_ENCODE_WRITE);
461  } else {
462  barriers_ref[barriers_ref_index++] = TRANSITION_BARRIER(pic->recon_surface->texture, outputSubresource,
463  D3D12_RESOURCE_STATE_COMMON,
464  D3D12_RESOURCE_STATE_VIDEO_ENCODE_READ);
465  }
466  }
467  }
468  } else {
469  barriers_ref[barriers_ref_index++] = TRANSITION_BARRIER(pic->recon_surface->texture,
470  D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES,
471  D3D12_RESOURCE_STATE_COMMON,
472  D3D12_RESOURCE_STATE_VIDEO_ENCODE_WRITE);
473 
474  if (d3d12_refs.NumTexture2Ds) {
475  for (i = 0; i < d3d12_refs.NumTexture2Ds; i++)
476  barriers_ref[barriers_ref_index++] = TRANSITION_BARRIER(d3d12_refs.ppTexture2Ds[i],
477  D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES,
478  D3D12_RESOURCE_STATE_COMMON,
479  D3D12_RESOURCE_STATE_VIDEO_ENCODE_READ);
480  }
481  }
482  ID3D12VideoEncodeCommandList2_ResourceBarrier(cmd_list, barriers_ref_index, barriers_ref);
483 
484  ID3D12VideoEncodeCommandList2_EncodeFrame(cmd_list, ctx->encoder, ctx->encoder_heap,
485  &input_args, &output_args);
486 
487  barriers[3] = TRANSITION_BARRIER(pic->encoded_metadata,
488  D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES,
489  D3D12_RESOURCE_STATE_VIDEO_ENCODE_WRITE,
490  D3D12_RESOURCE_STATE_VIDEO_ENCODE_READ);
491 
492  ID3D12VideoEncodeCommandList2_ResourceBarrier(cmd_list, 1, &barriers[3]);
493 
494  ID3D12VideoEncodeCommandList2_ResolveEncoderOutputMetadata(cmd_list, &input_metadata, &output_metadata);
495 
496  if (barriers_ref_index > 0) {
497  for (i = 0; i < barriers_ref_index; i++)
498  FFSWAP(D3D12_RESOURCE_STATES, barriers_ref[i].Transition.StateBefore, barriers_ref[i].Transition.StateAfter);
499 
500  ID3D12VideoEncodeCommandList2_ResourceBarrier(cmd_list, barriers_ref_index,
501  barriers_ref);
502  }
503 
504  barriers[0] = TRANSITION_BARRIER(pic->input_surface->texture,
505  D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES,
506  D3D12_RESOURCE_STATE_VIDEO_ENCODE_READ,
507  D3D12_RESOURCE_STATE_COMMON);
508  barriers[1] = TRANSITION_BARRIER(pic->output_buffer,
509  D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES,
510  D3D12_RESOURCE_STATE_VIDEO_ENCODE_WRITE,
511  D3D12_RESOURCE_STATE_COMMON);
512  barriers[2] = TRANSITION_BARRIER(pic->encoded_metadata,
513  D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES,
514  D3D12_RESOURCE_STATE_VIDEO_ENCODE_READ,
515  D3D12_RESOURCE_STATE_COMMON);
516  barriers[3] = TRANSITION_BARRIER(pic->resolved_metadata,
517  D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES,
518  D3D12_RESOURCE_STATE_VIDEO_ENCODE_WRITE,
519  D3D12_RESOURCE_STATE_COMMON);
520 
521  ID3D12VideoEncodeCommandList2_ResourceBarrier(cmd_list, 4, barriers);
522 
523  hr = ID3D12VideoEncodeCommandList2_Close(cmd_list);
524  if (FAILED(hr)) {
525  err = AVERROR_UNKNOWN;
526  goto fail;
527  }
528 
529  hr = ID3D12CommandQueue_Wait(ctx->command_queue, pic->input_surface->sync_ctx.fence,
531  if (FAILED(hr)) {
532  err = AVERROR_UNKNOWN;
533  goto fail;
534  }
535 
536  ID3D12CommandQueue_ExecuteCommandLists(ctx->command_queue, 1, (ID3D12CommandList **)&ctx->command_list);
537 
538  hr = ID3D12CommandQueue_Signal(ctx->command_queue, pic->input_surface->sync_ctx.fence,
540  if (FAILED(hr)) {
541  err = AVERROR_UNKNOWN;
542  goto fail;
543  }
544 
545  hr = ID3D12CommandQueue_Signal(ctx->command_queue, ctx->sync_ctx.fence, ++ctx->sync_ctx.fence_value);
546  if (FAILED(hr)) {
547  err = AVERROR_UNKNOWN;
548  goto fail;
549  }
550 
551  err = d3d12va_discard_command_allocator(avctx, command_allocator, ctx->sync_ctx.fence_value);
552  if (err < 0)
553  goto fail;
554 
555  pic->fence_value = ctx->sync_ctx.fence_value;
556 
557  // Update intra refresh frame index for next frame
558  if (ctx->intra_refresh.Mode != D3D12_VIDEO_ENCODER_INTRA_REFRESH_MODE_NONE) {
559  ctx->intra_refresh_frame_index =
560  (ctx->intra_refresh_frame_index + 1) % ctx->intra_refresh.IntraRefreshDuration;
561  }
562 
563  if (d3d12_refs.ppTexture2Ds)
564  av_freep(&d3d12_refs.ppTexture2Ds);
565 
566  if (ctx->is_texture_array && d3d12_refs.pSubresources)
567  av_freep(&d3d12_refs.pSubresources);
568 
569  if (barriers_ref)
570  av_freep(&barriers_ref);
571 
572  return 0;
573 
574 fail:
575  if (command_allocator)
576  d3d12va_discard_command_allocator(avctx, command_allocator, ctx->sync_ctx.fence_value);
577 
578  if (d3d12_refs.ppTexture2Ds)
579  av_freep(&d3d12_refs.ppTexture2Ds);
580 
581  if (ctx->is_texture_array && d3d12_refs.pSubresources)
582  av_freep(&d3d12_refs.pSubresources);
583 
584  if (barriers_ref)
585  av_freep(&barriers_ref);
586 
587  if (ctx->codec->free_picture_params)
588  ctx->codec->free_picture_params(pic);
589 
591  pic->output_buffer = NULL;
594  return err;
595 }
596 
598  FFHWBaseEncodePicture *base_pic)
599 {
600  D3D12VAEncodePicture *pic = base_pic->priv;
601 
602  d3d12va_encode_wait(avctx, base_pic);
603 
604  if (pic->output_buffer_ref) {
605  av_log(avctx, AV_LOG_DEBUG, "Discard output for pic "
606  "%"PRId64"/%"PRId64".\n",
607  base_pic->display_order, base_pic->encode_order);
608 
610  pic->output_buffer = NULL;
611  }
612 
615 
616  return 0;
617 }
618 
620 {
622 
623  switch (ctx->rc.Mode)
624  {
625  case D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE_CQP:
626  av_freep(&ctx->rc.ConfigParams.pConfiguration_CQP);
627  break;
628  case D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE_CBR:
629  av_freep(&ctx->rc.ConfigParams.pConfiguration_CBR);
630  break;
631  case D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE_VBR:
632  av_freep(&ctx->rc.ConfigParams.pConfiguration_VBR);
633  break;
634  case D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE_QVBR:
635  av_freep(&ctx->rc.ConfigParams.pConfiguration_QVBR);
636  break;
637  default:
638  break;
639  }
640 
641  return 0;
642 }
643 
645 {
647  D3D12VAEncodePicture *priv = pic->priv;
648  AVFrame *frame = pic->input_image;
649 
650  if (ctx->codec->picture_priv_data_size > 0) {
651  pic->codec_priv = av_mallocz(ctx->codec->picture_priv_data_size);
652  if (!pic->codec_priv)
653  return AVERROR(ENOMEM);
654  }
655 
656  priv->input_surface = (AVD3D12VAFrame *)frame->data[0];
657 
658  return 0;
659 }
660 
662 {
664  D3D12VAEncodePicture *priv = pic->priv;
665 
666  if (pic->encode_issued)
667  d3d12va_encode_discard(avctx, pic);
668 
669  if (ctx->codec->free_picture_params)
670  ctx->codec->free_picture_params(priv);
671 
672  return 0;
673 }
674 
676  D3D12VAEncodePicture *pic, size_t *size)
677 {
678  D3D12_VIDEO_ENCODER_OUTPUT_METADATA *meta = NULL;
679  uint8_t *data;
680  HRESULT hr;
681  int err;
682 
683  hr = ID3D12Resource_Map(pic->resolved_metadata, 0, NULL, (void **)&data);
684  if (FAILED(hr)) {
685  err = AVERROR_UNKNOWN;
686  return err;
687  }
688 
689  meta = (D3D12_VIDEO_ENCODER_OUTPUT_METADATA *)data;
690 
691  if (meta->EncodeErrorFlags != D3D12_VIDEO_ENCODER_ENCODE_ERROR_FLAG_NO_ERROR) {
692  av_log(avctx, AV_LOG_ERROR, "Encode failed %"PRIu64"\n", meta->EncodeErrorFlags);
693  err = AVERROR(EINVAL);
694  return err;
695  }
696 
697  if (meta->EncodedBitstreamWrittenBytesCount == 0) {
698  av_log(avctx, AV_LOG_ERROR, "No bytes were written to encoded bitstream\n");
699  err = AVERROR(EINVAL);
700  return err;
701  }
702 
703  *size = meta->EncodedBitstreamWrittenBytesCount;
704 
705  ID3D12Resource_Unmap(pic->resolved_metadata, 0, NULL);
706 
707  return 0;
708 }
709 
712 {
713  int err;
714  uint8_t *ptr, *mapped_data;
715  size_t total_size = 0;
716  HRESULT hr;
717 
718  err = d3d12va_encode_get_buffer_size(avctx, pic, &total_size);
719  if (err < 0)
720  goto end;
721 
722  total_size += pic->header_size;
723  av_log(avctx, AV_LOG_DEBUG, "Output buffer size %zu\n", total_size);
724 
725  hr = ID3D12Resource_Map(pic->output_buffer, 0, NULL, (void **)&mapped_data);
726  if (FAILED(hr)) {
727  err = AVERROR_UNKNOWN;
728  goto end;
729  }
730 
731  err = ff_get_encode_buffer(avctx, pkt, total_size, 0);
732  if (err < 0)
733  goto end;
734  ptr = pkt->data;
735 
736  memcpy(ptr, mapped_data, pic->header_size);
737 
738  ptr += pic->header_size;
739  mapped_data += pic->aligned_header_size;
740  total_size -= pic->header_size;
741 
742  memcpy(ptr, mapped_data, total_size);
743 
744  ID3D12Resource_Unmap(pic->output_buffer, 0, NULL);
745 
746 end:
748  pic->output_buffer = NULL;
749  return err;
750 }
751 
753  FFHWBaseEncodePicture *base_pic, AVPacket *pkt)
754 {
756  FFHWBaseEncodeContext *base_ctx = avctx->priv_data;
757  D3D12VAEncodePicture *pic = base_pic->priv;
758  AVPacket *pkt_ptr = pkt;
759  int err = 0;
760 
761  err = d3d12va_encode_wait(avctx, base_pic);
762  if (err < 0)
763  return err;
764 
765  if (ctx->codec->get_coded_data)
766  err = ctx->codec->get_coded_data(avctx, pic, pkt);
767  else
768  err = d3d12va_encode_get_coded_data(avctx, pic, pkt);
769 
770  if (err < 0)
771  return err;
772 
773  av_log(avctx, AV_LOG_DEBUG, "Output read for pic %"PRId64"/%"PRId64".\n",
774  base_pic->display_order, base_pic->encode_order);
775 
777  pkt_ptr, 0);
778 
779  return 0;
780 }
781 
783 {
784  FFHWBaseEncodeContext *base_ctx = avctx->priv_data;
787  const AVPixFmtDescriptor *desc;
788  int i, depth;
789 
791  if (!desc) {
792  av_log(avctx, AV_LOG_ERROR, "Invalid input pixfmt (%d).\n",
793  base_ctx->input_frames->sw_format);
794  return AVERROR(EINVAL);
795  }
796 
797  depth = desc->comp[0].depth;
798  for (i = 1; i < desc->nb_components; i++) {
799  if (desc->comp[i].depth != depth) {
800  av_log(avctx, AV_LOG_ERROR, "Invalid input pixfmt (%s).\n",
801  desc->name);
802  return AVERROR(EINVAL);
803  }
804  }
805  av_log(avctx, AV_LOG_VERBOSE, "Input surface format is %s.\n",
806  desc->name);
807 
808  av_assert0(ctx->codec->profiles);
809  for (i = 0; (ctx->codec->profiles[i].av_profile !=
810  AV_PROFILE_UNKNOWN); i++) {
811  profile = &ctx->codec->profiles[i];
812  if (depth != profile->depth ||
813  desc->nb_components != profile->nb_components)
814  continue;
815  if (desc->nb_components > 1 &&
816  (desc->log2_chroma_w != profile->log2_chroma_w ||
817  desc->log2_chroma_h != profile->log2_chroma_h))
818  continue;
819  if (avctx->profile != profile->av_profile &&
820  avctx->profile != AV_PROFILE_UNKNOWN)
821  continue;
822 
823  ctx->profile = profile;
824  break;
825  }
826  if (!ctx->profile) {
827  av_log(avctx, AV_LOG_ERROR, "No usable encoding profile found.\n");
828  return AVERROR(ENOSYS);
829  }
830 
831  avctx->profile = profile->av_profile;
832  return 0;
833 }
834 
836  // Bitrate Quality
837  // | Maxrate | HRD/VBV
838  { 0 }, // | | | |
839  { RC_MODE_CQP, "CQP", 0, 0, 1, 0, D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE_CQP },
840  { RC_MODE_CBR, "CBR", 1, 0, 0, 1, D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE_CBR },
841  { RC_MODE_VBR, "VBR", 1, 1, 0, 1, D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE_VBR },
842  { RC_MODE_QVBR, "QVBR", 1, 1, 1, 1, D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE_QVBR },
843 };
844 
846 {
847  HRESULT hr;
849  D3D12_FEATURE_DATA_VIDEO_ENCODER_RATE_CONTROL_MODE d3d12_rc_mode = {
850  .Codec = ctx->codec->d3d12_codec,
851  };
852 
853  if (!rc_mode->d3d12_mode)
854  return 0;
855 
856  d3d12_rc_mode.IsSupported = 0;
857  d3d12_rc_mode.RateControlMode = rc_mode->d3d12_mode;
858 
859  hr = ID3D12VideoDevice3_CheckFeatureSupport(ctx->video_device3,
860  D3D12_FEATURE_VIDEO_ENCODER_RATE_CONTROL_MODE,
861  &d3d12_rc_mode, sizeof(d3d12_rc_mode));
862  if (FAILED(hr)) {
863  av_log(avctx, AV_LOG_ERROR, "Failed to check rate control support.\n");
864  return 0;
865  }
866 
867  return d3d12_rc_mode.IsSupported;
868 }
869 
871 {
873  int64_t rc_target_bitrate;
874  int64_t rc_peak_bitrate;
875  int rc_quality;
876  int64_t hrd_buffer_size;
877  int64_t hrd_initial_buffer_fullness;
878  int fr_num, fr_den;
880 
881 #define SET_QP_RANGE(ctl) do { \
882  if (avctx->qmin > 0 || avctx->qmax > 0) { \
883  ctl->MinQP = avctx->qmin; \
884  ctl->MaxQP = avctx->qmax; \
885  ctx->rc.Flags |= D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_QP_RANGE; \
886  } \
887  } while(0)
888 
889 #define SET_MAX_FRAME_SIZE(ctl) do { \
890  if (ctx->max_frame_size > 0) { \
891  ctl->MaxFrameBitSize = ctx->max_frame_size * 8; \
892  ctx->rc.Flags |= D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_MAX_FRAME_SIZE; \
893  } \
894  } while(0)
895 
896  // Rate control mode selection:
897  // * If the user has set a mode explicitly with the rc_mode option,
898  // use it and fail if it is not available.
899  // * If an explicit QP option has been set, use CQP.
900  // * If the codec is CQ-only, use CQP.
901  // * If the QSCALE avcodec option is set, use CQP.
902  // * If bitrate and quality are both set, try QVBR.
903  // * If quality is set, try CQP.
904  // * If bitrate and maxrate are set and have the same value, try CBR.
905  // * If a bitrate is set, try VBR, then CBR.
906  // * If no bitrate is set, try CQP.
907 
908 #define TRY_RC_MODE(mode, fail) do { \
909  rc_mode = &d3d12va_encode_rc_modes[mode]; \
910  if (!(rc_mode->d3d12_mode && check_rate_control_support(avctx, rc_mode))) { \
911  if (fail) { \
912  av_log(avctx, AV_LOG_ERROR, "Driver does not support %s " \
913  "RC mode.\n", rc_mode->name); \
914  return AVERROR(EINVAL); \
915  } \
916  av_log(avctx, AV_LOG_DEBUG, "Driver does not support %s " \
917  "RC mode.\n", rc_mode->name); \
918  rc_mode = NULL; \
919  } else { \
920  goto rc_mode_found; \
921  } \
922  } while (0)
923 
924  if (ctx->explicit_rc_mode)
925  TRY_RC_MODE(ctx->explicit_rc_mode, 1);
926 
927  if (ctx->explicit_qp)
929 
932 
933  if (avctx->flags & AV_CODEC_FLAG_QSCALE)
935 
936  if (avctx->bit_rate > 0 && avctx->global_quality > 0)
938 
939  if (avctx->global_quality > 0) {
941  }
942 
943  if (avctx->bit_rate > 0 && avctx->rc_max_rate == avctx->bit_rate)
945 
946  if (avctx->bit_rate > 0) {
949  } else {
951  }
952 
953  av_log(avctx, AV_LOG_ERROR, "Driver does not support any "
954  "RC mode compatible with selected options.\n");
955  return AVERROR(EINVAL);
956 
957 rc_mode_found:
958  if (rc_mode->bitrate) {
959  if (avctx->bit_rate <= 0) {
960  av_log(avctx, AV_LOG_ERROR, "Bitrate must be set for %s "
961  "RC mode.\n", rc_mode->name);
962  return AVERROR(EINVAL);
963  }
964 
965  if (rc_mode->maxrate) {
966  if (avctx->rc_max_rate > 0) {
967  if (avctx->rc_max_rate < avctx->bit_rate) {
968  av_log(avctx, AV_LOG_ERROR, "Invalid bitrate settings: "
969  "bitrate (%"PRId64") must not be greater than "
970  "maxrate (%"PRId64").\n", avctx->bit_rate,
971  avctx->rc_max_rate);
972  return AVERROR(EINVAL);
973  }
974  rc_target_bitrate = avctx->bit_rate;
975  rc_peak_bitrate = avctx->rc_max_rate;
976  } else {
977  // We only have a target bitrate, but this mode requires
978  // that a maximum rate be supplied as well. Since the
979  // user does not want this to be a constraint, arbitrarily
980  // pick a maximum rate of double the target rate.
981  rc_target_bitrate = avctx->bit_rate;
982  rc_peak_bitrate = 2 * avctx->bit_rate;
983  }
984  } else {
985  if (avctx->rc_max_rate > avctx->bit_rate) {
986  av_log(avctx, AV_LOG_WARNING, "Max bitrate is ignored "
987  "in %s RC mode.\n", rc_mode->name);
988  }
989  rc_target_bitrate = avctx->bit_rate;
990  rc_peak_bitrate = 0;
991  }
992  } else {
993  rc_target_bitrate = 0;
994  rc_peak_bitrate = 0;
995  }
996 
997  if (rc_mode->quality) {
998  if (ctx->explicit_qp) {
999  rc_quality = ctx->explicit_qp;
1000  } else if (avctx->global_quality > 0) {
1001  if (avctx->flags & AV_CODEC_FLAG_QSCALE)
1002  rc_quality = avctx->global_quality / FF_QP2LAMBDA;
1003  else
1004  rc_quality = avctx->global_quality;
1005  } else {
1006  rc_quality = ctx->codec->default_quality;
1007  av_log(avctx, AV_LOG_WARNING, "No quality level set; "
1008  "using default (%d).\n", rc_quality);
1009  }
1010  } else {
1011  rc_quality = 0;
1012  }
1013 
1014  if (rc_mode->hrd) {
1015  if (avctx->rc_buffer_size)
1016  hrd_buffer_size = avctx->rc_buffer_size;
1017  else if (avctx->rc_max_rate > 0)
1018  hrd_buffer_size = avctx->rc_max_rate;
1019  else
1020  hrd_buffer_size = avctx->bit_rate;
1021  if (avctx->rc_initial_buffer_occupancy) {
1022  if (avctx->rc_initial_buffer_occupancy > hrd_buffer_size) {
1023  av_log(avctx, AV_LOG_ERROR, "Invalid RC buffer settings: "
1024  "must have initial buffer size (%d) <= "
1025  "buffer size (%"PRId64").\n",
1026  avctx->rc_initial_buffer_occupancy, hrd_buffer_size);
1027  return AVERROR(EINVAL);
1028  }
1029  hrd_initial_buffer_fullness = avctx->rc_initial_buffer_occupancy;
1030  } else {
1031  hrd_initial_buffer_fullness = hrd_buffer_size * 3 / 4;
1032  }
1033  } else {
1034  if (avctx->rc_buffer_size || avctx->rc_initial_buffer_occupancy) {
1035  av_log(avctx, AV_LOG_WARNING, "Buffering settings are ignored "
1036  "in %s RC mode.\n", rc_mode->name);
1037  }
1038 
1039  hrd_buffer_size = 0;
1040  hrd_initial_buffer_fullness = 0;
1041  }
1042 
1043  if (rc_target_bitrate > UINT32_MAX ||
1044  hrd_buffer_size > UINT32_MAX ||
1045  hrd_initial_buffer_fullness > UINT32_MAX) {
1046  av_log(avctx, AV_LOG_ERROR, "RC parameters of 2^32 or "
1047  "greater are not supported by D3D12.\n");
1048  return AVERROR(EINVAL);
1049  }
1050 
1051  ctx->rc_quality = rc_quality;
1052 
1053  av_log(avctx, AV_LOG_VERBOSE, "RC mode: %s.\n", rc_mode->name);
1054 
1055  if (rc_mode->quality)
1056  av_log(avctx, AV_LOG_VERBOSE, "RC quality: %d.\n", rc_quality);
1057 
1058  if (rc_mode->hrd) {
1059  av_log(avctx, AV_LOG_VERBOSE, "RC buffer: %"PRId64" bits, "
1060  "initial fullness %"PRId64" bits.\n",
1061  hrd_buffer_size, hrd_initial_buffer_fullness);
1062  }
1063 
1064  if (avctx->framerate.num > 0 && avctx->framerate.den > 0)
1065  av_reduce(&fr_num, &fr_den,
1066  avctx->framerate.num, avctx->framerate.den, 65535);
1067  else
1068  av_reduce(&fr_num, &fr_den,
1069  avctx->time_base.den, avctx->time_base.num, 65535);
1070 
1071  av_log(avctx, AV_LOG_VERBOSE, "RC framerate: %d/%d (%.2f fps).\n",
1072  fr_num, fr_den, (double)fr_num / fr_den);
1073 
1074  ctx->rc.Flags = D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_NONE;
1075  ctx->rc.TargetFrameRate.Numerator = fr_num;
1076  ctx->rc.TargetFrameRate.Denominator = fr_den;
1077  ctx->rc.Mode = rc_mode->d3d12_mode;
1078 
1079  switch (rc_mode->mode) {
1080  case RC_MODE_CQP:
1081  // cqp ConfigParams will be updated in ctx->codec->configure.
1082  break;
1083  case RC_MODE_CBR: {
1084  D3D12_VIDEO_ENCODER_RATE_CONTROL_CBR *cbr_ctl;
1085 
1086  ctx->rc.ConfigParams.DataSize = sizeof(D3D12_VIDEO_ENCODER_RATE_CONTROL_CBR);
1087  cbr_ctl = av_mallocz(ctx->rc.ConfigParams.DataSize);
1088  if (!cbr_ctl)
1089  return AVERROR(ENOMEM);
1090 
1091  cbr_ctl->TargetBitRate = rc_target_bitrate;
1092  cbr_ctl->VBVCapacity = hrd_buffer_size;
1093  cbr_ctl->InitialVBVFullness = hrd_initial_buffer_fullness;
1094  ctx->rc.Flags |= D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_VBV_SIZES;
1095 
1096  SET_QP_RANGE(cbr_ctl);
1097  SET_MAX_FRAME_SIZE(cbr_ctl);
1098 
1099  ctx->rc.ConfigParams.pConfiguration_CBR = cbr_ctl;
1100  break;
1101  }
1102  case RC_MODE_VBR: {
1103  D3D12_VIDEO_ENCODER_RATE_CONTROL_VBR *vbr_ctl;
1104 
1105  ctx->rc.ConfigParams.DataSize = sizeof(D3D12_VIDEO_ENCODER_RATE_CONTROL_VBR);
1106  vbr_ctl = av_mallocz(ctx->rc.ConfigParams.DataSize);
1107  if (!vbr_ctl)
1108  return AVERROR(ENOMEM);
1109 
1110  vbr_ctl->TargetAvgBitRate = rc_target_bitrate;
1111  vbr_ctl->PeakBitRate = rc_peak_bitrate;
1112  vbr_ctl->VBVCapacity = hrd_buffer_size;
1113  vbr_ctl->InitialVBVFullness = hrd_initial_buffer_fullness;
1114  ctx->rc.Flags |= D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_VBV_SIZES;
1115 
1116  SET_QP_RANGE(vbr_ctl);
1117  SET_MAX_FRAME_SIZE(vbr_ctl);
1118 
1119  ctx->rc.ConfigParams.pConfiguration_VBR = vbr_ctl;
1120  break;
1121  }
1122  case RC_MODE_QVBR: {
1123  D3D12_VIDEO_ENCODER_RATE_CONTROL_QVBR *qvbr_ctl;
1124 
1125  ctx->rc.ConfigParams.DataSize = sizeof(D3D12_VIDEO_ENCODER_RATE_CONTROL_QVBR);
1126  qvbr_ctl = av_mallocz(ctx->rc.ConfigParams.DataSize);
1127  if (!qvbr_ctl)
1128  return AVERROR(ENOMEM);
1129 
1130  qvbr_ctl->TargetAvgBitRate = rc_target_bitrate;
1131  qvbr_ctl->PeakBitRate = rc_peak_bitrate;
1132  qvbr_ctl->ConstantQualityTarget = rc_quality;
1133 
1134  SET_QP_RANGE(qvbr_ctl);
1135  SET_MAX_FRAME_SIZE(qvbr_ctl);
1136 
1137  ctx->rc.ConfigParams.pConfiguration_QVBR = qvbr_ctl;
1138  break;
1139  }
1140  default:
1141  break;
1142  }
1143  return 0;
1144 }
1145 
1147 {
1148  FFHWBaseEncodeContext *base_ctx = avctx->priv_data;
1150  AVD3D12VAFramesContext *hwctx = base_ctx->input_frames->hwctx;
1151  HRESULT hr;
1152 
1153  if (ctx->me_precision == D3D12_VIDEO_ENCODER_MOTION_ESTIMATION_PRECISION_MODE_MAXIMUM)
1154  return 0;
1155 
1156  D3D12_VIDEO_ENCODER_PROFILE_DESC profile = { 0 };
1157  D3D12_VIDEO_ENCODER_PROFILE_H264 h264_profile = D3D12_VIDEO_ENCODER_PROFILE_H264_MAIN;
1158  D3D12_VIDEO_ENCODER_PROFILE_HEVC hevc_profile = D3D12_VIDEO_ENCODER_PROFILE_HEVC_MAIN;
1159 #if CONFIG_AV1_D3D12VA_ENCODER
1160  D3D12_VIDEO_ENCODER_AV1_PROFILE av1_profile = D3D12_VIDEO_ENCODER_AV1_PROFILE_MAIN;
1161 #endif
1162 
1163  D3D12_VIDEO_ENCODER_LEVEL_SETTING level = { 0 };
1164  D3D12_VIDEO_ENCODER_LEVELS_H264 h264_level = { 0 };
1165  D3D12_VIDEO_ENCODER_LEVEL_TIER_CONSTRAINTS_HEVC hevc_level = { 0 };
1166 #if CONFIG_AV1_D3D12VA_ENCODER
1167  D3D12_VIDEO_ENCODER_AV1_LEVEL_TIER_CONSTRAINTS av1_level = { 0 };
1168 #endif
1169 
1170  switch (ctx->codec->d3d12_codec) {
1171  case D3D12_VIDEO_ENCODER_CODEC_H264:
1172  profile.DataSize = sizeof(D3D12_VIDEO_ENCODER_PROFILE_H264);
1173  profile.pH264Profile = &h264_profile;
1174  level.DataSize = sizeof(D3D12_VIDEO_ENCODER_LEVELS_H264);
1175  level.pH264LevelSetting = &h264_level;
1176  break;
1177  case D3D12_VIDEO_ENCODER_CODEC_HEVC:
1178  profile.DataSize = sizeof(D3D12_VIDEO_ENCODER_PROFILE_HEVC);
1179  profile.pHEVCProfile = &hevc_profile;
1180  level.DataSize = sizeof(D3D12_VIDEO_ENCODER_LEVEL_TIER_CONSTRAINTS_HEVC);
1181  level.pHEVCLevelSetting = &hevc_level;
1182  break;
1183 #if CONFIG_AV1_D3D12VA_ENCODER
1184  case D3D12_VIDEO_ENCODER_CODEC_AV1:
1185  profile.DataSize = sizeof(D3D12_VIDEO_ENCODER_AV1_PROFILE);
1186  profile.pAV1Profile = &av1_profile;
1187  level.DataSize = sizeof(D3D12_VIDEO_ENCODER_AV1_LEVEL_TIER_CONSTRAINTS);
1188  level.pAV1LevelSetting = &av1_level;
1189  break;
1190 #endif
1191  default:
1192  av_assert0(0);
1193  }
1194 
1195  D3D12_FEATURE_DATA_VIDEO_ENCODER_SUPPORT support = {
1196  .NodeIndex = 0,
1197  .Codec = ctx->codec->d3d12_codec,
1198  .InputFormat = hwctx->format,
1199  .RateControl = ctx->rc,
1200  .IntraRefresh = D3D12_VIDEO_ENCODER_INTRA_REFRESH_MODE_NONE,
1201  .SubregionFrameEncoding = D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_FULL_FRAME,
1202  .ResolutionsListCount = 1,
1203  .pResolutionList = &ctx->resolution,
1204  .CodecGopSequence = ctx->gop,
1205  .MaxReferenceFramesInDPB = MAX_DPB_SIZE - 1,
1206  .CodecConfiguration = ctx->codec_conf,
1207  .SuggestedProfile = profile,
1208  .SuggestedLevel = level,
1209  .pResolutionDependentSupport = &ctx->res_limits,
1210  };
1211 
1212  hr = ID3D12VideoDevice3_CheckFeatureSupport(ctx->video_device3, D3D12_FEATURE_VIDEO_ENCODER_SUPPORT,
1213  &support, sizeof(support));
1214  if (FAILED(hr)) {
1215  av_log(avctx, AV_LOG_ERROR, "Failed to check encoder support for motion estimation.\n");
1216  return AVERROR(EINVAL);
1217  }
1218 
1219  if (!(support.SupportFlags & D3D12_VIDEO_ENCODER_SUPPORT_FLAG_MOTION_ESTIMATION_PRECISION_MODE_LIMIT_AVAILABLE)) {
1220  av_log(avctx, AV_LOG_ERROR, "Hardware does not support motion estimation "
1221  "precision mode limits.\n");
1222  return AVERROR(ENOTSUP);
1223  }
1224 
1225  av_log(avctx, AV_LOG_VERBOSE, "Hardware supports motion estimation "
1226  "precision mode limits.\n");
1227 
1228  return 0;
1229 }
1230 
1232 {
1233  FFHWBaseEncodeContext *base_ctx = avctx->priv_data;
1235  uint32_t ref_l0, ref_l1;
1236  int err;
1237  HRESULT hr;
1238  D3D12_FEATURE_DATA_VIDEO_ENCODER_CODEC_PICTURE_CONTROL_SUPPORT support;
1239  union {
1240  D3D12_VIDEO_ENCODER_CODEC_PICTURE_CONTROL_SUPPORT_H264 h264;
1241  D3D12_VIDEO_ENCODER_CODEC_PICTURE_CONTROL_SUPPORT_HEVC hevc;
1242 #if CONFIG_AV1_D3D12VA_ENCODER
1243  D3D12_VIDEO_ENCODER_CODEC_AV1_PICTURE_CONTROL_SUPPORT av1;
1244 #endif
1245  } codec_support;
1246 
1247  support.NodeIndex = 0;
1248  support.Codec = ctx->codec->d3d12_codec;
1249  support.Profile = ctx->profile->d3d12_profile;
1250 
1251  switch (ctx->codec->d3d12_codec) {
1252  case D3D12_VIDEO_ENCODER_CODEC_H264:
1253  support.PictureSupport.DataSize = sizeof(codec_support.h264);
1254  support.PictureSupport.pH264Support = &codec_support.h264;
1255  break;
1256 
1257  case D3D12_VIDEO_ENCODER_CODEC_HEVC:
1258  support.PictureSupport.DataSize = sizeof(codec_support.hevc);
1259  support.PictureSupport.pHEVCSupport = &codec_support.hevc;
1260  break;
1261 
1262 #if CONFIG_AV1_D3D12VA_ENCODER
1263  case D3D12_VIDEO_ENCODER_CODEC_AV1:
1264  memset(&codec_support.av1, 0, sizeof(codec_support.av1));
1265  support.PictureSupport.DataSize = sizeof(codec_support.av1);
1266  support.PictureSupport.pAV1Support = &codec_support.av1;
1267  break;
1268 #endif
1269  default:
1270  av_assert0(0);
1271  }
1272 
1273  hr = ID3D12VideoDevice3_CheckFeatureSupport(ctx->video_device3, D3D12_FEATURE_VIDEO_ENCODER_CODEC_PICTURE_CONTROL_SUPPORT,
1274  &support, sizeof(support));
1275  if (FAILED(hr))
1276  return AVERROR(EINVAL);
1277 
1278  if (support.IsSupported) {
1279  switch (ctx->codec->d3d12_codec) {
1280  case D3D12_VIDEO_ENCODER_CODEC_H264:
1281  ref_l0 = FFMIN(support.PictureSupport.pH264Support->MaxL0ReferencesForP,
1282  support.PictureSupport.pH264Support->MaxL1ReferencesForB ?
1283  support.PictureSupport.pH264Support->MaxL1ReferencesForB : UINT_MAX);
1284  ref_l1 = support.PictureSupport.pH264Support->MaxL1ReferencesForB;
1285  break;
1286 
1287  case D3D12_VIDEO_ENCODER_CODEC_HEVC:
1288  ref_l0 = FFMIN(support.PictureSupport.pHEVCSupport->MaxL0ReferencesForP,
1289  support.PictureSupport.pHEVCSupport->MaxL1ReferencesForB ?
1290  support.PictureSupport.pHEVCSupport->MaxL1ReferencesForB : UINT_MAX);
1291  ref_l1 = support.PictureSupport.pHEVCSupport->MaxL1ReferencesForB;
1292  break;
1293 
1294 #if CONFIG_AV1_D3D12VA_ENCODER
1295  case D3D12_VIDEO_ENCODER_CODEC_AV1:
1296  ref_l0 = support.PictureSupport.pAV1Support->MaxUniqueReferencesPerFrame;
1297  // AV1 doesn't use traditional L1 references like H.264/HEVC
1298  ref_l1 = 0;
1299  break;
1300 #endif
1301  default:
1302  av_assert0(0);
1303  }
1304  } else {
1305  ref_l0 = ref_l1 = 0;
1306  }
1307 
1308  if (ref_l0 > 0 && ref_l1 > 0 && ctx->bi_not_empty) {
1309  base_ctx->p_to_gpb = 1;
1310  av_log(avctx, AV_LOG_VERBOSE, "Driver does not support P-frames, "
1311  "replacing them with B-frames.\n");
1312  }
1313 
1314  err = ff_hw_base_init_gop_structure(base_ctx, avctx, ref_l0, ref_l1, ctx->codec->flags, 0);
1315  if (err < 0)
1316  return err;
1317 
1318  return 0;
1319 }
1320 
1322 {
1323  FFHWBaseEncodeContext *base_ctx = avctx->priv_data;
1325 
1326  if (ctx->intra_refresh.Mode == D3D12_VIDEO_ENCODER_INTRA_REFRESH_MODE_NONE)
1327  return 0;
1328 
1329  // Check for SDK API availability
1330 #if CONFIG_D3D12_INTRA_REFRESH
1331  HRESULT hr;
1332  D3D12_VIDEO_ENCODER_LEVEL_SETTING level = { 0 };
1333  D3D12_VIDEO_ENCODER_LEVELS_H264 h264_level = { 0 };
1334  D3D12_VIDEO_ENCODER_LEVEL_TIER_CONSTRAINTS_HEVC hevc_level = { 0 };
1335 #if CONFIG_AV1_D3D12VA_ENCODER
1336  D3D12_VIDEO_ENCODER_AV1_LEVEL_TIER_CONSTRAINTS av1_level = { 0 };
1337 #endif
1338 
1339  switch (ctx->codec->d3d12_codec) {
1340  case D3D12_VIDEO_ENCODER_CODEC_H264:
1341  level.DataSize = sizeof(D3D12_VIDEO_ENCODER_LEVELS_H264);
1342  level.pH264LevelSetting = &h264_level;
1343  break;
1344  case D3D12_VIDEO_ENCODER_CODEC_HEVC:
1345  level.DataSize = sizeof(D3D12_VIDEO_ENCODER_LEVEL_TIER_CONSTRAINTS_HEVC);
1346  level.pHEVCLevelSetting = &hevc_level;
1347  break;
1348 #if CONFIG_AV1_D3D12VA_ENCODER
1349  case D3D12_VIDEO_ENCODER_CODEC_AV1:
1350  level.DataSize = sizeof(D3D12_VIDEO_ENCODER_AV1_LEVEL_TIER_CONSTRAINTS);
1351  level.pAV1LevelSetting = &av1_level;
1352  break;
1353 #endif
1354  default:
1355  av_assert0(0);
1356  }
1357 
1358  D3D12_FEATURE_DATA_VIDEO_ENCODER_INTRA_REFRESH_MODE intra_refresh_support = {
1359  .NodeIndex = 0,
1360  .Codec = ctx->codec->d3d12_codec,
1361  .Profile = ctx->profile->d3d12_profile,
1362  .Level = level,
1363  .IntraRefreshMode = ctx->intra_refresh.Mode,
1364  };
1365 
1366  hr = ID3D12VideoDevice3_CheckFeatureSupport(ctx->video_device3,
1367  D3D12_FEATURE_VIDEO_ENCODER_INTRA_REFRESH_MODE,
1368  &intra_refresh_support, sizeof(intra_refresh_support));
1369 
1370  if (FAILED(hr) || !intra_refresh_support.IsSupported) {
1371  av_log(avctx, AV_LOG_ERROR, "Requested intra refresh mode not supported by driver.\n");
1372  return AVERROR(ENOTSUP);
1373  }
1374 #else
1375  // Older SDK - validation will occur in init_sequence_params via D3D12_FEATURE_VIDEO_ENCODER_SUPPORT
1376  av_log(avctx, AV_LOG_VERBOSE, "Intra refresh explicit check not available in this SDK.\n"
1377  "Support will be validated during encoder initialization.\n");
1378 #endif
1379 
1380  // Set duration: use GOP size if not specified
1381  if (ctx->intra_refresh.IntraRefreshDuration == 0) {
1382  ctx->intra_refresh.IntraRefreshDuration = base_ctx->gop_size;
1383  av_log(avctx, AV_LOG_VERBOSE, "Intra refresh duration set to GOP size: %d\n",
1384  ctx->intra_refresh.IntraRefreshDuration);
1385  }
1386 
1387  // Initialize frame index
1388  ctx->intra_refresh_frame_index = 0;
1389 
1390  av_log(avctx, AV_LOG_VERBOSE, "Intra refresh: mode=%d, duration=%d frames\n",
1391  ctx->intra_refresh.Mode, ctx->intra_refresh.IntraRefreshDuration);
1392 
1393  return 0;
1394 }
1395 
1397 {
1398  FFHWBaseEncodeContext *base_ctx = avctx->priv_data;
1400  AVD3D12VAFramesContext *frames_hwctx = base_ctx->input_frames->hwctx;
1401  HRESULT hr;
1402 
1403  D3D12_VIDEO_ENCODER_DESC desc = {
1404  .NodeMask = 0,
1405  .Flags = D3D12_VIDEO_ENCODER_FLAG_NONE,
1406  .EncodeCodec = ctx->codec->d3d12_codec,
1407  .EncodeProfile = ctx->profile->d3d12_profile,
1408  .InputFormat = frames_hwctx->format,
1409  .CodecConfiguration = ctx->codec_conf,
1410  .MaxMotionEstimationPrecision = ctx->me_precision,
1411  };
1412 
1413  hr = ID3D12VideoDevice3_CreateVideoEncoder(ctx->video_device3, &desc, &IID_ID3D12VideoEncoder,
1414  (void **)&ctx->encoder);
1415  if (FAILED(hr)) {
1416  av_log(avctx, AV_LOG_ERROR, "Failed to create encoder.\n");
1417  return AVERROR(EINVAL);
1418  }
1419 
1420  return 0;
1421 }
1422 
1424 {
1426  HRESULT hr;
1427 
1428  D3D12_VIDEO_ENCODER_HEAP_DESC desc = {
1429  .NodeMask = 0,
1430  .Flags = D3D12_VIDEO_ENCODER_HEAP_FLAG_NONE,
1431  .EncodeCodec = ctx->codec->d3d12_codec,
1432  .EncodeProfile = ctx->profile->d3d12_profile,
1433  .EncodeLevel = ctx->level,
1434  .ResolutionsListCount = 1,
1435  .pResolutionList = &ctx->resolution,
1436  };
1437 
1438  hr = ID3D12VideoDevice3_CreateVideoEncoderHeap(ctx->video_device3, &desc,
1439  &IID_ID3D12VideoEncoderHeap, (void **)&ctx->encoder_heap);
1440  if (FAILED(hr)) {
1441  av_log(avctx, AV_LOG_ERROR, "Failed to create encoder heap.\n");
1442  return AVERROR(EINVAL);
1443  }
1444 
1445  return 0;
1446 }
1447 
1448 static void d3d12va_encode_free_buffer(void *opaque, uint8_t *data)
1449 {
1450  ID3D12Resource *pResource;
1451 
1452  pResource = (ID3D12Resource *)data;
1453  D3D12_OBJECT_RELEASE(pResource);
1454 }
1455 
1457 {
1458  AVCodecContext *avctx = opaque;
1459  FFHWBaseEncodeContext *base_ctx = avctx->priv_data;
1461  ID3D12Resource *pResource = NULL;
1462  HRESULT hr;
1463  AVBufferRef *ref;
1464  D3D12_HEAP_PROPERTIES heap_props;
1465  D3D12_HEAP_TYPE heap_type = D3D12_HEAP_TYPE_READBACK;
1466 
1467  D3D12_RESOURCE_DESC desc = {
1468  .Dimension = D3D12_RESOURCE_DIMENSION_BUFFER,
1469  .Alignment = 0,
1470  .Width = FFALIGN(3 * base_ctx->surface_width * base_ctx->surface_height + (1 << 16),
1471  D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT),
1472  .Height = 1,
1473  .DepthOrArraySize = 1,
1474  .MipLevels = 1,
1475  .Format = DXGI_FORMAT_UNKNOWN,
1476  .SampleDesc = { .Count = 1, .Quality = 0 },
1477  .Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR,
1478  .Flags = D3D12_RESOURCE_FLAG_NONE,
1479  };
1480 
1481  ctx->hwctx->device->lpVtbl->GetCustomHeapProperties(ctx->hwctx->device, &heap_props, 0, heap_type);
1482 
1483  hr = ID3D12Device_CreateCommittedResource(ctx->hwctx->device, &heap_props, D3D12_HEAP_FLAG_NONE,
1484  &desc, D3D12_RESOURCE_STATE_COMMON, NULL, &IID_ID3D12Resource,
1485  (void **)&pResource);
1486 
1487  if (FAILED(hr)) {
1488  av_log(avctx, AV_LOG_ERROR, "Failed to create d3d12 buffer.\n");
1489  return NULL;
1490  }
1491 
1492  ref = av_buffer_create((uint8_t *)(uintptr_t)pResource,
1493  sizeof(pResource),
1495  avctx, AV_BUFFER_FLAG_READONLY);
1496  if (!ref) {
1497  D3D12_OBJECT_RELEASE(pResource);
1498  return NULL;
1499  }
1500 
1501  return ref;
1502 }
1503 
1505 {
1506  FFHWBaseEncodeContext *base_ctx = avctx->priv_data;
1508  AVD3D12VAFramesContext *frames_ctx = base_ctx->input_frames->hwctx;
1509  HRESULT hr;
1510 
1511  ctx->req.NodeIndex = 0;
1512  ctx->req.Codec = ctx->codec->d3d12_codec;
1513  ctx->req.Profile = ctx->profile->d3d12_profile;
1514  ctx->req.InputFormat = frames_ctx->format;
1515  ctx->req.PictureTargetResolution = ctx->resolution;
1516 
1517  hr = ID3D12VideoDevice3_CheckFeatureSupport(ctx->video_device3,
1518  D3D12_FEATURE_VIDEO_ENCODER_RESOURCE_REQUIREMENTS,
1519  &ctx->req, sizeof(ctx->req));
1520  if (FAILED(hr)) {
1521  av_log(avctx, AV_LOG_ERROR, "Failed to check encoder resource requirements support.\n");
1522  return AVERROR(EINVAL);
1523  }
1524 
1525  if (!ctx->req.IsSupported) {
1526  av_log(avctx, AV_LOG_ERROR, "Encoder resource requirements unsupported.\n");
1527  return AVERROR(EINVAL);
1528  }
1529 
1530  ctx->output_buffer_pool = av_buffer_pool_init2(sizeof(ID3D12Resource *), avctx,
1532  if (!ctx->output_buffer_pool)
1533  return AVERROR(ENOMEM);
1534 
1535  return 0;
1536 }
1537 
1539 {
1541  ID3D12CommandAllocator *command_allocator = NULL;
1542  int err = AVERROR_UNKNOWN;
1543  HRESULT hr;
1544 
1545  D3D12_COMMAND_QUEUE_DESC queue_desc = {
1546  .Type = D3D12_COMMAND_LIST_TYPE_VIDEO_ENCODE,
1547  .Priority = 0,
1548  .Flags = D3D12_COMMAND_QUEUE_FLAG_NONE,
1549  .NodeMask = 0,
1550  };
1551 
1554  if (!ctx->allocator_queue)
1555  return AVERROR(ENOMEM);
1556 
1557  hr = ID3D12Device_CreateFence(ctx->hwctx->device, 0, D3D12_FENCE_FLAG_NONE,
1558  &IID_ID3D12Fence, (void **)&ctx->sync_ctx.fence);
1559  if (FAILED(hr)) {
1560  av_log(avctx, AV_LOG_ERROR, "Failed to create fence(%lx)\n", (long)hr);
1561  err = AVERROR_UNKNOWN;
1562  goto fail;
1563  }
1564 
1565  ctx->sync_ctx.event = CreateEvent(NULL, FALSE, FALSE, NULL);
1566  if (!ctx->sync_ctx.event)
1567  goto fail;
1568 
1569  err = d3d12va_get_valid_command_allocator(avctx, &command_allocator);
1570  if (err < 0)
1571  goto fail;
1572 
1573  hr = ID3D12Device_CreateCommandQueue(ctx->hwctx->device, &queue_desc,
1574  &IID_ID3D12CommandQueue, (void **)&ctx->command_queue);
1575  if (FAILED(hr)) {
1576  av_log(avctx, AV_LOG_ERROR, "Failed to create command queue(%lx)\n", (long)hr);
1577  err = AVERROR_UNKNOWN;
1578  goto fail;
1579  }
1580 
1581  hr = ID3D12Device_CreateCommandList(ctx->hwctx->device, 0, queue_desc.Type,
1582  command_allocator, NULL, &IID_ID3D12CommandList,
1583  (void **)&ctx->command_list);
1584  if (FAILED(hr)) {
1585  av_log(avctx, AV_LOG_ERROR, "Failed to create command list(%lx)\n", (long)hr);
1586  err = AVERROR_UNKNOWN;
1587  goto fail;
1588  }
1589 
1590  hr = ID3D12VideoEncodeCommandList2_Close(ctx->command_list);
1591  if (FAILED(hr)) {
1592  av_log(avctx, AV_LOG_ERROR, "Failed to close the command list(%lx)\n", (long)hr);
1593  err = AVERROR_UNKNOWN;
1594  goto fail;
1595  }
1596 
1597  ID3D12CommandQueue_ExecuteCommandLists(ctx->command_queue, 1, (ID3D12CommandList **)&ctx->command_list);
1598 
1599  err = d3d12va_sync_with_gpu(avctx);
1600  if (err < 0)
1601  goto fail;
1602 
1603  err = d3d12va_discard_command_allocator(avctx, command_allocator, ctx->sync_ctx.fence_value);
1604  if (err < 0)
1605  goto fail;
1606 
1607  return 0;
1608 
1609 fail:
1610  D3D12_OBJECT_RELEASE(command_allocator);
1611  return err;
1612 }
1613 
1615 {
1616  FFHWBaseEncodeContext *base_ctx = avctx->priv_data;
1618  AVD3D12VAFramesContext *hwctx;
1619  enum AVPixelFormat recon_format;
1620  int err;
1621 
1622  err = ff_hw_base_get_recon_format(base_ctx, NULL, &recon_format);
1623  if (err < 0)
1624  return err;
1625 
1626  base_ctx->recon_frames_ref = av_hwframe_ctx_alloc(base_ctx->device_ref);
1627  if (!base_ctx->recon_frames_ref)
1628  return AVERROR(ENOMEM);
1629 
1630  base_ctx->recon_frames = (AVHWFramesContext *)base_ctx->recon_frames_ref->data;
1631  hwctx = (AVD3D12VAFramesContext *)base_ctx->recon_frames->hwctx;
1632 
1633  base_ctx->recon_frames->format = AV_PIX_FMT_D3D12;
1634  base_ctx->recon_frames->sw_format = recon_format;
1635  base_ctx->recon_frames->width = base_ctx->surface_width;
1636  base_ctx->recon_frames->height = base_ctx->surface_height;
1637 
1638  hwctx->resource_flags = D3D12_RESOURCE_FLAG_VIDEO_ENCODE_REFERENCE_ONLY |
1639  D3D12_RESOURCE_FLAG_DENY_SHADER_RESOURCE;
1640  if (ctx->is_texture_array) {
1641  base_ctx->recon_frames->initial_pool_size = MAX_DPB_SIZE + 1;
1643  }
1644 
1645  err = av_hwframe_ctx_init(base_ctx->recon_frames_ref);
1646  if (err < 0) {
1647  av_log(avctx, AV_LOG_ERROR, "Failed to initialise reconstructed "
1648  "frame context: %d.\n", err);
1649  return err;
1650  }
1651 
1652  return 0;
1653 }
1654 
1656  .priv_size = sizeof(D3D12VAEncodePicture),
1657 
1659 
1660  .issue = &d3d12va_encode_issue,
1661 
1663 
1664  .free = &d3d12va_encode_free,
1665 };
1666 
1668 {
1669  return ff_hw_base_encode_receive_packet(avctx->priv_data, avctx, pkt);
1670 }
1671 
1673 {
1674  FFHWBaseEncodeContext *base_ctx = avctx->priv_data;
1676  D3D12_FEATURE_DATA_VIDEO_FEATURE_AREA_SUPPORT support = { 0 };
1677  D3D12_FEATURE_DATA_FORMAT_INFO format_info = { 0 };
1678  int err;
1679  HRESULT hr;
1680 
1681  err = ff_hw_base_encode_init(avctx, base_ctx);
1682  if (err < 0)
1683  goto fail;
1684 
1685  base_ctx->op = &d3d12va_type;
1686 
1687  ctx->hwctx = base_ctx->device->hwctx;
1688 
1689  ctx->resolution.Width = base_ctx->input_frames->width;
1690  ctx->resolution.Height = base_ctx->input_frames->height;
1691 
1692  hr = ID3D12Device_QueryInterface(ctx->hwctx->device, &IID_ID3D12Device3, (void **)&ctx->device3);
1693  if (FAILED(hr)) {
1694  av_log(avctx, AV_LOG_ERROR, "ID3D12Device3 interface is not supported.\n");
1695  err = AVERROR_UNKNOWN;
1696  goto fail;
1697  }
1698 
1699  hr = ID3D12Device3_QueryInterface(ctx->device3, &IID_ID3D12VideoDevice3, (void **)&ctx->video_device3);
1700  if (FAILED(hr)) {
1701  av_log(avctx, AV_LOG_ERROR, "ID3D12VideoDevice3 interface is not supported.\n");
1702  err = AVERROR_UNKNOWN;
1703  goto fail;
1704  }
1705 
1706  if (FAILED(ID3D12VideoDevice3_CheckFeatureSupport(ctx->video_device3, D3D12_FEATURE_VIDEO_FEATURE_AREA_SUPPORT,
1707  &support, sizeof(support))) && !support.VideoEncodeSupport) {
1708  av_log(avctx, AV_LOG_ERROR, "D3D12 video device has no video encoder support.\n");
1709  err = AVERROR(EINVAL);
1710  goto fail;
1711  }
1712 
1713  format_info.Format = ((AVD3D12VAFramesContext *)base_ctx->input_frames->hwctx)->format;
1714  if (FAILED(ID3D12VideoDevice_CheckFeatureSupport(ctx->hwctx->device, D3D12_FEATURE_FORMAT_INFO,
1715  &format_info, sizeof(format_info)))) {
1716  av_log(avctx, AV_LOG_ERROR, "Failed to query format plane count: %#lx\n", hr);
1717  err = AVERROR_EXTERNAL;
1718  goto fail;
1719  }
1720  ctx->plane_count = format_info.PlaneCount;
1721 
1722  err = d3d12va_encode_set_profile(avctx);
1723  if (err < 0)
1724  goto fail;
1725 
1726  if (ctx->codec->set_tile) {
1727  err = ctx->codec->set_tile(avctx);
1728  if (err < 0)
1729  goto fail;
1730  }
1731 
1732  err = d3d12va_encode_init_rate_control(avctx);
1733  if (err < 0)
1734  goto fail;
1735 
1736  if (ctx->codec->get_encoder_caps) {
1737  err = ctx->codec->get_encoder_caps(avctx);
1738  if (err < 0)
1739  goto fail;
1740  }
1741 
1742  err = d3d12va_encode_init_gop_structure(avctx);
1743  if (err < 0)
1744  goto fail;
1745 
1746  err = d3d12va_encode_init_intra_refresh(avctx);
1747  if (err < 0)
1748  goto fail;
1749 
1750  if (!(ctx->codec->flags & FF_HW_FLAG_SLICE_CONTROL) && avctx->slices > 0) {
1751  av_log(avctx, AV_LOG_WARNING, "Multiple slices were requested "
1752  "but this codec does not support controlling slices.\n");
1753  }
1754 
1756  if (err < 0)
1757  goto fail;
1758 
1760  if (err < 0)
1761  goto fail;
1762 
1763  if (ctx->codec->configure) {
1764  err = ctx->codec->configure(avctx);
1765  if (err < 0)
1766  goto fail;
1767  }
1768 
1770  if (err < 0)
1771  goto fail;
1772 
1773  if (ctx->codec->init_sequence_params) {
1774  err = ctx->codec->init_sequence_params(avctx);
1775  if (err < 0) {
1776  av_log(avctx, AV_LOG_ERROR, "Codec sequence initialisation "
1777  "failed: %d.\n", err);
1778  goto fail;
1779  }
1780  }
1781 
1782  if (ctx->codec->set_level) {
1783  err = ctx->codec->set_level(avctx);
1784  if (err < 0)
1785  goto fail;
1786  }
1787 
1789  if (err < 0)
1790  goto fail;
1791 
1792  base_ctx->output_delay = base_ctx->b_per_p;
1793  base_ctx->decode_delay = base_ctx->max_b_depth;
1794 
1795  err = d3d12va_create_encoder(avctx);
1796  if (err < 0)
1797  goto fail;
1798 
1799  err = d3d12va_create_encoder_heap(avctx);
1800  if (err < 0)
1801  goto fail;
1802 
1803  base_ctx->async_encode = 1;
1804  base_ctx->encode_fifo = av_fifo_alloc2(base_ctx->async_depth,
1805  sizeof(D3D12VAEncodePicture *), 0);
1806  if (!base_ctx->encode_fifo)
1807  return AVERROR(ENOMEM);
1808 
1809  return 0;
1810 
1811 fail:
1812  return err;
1813 }
1814 
1816 {
1817  int num_allocator = 0;
1818  FFHWBaseEncodeContext *base_ctx = avctx->priv_data;
1820  FFHWBaseEncodePicture *pic, *next;
1821  CommandAllocator allocator;
1822 
1823  if (!base_ctx->frame)
1824  return 0;
1825 
1826  for (pic = base_ctx->pic_start; pic; pic = next) {
1827  next = pic->next;
1828  d3d12va_encode_free(avctx, pic);
1829  }
1830 
1832 
1833  av_buffer_pool_uninit(&ctx->output_buffer_pool);
1834 
1835  D3D12_OBJECT_RELEASE(ctx->command_list);
1836  D3D12_OBJECT_RELEASE(ctx->command_queue);
1837 
1838  if (ctx->allocator_queue) {
1839  while (av_fifo_read(ctx->allocator_queue, &allocator, 1) >= 0) {
1840  num_allocator++;
1842  }
1843 
1844  av_log(avctx, AV_LOG_VERBOSE, "Total number of command allocators reused: %d\n", num_allocator);
1845  }
1846 
1847  av_fifo_freep2(&ctx->allocator_queue);
1848 
1849  D3D12_OBJECT_RELEASE(ctx->sync_ctx.fence);
1850  if (ctx->sync_ctx.event)
1851  CloseHandle(ctx->sync_ctx.event);
1852 
1853  D3D12_OBJECT_RELEASE(ctx->encoder_heap);
1854  D3D12_OBJECT_RELEASE(ctx->encoder);
1855  D3D12_OBJECT_RELEASE(ctx->video_device3);
1856  D3D12_OBJECT_RELEASE(ctx->device3);
1857 
1858  ff_hw_base_encode_close(base_ctx);
1859 
1860  return 0;
1861 }
FFHWBaseEncodeContext::output_delay
int64_t output_delay
Definition: hw_base_encode.h:169
AVHWDeviceContext::hwctx
void * hwctx
The format-specific data, allocated and freed by libavutil along with this context.
Definition: hwcontext.h:88
AVD3D12VAFramesContext::flags
AVD3D12VAFrameFlags flags
A combination of AVD3D12VAFrameFlags.
Definition: hwcontext_d3d12va.h:206
AV_LOG_WARNING
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition: log.h:216
AVPixelFormat
AVPixelFormat
Pixel format.
Definition: pixfmt.h:71
level
uint8_t level
Definition: svq3.c:208
FFHWBaseEncodeContext::recon_frames_ref
AVBufferRef * recon_frames_ref
Definition: hw_base_encode.h:156
FFHWBaseEncodePicture::next
struct FFHWBaseEncodePicture * next
Definition: hw_base_encode.h:67
d3d12va_encode_set_profile
static int d3d12va_encode_set_profile(AVCodecContext *avctx)
Definition: d3d12va_encode.c:782
AVERROR
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFrame structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample they are references to shared objects When the negotiation mechanism computes the intersection of the formats supported at each end of a all references to both lists are replaced with a reference to the intersection And when a single format is eventually chosen for a link amongst the remaining all references to the list are updated That means that if a filter requires that its input and output have the same format amongst a supported all it has to do is use a reference to the same list of formats query_formats can leave some formats unset and return AVERROR(EAGAIN) to cause the negotiation mechanism toagain later. That can be used by filters with complex requirements to use the format negotiated on one link to set the formats supported on another. Frame references ownership and permissions
FFHWBaseEncodePicture::priv
void * priv
Definition: hw_base_encode.h:63
FFHWBaseEncodePicture::codec_priv
void * codec_priv
Definition: hw_base_encode.h:65
av_pix_fmt_desc_get
const AVPixFmtDescriptor * av_pix_fmt_desc_get(enum AVPixelFormat pix_fmt)
Definition: pixdesc.c:3456
AVBufferRef::data
uint8_t * data
The data buffer.
Definition: buffer.h:90
AVHWFramesContext::format
enum AVPixelFormat format
The pixel format identifying the underlying HW surface type.
Definition: hwcontext.h:200
AV_CODEC_FLAG_QSCALE
#define AV_CODEC_FLAG_QSCALE
Use fixed qscale.
Definition: avcodec.h:213
int64_t
long long int64_t
Definition: coverity.c:34
output
filter_frame For filters that do not use the this method is called when a frame is pushed to the filter s input It can be called at any time except in a reentrant way If the input frame is enough to produce output
Definition: filter_design.txt:226
d3d12va_encode_create_recon_frames
static int d3d12va_encode_create_recon_frames(AVCodecContext *avctx)
Definition: d3d12va_encode.c:1614
av_frame_free
void av_frame_free(AVFrame **frame)
Free the frame and any dynamically allocated objects in it, e.g.
Definition: frame.c:64
av_fifo_peek
int av_fifo_peek(const AVFifo *f, void *buf, size_t nb_elems, size_t offset)
Read data from a FIFO without modifying FIFO state.
Definition: fifo.c:255
av_hwframe_ctx_init
int av_hwframe_ctx_init(AVBufferRef *ref)
Finalize the context before use.
Definition: hwcontext.c:337
AVFrame
This structure describes decoded (raw) audio or video data.
Definition: frame.h:427
pixdesc.h
D3D12VAEncodePicture::input_surface
AVD3D12VAFrame * input_surface
Definition: d3d12va_encode.h:46
av_hwframe_ctx_alloc
AVBufferRef * av_hwframe_ctx_alloc(AVBufferRef *device_ref_in)
Allocate an AVHWFramesContext tied to a given device context.
Definition: hwcontext.c:263
AVPacket::data
uint8_t * data
Definition: packet.h:588
ff_hw_base_encode_init
int ff_hw_base_encode_init(AVCodecContext *avctx, FFHWBaseEncodeContext *ctx)
Definition: hw_base_encode.c:781
encode.h
d3d12va_encode.h
d3d12va_encode_get_coded_data
static int d3d12va_encode_get_coded_data(AVCodecContext *avctx, D3D12VAEncodePicture *pic, AVPacket *pkt)
Definition: d3d12va_encode.c:710
data
const char data[16]
Definition: mxf.c:149
FF_HW_FLAG_SLICE_CONTROL
@ FF_HW_FLAG_SLICE_CONTROL
Definition: hw_base_encode.h:47
FFHWBaseEncodePicture::recon_image
AVFrame * recon_image
Definition: hw_base_encode.h:84
AV_LOG_VERBOSE
#define AV_LOG_VERBOSE
Detailed information.
Definition: log.h:226
AVERROR_UNKNOWN
#define AVERROR_UNKNOWN
Unknown error, typically from an external library.
Definition: error.h:73
AVHWFramesContext::width
int width
The allocated dimensions of the frames in this pool.
Definition: hwcontext.h:220
AVFrame::data
uint8_t * data[AV_NUM_DATA_POINTERS]
pointer to the picture/channel planes.
Definition: frame.h:448
D3D12VAEncodePicture::resolved_metadata
ID3D12Resource * resolved_metadata
Definition: d3d12va_encode.h:53
FFHWBaseEncodeContext
Definition: hw_base_encode.h:122
AVCodecContext::framerate
AVRational framerate
Definition: avcodec.h:559
d3d12va_encode_output
static int d3d12va_encode_output(AVCodecContext *avctx, FFHWBaseEncodePicture *base_pic, AVPacket *pkt)
Definition: d3d12va_encode.c:752
ff_d3d12va_encode_hw_configs
const AVCodecHWConfigInternal *const ff_d3d12va_encode_hw_configs[]
Definition: d3d12va_encode.c:37
D3D12VAEncodePicture::output_buffer_ref
AVBufferRef * output_buffer_ref
Definition: d3d12va_encode.h:49
d3d12va_encode_free
static int d3d12va_encode_free(AVCodecContext *avctx, FFHWBaseEncodePicture *pic)
Definition: d3d12va_encode.c:661
d3d12va_sync_with_gpu
static int d3d12va_sync_with_gpu(AVCodecContext *avctx)
Definition: d3d12va_encode.c:55
FFHWBaseEncodePicture::type
int type
Definition: hw_base_encode.h:78
ff_hw_base_encode_close
int ff_hw_base_encode_close(FFHWBaseEncodeContext *ctx)
Definition: hw_base_encode.c:814
FFHWBaseEncodePicture::is_reference
int is_reference
Definition: hw_base_encode.h:87
fail
#define fail()
Definition: checkasm.h:214
av_fifo_write
int av_fifo_write(AVFifo *f, const void *buf, size_t nb_elems)
Write data into a FIFO.
Definition: fifo.c:188
D3D12VAEncodePicture::output_buffer
ID3D12Resource * output_buffer
Definition: d3d12va_encode.h:50
CommandAllocator::command_allocator
ID3D12CommandAllocator * command_allocator
Definition: d3d12va_encode.c:67
D3D12VAEncodePicture::recon_surface
AVD3D12VAFrame * recon_surface
Definition: d3d12va_encode.h:47
av_buffer_pool_init2
AVBufferPool * av_buffer_pool_init2(size_t size, void *opaque, AVBufferRef *(*alloc)(void *opaque, size_t size), void(*pool_free)(void *opaque))
Allocate and initialize a buffer pool with a more complex allocator.
Definition: buffer.c:259
AVCodecContext::flags
int flags
AV_CODEC_FLAG_*.
Definition: avcodec.h:496
FFHWBaseEncodePicture::input_image
AVFrame * input_image
Definition: hw_base_encode.h:83
CommandAllocator::fence_value
uint64_t fence_value
Definition: d3d12va_encode.c:68
ff_hw_base_init_gop_structure
int ff_hw_base_init_gop_structure(FFHWBaseEncodeContext *ctx, AVCodecContext *avctx, uint32_t ref_l0, uint32_t ref_l1, int flags, int prediction_pre_only)
Definition: hw_base_encode.c:662
av_reduce
int av_reduce(int *dst_num, int *dst_den, int64_t num, int64_t den, int64_t max)
Reduce a fraction.
Definition: rational.c:35
AVRational::num
int num
Numerator.
Definition: rational.h:59
FFHWBaseEncodeContext::device
AVHWDeviceContext * device
Definition: hw_base_encode.h:149
avassert.h
d3d12va_encode_rc_modes
static const D3D12VAEncodeRCMode d3d12va_encode_rc_modes[]
Definition: d3d12va_encode.c:835
check_rate_control_support
static int check_rate_control_support(AVCodecContext *avctx, const D3D12VAEncodeRCMode *rc_mode)
Definition: d3d12va_encode.c:845
ff_hw_base_get_recon_format
int ff_hw_base_get_recon_format(FFHWBaseEncodeContext *ctx, const void *hwconfig, enum AVPixelFormat *fmt)
Definition: hw_base_encode.c:723
d3d12va_encode_get_buffer_size
static int d3d12va_encode_get_buffer_size(AVCodecContext *avctx, D3D12VAEncodePicture *pic, size_t *size)
Definition: d3d12va_encode.c:675
pkt
AVPacket * pkt
Definition: movenc.c:60
AV_LOG_ERROR
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:210
AV_PROFILE_UNKNOWN
#define AV_PROFILE_UNKNOWN
Definition: defs.h:65
d3d12va_encode_wait
static int d3d12va_encode_wait(AVCodecContext *avctx, FFHWBaseEncodePicture *base_pic)
Definition: d3d12va_encode.c:110
av_fifo_read
int av_fifo_read(AVFifo *f, void *buf, size_t nb_elems)
Read data from a FIFO.
Definition: fifo.c:240
AVCodecContext::rc_initial_buffer_occupancy
int rc_initial_buffer_occupancy
Number of bits which should be loaded into the rc buffer before decoding starts.
Definition: avcodec.h:1306
AVHWFramesContext::height
int height
Definition: hwcontext.h:220
d3d12va_encode_issue
static int d3d12va_encode_issue(AVCodecContext *avctx, FFHWBaseEncodePicture *base_pic)
Definition: d3d12va_encode.c:195
av_buffer_pool_get
AVBufferRef * av_buffer_pool_get(AVBufferPool *pool)
Allocate a new AVBuffer, reusing an old buffer from the pool when available.
Definition: buffer.c:390
AVCodecContext::global_quality
int global_quality
Global quality for codecs which cannot change it per frame.
Definition: avcodec.h:1225
D3D12_OBJECT_RELEASE
#define D3D12_OBJECT_RELEASE(pInterface)
A release macro used by D3D12 objects highly frequently.
Definition: hwcontext_d3d12va_internal.h:51
D3D12VAEncodePicture::header_size
int header_size
Definition: d3d12va_encode.h:43
AV_BUFFER_FLAG_READONLY
#define AV_BUFFER_FLAG_READONLY
Always treat the buffer as read-only, even when it has only one reference.
Definition: buffer.h:114
AVFormatContext::flags
int flags
Flags modifying the (de)muxer behaviour.
Definition: avformat.h:1415
SET_QP_RANGE
#define SET_QP_RANGE(ctl)
FFHWBaseEncodeContext::max_b_depth
int max_b_depth
Definition: hw_base_encode.h:188
FFHWBaseEncodeContext::async_encode
int async_encode
Definition: hw_base_encode.h:216
AVD3D12VAFrame::sync_ctx
AVD3D12VASyncContext sync_ctx
The sync context for the texture.
Definition: hwcontext_d3d12va.h:159
av_assert0
#define av_assert0(cond)
assert() equivalent, that is always enabled.
Definition: avassert.h:41
d3d12va_create_encoder_heap
static int d3d12va_create_encoder_heap(AVCodecContext *avctx)
Definition: d3d12va_encode.c:1423
AV_LOG_DEBUG
#define AV_LOG_DEBUG
Stuff which is only useful for libav* developers.
Definition: log.h:231
ctx
AVFormatContext * ctx
Definition: movenc.c:49
D3D12VAEncodePicture::pic_ctl
D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA pic_ctl
Definition: d3d12va_encode.h:57
AVD3D12VASyncContext
This struct is used to sync d3d12 execution.
Definition: hwcontext_d3d12va.h:104
d3d12va_encode_discard
static int d3d12va_encode_discard(AVCodecContext *avctx, FFHWBaseEncodePicture *base_pic)
Definition: d3d12va_encode.c:597
AVCodecContext::rc_max_rate
int64_t rc_max_rate
maximum bitrate
Definition: avcodec.h:1278
av_mallocz
#define av_mallocz(s)
Definition: tableprint_vlc.h:31
AVD3D12VASyncContext::fence
ID3D12Fence * fence
D3D12 fence object.
Definition: hwcontext_d3d12va.h:108
D3D12VAEncodeRCMode
Definition: d3d12va_encode.h:104
FFHWBaseEncodeContext::pic_start
FFHWBaseEncodePicture * pic_start
Definition: hw_base_encode.h:160
FFHWBaseEncodeContext::b_per_p
int b_per_p
Definition: hw_base_encode.h:189
AVCodecContext::rc_buffer_size
int rc_buffer_size
decoder bitstream buffer size
Definition: avcodec.h:1263
d3d12va_discard_command_allocator
static int d3d12va_discard_command_allocator(AVCodecContext *avctx, ID3D12CommandAllocator *pAllocator, uint64_t fence_value)
Definition: d3d12va_encode.c:96
D3D12VAEncodePicture::fence_value
int fence_value
Definition: d3d12va_encode.h:59
NULL
#define NULL
Definition: coverity.c:32
AVHWFramesContext::sw_format
enum AVPixelFormat sw_format
The pixel format identifying the actual data layout of the hardware frames.
Definition: hwcontext.h:213
av_buffer_unref
void av_buffer_unref(AVBufferRef **buf)
Free a given reference and automatically free the buffer if there are no more references to it.
Definition: buffer.c:139
AVCodecContext::bit_rate
int64_t bit_rate
the average bitrate
Definition: avcodec.h:489
D3D12VAEncodePicture::subresource_index
int subresource_index
Definition: d3d12va_encode.h:55
av_buffer_pool_uninit
void av_buffer_pool_uninit(AVBufferPool **ppool)
Mark the pool as being available for freeing.
Definition: buffer.c:328
FFHWEncodePictureOperation
Definition: hw_base_encode.h:109
AVD3D12VAFramesContext
This struct is allocated as AVHWFramesContext.hwctx.
Definition: hwcontext_d3d12va.h:172
AV_PIX_FMT_D3D12
@ AV_PIX_FMT_D3D12
Hardware surfaces for Direct3D 12.
Definition: pixfmt.h:440
AVD3D12VAFrame::texture
ID3D12Resource * texture
The texture in which the frame is located.
Definition: hwcontext_d3d12va.h:144
hwcontext_d3d12va.h
AVD3D12VAFramesContext::resource_flags
D3D12_RESOURCE_FLAGS resource_flags
Options for working with resources.
Definition: hwcontext_d3d12va.h:185
av_buffer_create
AVBufferRef * av_buffer_create(uint8_t *data, size_t size, void(*free)(void *opaque, uint8_t *data), void *opaque, int flags)
Create an AVBuffer from an existing array.
Definition: buffer.c:55
AVCodecContext::time_base
AVRational time_base
This is the fundamental unit of time (in seconds) in terms of which frame timestamps are represented.
Definition: avcodec.h:543
ff_hw_base_encode_set_output_property
int ff_hw_base_encode_set_output_property(FFHWBaseEncodeContext *ctx, AVCodecContext *avctx, FFHWBaseEncodePicture *pic, AVPacket *pkt, int flag_no_delay)
Definition: hw_base_encode.c:519
FF_HW_FLAG_CONSTANT_QUALITY_ONLY
@ FF_HW_FLAG_CONSTANT_QUALITY_ONLY
Definition: hw_base_encode.h:49
d3d12va_encode_free_buffer
static void d3d12va_encode_free_buffer(void *opaque, uint8_t *data)
Definition: d3d12va_encode.c:1448
FFHWEncodePictureOperation::priv_size
size_t priv_size
Definition: hw_base_encode.h:111
d3d12va_encode_create_metadata_buffers
static int d3d12va_encode_create_metadata_buffers(AVCodecContext *avctx, D3D12VAEncodePicture *pic)
Definition: d3d12va_encode.c:143
FFHWBaseEncodeContext::frame
AVFrame * frame
Definition: hw_base_encode.h:211
init
int(* init)(AVBSFContext *ctx)
Definition: dts2pts.c:550
d3d12va_get_valid_command_allocator
static int d3d12va_get_valid_command_allocator(AVCodecContext *avctx, ID3D12CommandAllocator **ppAllocator)
Definition: d3d12va_encode.c:71
d3d12va_encode_create_command_objects
static int d3d12va_encode_create_command_objects(AVCodecContext *avctx)
Definition: d3d12va_encode.c:1538
ff_d3d12va_encode_init
int ff_d3d12va_encode_init(AVCodecContext *avctx)
Definition: d3d12va_encode.c:1672
FFHWBaseEncodePicture::nb_refs
int nb_refs[MAX_REFERENCE_LIST_NUM]
Definition: hw_base_encode.h:97
CommandAllocator
Definition: d3d12va_encode.c:66
d3d12va_type
static const FFHWEncodePictureOperation d3d12va_type
Definition: d3d12va_encode.c:1655
MAX_DPB_SIZE
#define MAX_DPB_SIZE
Definition: hw_base_encode.h:26
D3D12VAEncodeProfile
Definition: d3d12va_encode.h:62
FFHWBaseEncodeContext::decode_delay
int64_t decode_delay
Definition: hw_base_encode.h:173
size
int size
Definition: twinvq_data.h:10344
ff_hw_base_encode_receive_packet
int ff_hw_base_encode_receive_packet(FFHWBaseEncodeContext *ctx, AVCodecContext *avctx, AVPacket *pkt)
Definition: hw_base_encode.c:558
SET_MAX_FRAME_SIZE
#define SET_MAX_FRAME_SIZE(ctl)
AVCodecHWConfigInternal
Definition: hwconfig.h:25
FFHWBaseEncodeContext::p_to_gpb
int p_to_gpb
Definition: hw_base_encode.h:194
FFHWBaseEncodePicture::encode_order
int64_t encode_order
Definition: hw_base_encode.h:70
AVERROR_EXTERNAL
#define AVERROR_EXTERNAL
Generic error in an external library.
Definition: error.h:59
AVD3D12VAFrame
D3D12VA frame descriptor for pool allocation.
Definition: hwcontext_d3d12va.h:138
RC_MODE_QVBR
@ RC_MODE_QVBR
Definition: d3d12va_encode.h:99
D3D12VA_VIDEO_ENC_ASYNC_DEPTH
#define D3D12VA_VIDEO_ENC_ASYNC_DEPTH
Definition: d3d12va_encode.h:40
D3D12VAEncodePicture::encoded_metadata
ID3D12Resource * encoded_metadata
Definition: d3d12va_encode.h:52
D3D12VAEncodePicture
Definition: d3d12va_encode.h:42
MAX_PARAM_BUFFER_SIZE
@ MAX_PARAM_BUFFER_SIZE
Definition: vaapi_encode.h:47
d3d12va_encode_alloc_output_buffer
static AVBufferRef * d3d12va_encode_alloc_output_buffer(void *opaque, size_t size)
Definition: d3d12va_encode.c:1456
HW_CONFIG_ENCODER_FRAMES
#define HW_CONFIG_ENCODER_FRAMES(format, device_type_)
Definition: hwconfig.h:98
d3d12va_encode_init
static int d3d12va_encode_init(AVCodecContext *avctx, FFHWBaseEncodePicture *pic)
Definition: d3d12va_encode.c:644
log.h
FFHWBaseEncodeContext::op
const struct FFHWEncodePictureOperation * op
Definition: hw_base_encode.h:127
i
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:256
AV_D3D12VA_FRAME_FLAG_TEXTURE_ARRAY
@ AV_D3D12VA_FRAME_FLAG_TEXTURE_ARRAY
Indicates that frame data should be allocated using a texture array resource.
Definition: hwcontext_d3d12va.h:131
internal.h
TRY_RC_MODE
#define TRY_RC_MODE(mode, fail)
RC_MODE_VBR
@ RC_MODE_VBR
Definition: d3d12va_encode.h:98
common.h
FFMIN
#define FFMIN(a, b)
Definition: macros.h:49
FFHWBaseEncodePicture::refs
struct FFHWBaseEncodePicture * refs[MAX_REFERENCE_LIST_NUM][MAX_PICTURE_REFERENCES]
Definition: hw_base_encode.h:98
d3d12va_fence_completion
static int d3d12va_fence_completion(AVD3D12VASyncContext *psync_ctx)
Definition: d3d12va_encode.c:42
d3d12va_encode_init_intra_refresh
static int d3d12va_encode_init_intra_refresh(AVCodecContext *avctx)
Definition: d3d12va_encode.c:1321
profile
int profile
Definition: mxfenc.c:2297
av_calloc
void * av_calloc(size_t nmemb, size_t size)
Definition: mem.c:264
d3d12va_create_encoder
static int d3d12va_create_encoder(AVCodecContext *avctx)
Definition: d3d12va_encode.c:1396
avcodec.h
AVD3D12VAFramesContext::format
DXGI_FORMAT format
DXGI_FORMAT format.
Definition: hwcontext_d3d12va.h:177
AVHWFramesContext
This struct describes a set or pool of "hardware" frames (i.e.
Definition: hwcontext.h:118
d3d12va_encode_init_rate_control
static int d3d12va_encode_init_rate_control(AVCodecContext *avctx)
Definition: d3d12va_encode.c:870
FFHWBaseEncodeContext::gop_size
int gop_size
Definition: hw_base_encode.h:184
FFHWBaseEncodePicture
Definition: hw_base_encode.h:61
FFSWAP
#define FFSWAP(type, a, b)
Definition: macros.h:52
frame
these buffered frames must be flushed immediately if a new input produces new the filter must not call request_frame to get more It must just process the frame or queue it The task of requesting more frames is left to the filter s request_frame method or the application If a filter has several the filter must be ready for frames arriving randomly on any input any filter with several inputs will most likely require some kind of queuing mechanism It is perfectly acceptable to have a limited queue and to drop frames when the inputs are too unbalanced request_frame For filters that do not use the this method is called when a frame is wanted on an output For a it should directly call filter_frame on the corresponding output For a if there are queued frames already one of these frames should be pushed If the filter should request a frame on one of its repeatedly until at least one frame has been pushed Return or at least make progress towards producing a frame
Definition: filter_design.txt:265
AVHWFramesContext::hwctx
void * hwctx
The format-specific data, allocated and freed automatically along with this context.
Definition: hwcontext.h:153
D3D12VAEncodeContext
Definition: d3d12va_encode.h:146
FFHWBaseEncodeContext::device_ref
AVBufferRef * device_ref
Definition: hw_base_encode.h:148
FFHWBaseEncodeContext::encode_fifo
AVFifo * encode_fifo
Definition: hw_base_encode.h:219
av_fifo_alloc2
AVFifo * av_fifo_alloc2(size_t nb_elems, size_t elem_size, unsigned int flags)
Allocate and initialize an AVFifo with a given element size.
Definition: fifo.c:47
ff_hw_base_encode_get_pictype_name
static const char * ff_hw_base_encode_get_pictype_name(const int type)
Definition: hw_base_encode.h:32
d3d12va_encode_prepare_output_buffers
static int d3d12va_encode_prepare_output_buffers(AVCodecContext *avctx)
Definition: d3d12va_encode.c:1504
FFHWBaseEncodeContext::surface_height
int surface_height
Definition: hw_base_encode.h:141
FF_HW_PICTURE_TYPE_IDR
@ FF_HW_PICTURE_TYPE_IDR
Definition: hw_base_encode.h:39
FFHWBaseEncodeContext::async_depth
int async_depth
Definition: hw_base_encode.h:221
AVCodecContext
main external API structure.
Definition: avcodec.h:439
AVD3D12VASyncContext::event
HANDLE event
A handle to the event object that's raised when the fence reaches a certain value.
Definition: hwcontext_d3d12va.h:114
d3d12va_encode_init_motion_estimation_precision
static int d3d12va_encode_init_motion_estimation_precision(AVCodecContext *avctx)
Definition: d3d12va_encode.c:1146
ff_get_encode_buffer
int ff_get_encode_buffer(AVCodecContext *avctx, AVPacket *avpkt, int64_t size, int flags)
Get a buffer for a packet.
Definition: encode.c:105
AVRational::den
int den
Denominator.
Definition: rational.h:60
AVCodecContext::profile
int profile
profile
Definition: avcodec.h:1626
d3d12va_encode_free_rc_params
static int d3d12va_encode_free_rc_params(AVCodecContext *avctx)
Definition: d3d12va_encode.c:619
D3D12VAEncodePicture::aligned_header_size
int aligned_header_size
Definition: d3d12va_encode.h:44
ref
static int ref[MAX_W *MAX_W]
Definition: jpeg2000dwt.c:117
FFHWBaseEncodeContext::input_frames
AVHWFramesContext * input_frames
Definition: hw_base_encode.h:153
FFHWBaseEncodeContext::surface_width
int surface_width
Definition: hw_base_encode.h:140
AVHWFramesContext::initial_pool_size
int initial_pool_size
Initial size of the frame pool.
Definition: hwcontext.h:190
desc
const char * desc
Definition: libsvtav1.c:78
FFHWBaseEncodePicture::encode_complete
int encode_complete
Definition: hw_base_encode.h:81
mem.h
AVBufferRef
A reference to a data buffer.
Definition: buffer.h:82
AVPixFmtDescriptor
Descriptor that unambiguously describes how the bits of a pixel are stored in the up to 4 data planes...
Definition: pixdesc.h:69
ff_d3d12va_encode_close
int ff_d3d12va_encode_close(AVCodecContext *avctx)
Definition: d3d12va_encode.c:1815
FFALIGN
#define FFALIGN(x, a)
Definition: macros.h:78
AVCodecContext::slices
int slices
Number of slices.
Definition: avcodec.h:1029
ff_d3d12va_encode_receive_packet
int ff_d3d12va_encode_receive_packet(AVCodecContext *avctx, AVPacket *pkt)
Definition: d3d12va_encode.c:1667
AVPacket
This structure stores compressed data.
Definition: packet.h:565
AVCodecContext::priv_data
void * priv_data
Definition: avcodec.h:466
av_freep
#define av_freep(p)
Definition: tableprint_vlc.h:35
d3d12va_encode_init_gop_structure
static int d3d12va_encode_init_gop_structure(AVCodecContext *avctx)
Definition: d3d12va_encode.c:1231
FFHWBaseEncodeContext::recon_frames
AVHWFramesContext * recon_frames
Definition: hw_base_encode.h:157
DX_CHECK
#define DX_CHECK(hr)
A check macro used by D3D12 functions highly frequently.
Definition: hwcontext_d3d12va_internal.h:40
av_log
#define av_log(a,...)
Definition: tableprint_vlc.h:27
av_fifo_freep2
void av_fifo_freep2(AVFifo **f)
Free an AVFifo and reset pointer to NULL.
Definition: fifo.c:286
AVD3D12VASyncContext::fence_value
uint64_t fence_value
The fence value used for sync.
Definition: hwcontext_d3d12va.h:119
FFHWBaseEncodePicture::encode_issued
int encode_issued
Definition: hw_base_encode.h:80
width
#define width
Definition: dsp.h:89
FF_QP2LAMBDA
#define FF_QP2LAMBDA
factor to convert from H.263 QP to lambda
Definition: avutil.h:226
rc_mode
mfxU16 rc_mode
Definition: qsvenc.c:141
hwcontext_d3d12va_internal.h
FFHWBaseEncodePicture::display_order
int64_t display_order
Definition: hw_base_encode.h:69
AV_FIFO_FLAG_AUTO_GROW
#define AV_FIFO_FLAG_AUTO_GROW
Automatically resize the FIFO on writes, so that the data fits.
Definition: fifo.h:63
AVD3D12VAFrame::subresource_index
int subresource_index
Index of the subresource within the texture.
Definition: hwcontext_d3d12va.h:152
RC_MODE_CQP
@ RC_MODE_CQP
Definition: d3d12va_encode.h:96
TRANSITION_BARRIER
#define TRANSITION_BARRIER(res, subres, before, after)
RC_MODE_CBR
@ RC_MODE_CBR
Definition: d3d12va_encode.h:97