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  const uint8_t *data, size_t size)
146 {
148  const AVRegionOfInterest *roi;
149  uint32_t roi_size;
150  int nb_roi, i;
151  int block_width, block_height;
152  int block_size, qp_range;
153  int is_av1 = 0;
154 
155  // Use the QP map region size reported by the driver
156  block_size = ctx->qp_map_region_size;
157 
158  // Determine QP range and element size based on codec
159  switch (ctx->codec->d3d12_codec) {
160  case D3D12_VIDEO_ENCODER_CODEC_H264:
161  case D3D12_VIDEO_ENCODER_CODEC_HEVC:
162  qp_range = 51;
163  is_av1 = 0;
164  break;
165 #if CONFIG_AV1_D3D12VA_ENCODER
166  case D3D12_VIDEO_ENCODER_CODEC_AV1:
167  qp_range = 255;
168  is_av1 = 1;
169  break;
170 #endif
171  default:
172  av_log(avctx, AV_LOG_ERROR, "Unsupported codec for ROI.\n");
173  return AVERROR(EINVAL);
174  }
175 
176  // Calculate map dimensions using ceil division as required by D3D12
177  block_width = (avctx->width + block_size - 1) / block_size;
178  block_height = (avctx->height + block_size - 1) / block_size;
179 
180  // Allocate QP map with correct type based on codec
181  if (is_av1) {
182  pic->qp_map = av_calloc(block_width * block_height, sizeof(int16_t));
183  } else {
184  pic->qp_map = av_calloc(block_width * block_height, sizeof(int8_t));
185  }
186  if (!pic->qp_map)
187  return AVERROR(ENOMEM);
188 
189  // Process ROI regions
190  roi = (const AVRegionOfInterest *)data;
191  roi_size = roi->self_size;
192  av_assert0(roi_size && size % roi_size == 0);
193  nb_roi = size / roi_size;
194 
195  // Iterate in reverse for priority (first region in array takes priority on overlap)
196  for (i = nb_roi - 1; i >= 0; i--) {
197  int startx, endx, starty, endy;
198  int delta_qp;
199  int x, y;
200 
201  roi = (const AVRegionOfInterest *)(data + roi_size * i);
202 
203  // Convert pixel coordinates to block coordinates
204  starty = FFMIN(block_height, roi->top / block_size);
205  endy = FFMIN(block_height, (roi->bottom + block_size - 1) / block_size);
206  startx = FFMIN(block_width, roi->left / block_size);
207  endx = FFMIN(block_width, (roi->right + block_size - 1) / block_size);
208 
209  if (roi->qoffset.den == 0) {
210  av_freep(&pic->qp_map);
211  av_log(avctx, AV_LOG_ERROR, "AVRegionOfInterest.qoffset.den must not be zero.\n");
212  return AVERROR(EINVAL);
213  }
214 
215  // Convert qoffset to delta QP
216  delta_qp = roi->qoffset.num * qp_range / roi->qoffset.den;
217 
218  av_log(avctx, AV_LOG_DEBUG, "ROI: (%d,%d)-(%d,%d) -> %+d.\n",
219  roi->top, roi->left, roi->bottom, roi->right, delta_qp);
220 
221  // Fill QP map for this ROI region with correct type
222  if (is_av1) {
223  int16_t *qp_map_int16 = (int16_t *)pic->qp_map;
224  delta_qp = av_clip_int16(delta_qp);
225  for (y = starty; y < endy; y++)
226  for (x = startx; x < endx; x++)
227  qp_map_int16[x + y * block_width] = delta_qp;
228  } else {
229  int8_t *qp_map_int8 = (int8_t *)pic->qp_map;
230  delta_qp = av_clip_int8(delta_qp);
231  for (y = starty; y < endy; y++)
232  for (x = startx; x < endx; x++)
233  qp_map_int8[x + y * block_width] = delta_qp;
234  }
235  }
236 
237  pic->qp_map_size = block_width * block_height;
238 
239  return 0;
240 }
241 
244 {
246  int width = sizeof(D3D12_VIDEO_ENCODER_OUTPUT_METADATA) + sizeof(D3D12_VIDEO_ENCODER_FRAME_SUBREGION_METADATA);
247 #if CONFIG_AV1_D3D12VA_ENCODER
248  if (ctx->codec->d3d12_codec == D3D12_VIDEO_ENCODER_CODEC_AV1) {
249  width += sizeof(D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_SUBREGIONS_LAYOUT_DATA_TILES)
250  + sizeof(D3D12_VIDEO_ENCODER_AV1_POST_ENCODE_VALUES);
251  }
252 #endif
253  D3D12_HEAP_PROPERTIES encoded_meta_props = { .Type = D3D12_HEAP_TYPE_DEFAULT }, resolved_meta_props;
254  D3D12_HEAP_TYPE resolved_heap_type = D3D12_HEAP_TYPE_READBACK;
255  HRESULT hr;
256 
257  D3D12_RESOURCE_DESC meta_desc = {
258  .Dimension = D3D12_RESOURCE_DIMENSION_BUFFER,
259  .Alignment = 0,
260  .Width = ctx->req.MaxEncoderOutputMetadataBufferSize,
261  .Height = 1,
262  .DepthOrArraySize = 1,
263  .MipLevels = 1,
264  .Format = DXGI_FORMAT_UNKNOWN,
265  .SampleDesc = { .Count = 1, .Quality = 0 },
266  .Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR,
267  .Flags = D3D12_RESOURCE_FLAG_NONE,
268  };
269 
270  hr = ID3D12Device_CreateCommittedResource(ctx->hwctx->device, &encoded_meta_props, D3D12_HEAP_FLAG_NONE,
271  &meta_desc, D3D12_RESOURCE_STATE_COMMON, NULL,
272  &IID_ID3D12Resource, (void **)&pic->encoded_metadata);
273  if (FAILED(hr)) {
274  av_log(avctx, AV_LOG_ERROR, "Failed to create metadata buffer.\n");
275  return AVERROR_UNKNOWN;
276  }
277 
278  ctx->hwctx->device->lpVtbl->GetCustomHeapProperties(ctx->hwctx->device, &resolved_meta_props, 0, resolved_heap_type);
279 
280  meta_desc.Width = width;
281 
282  hr = ID3D12Device_CreateCommittedResource(ctx->hwctx->device, &resolved_meta_props, D3D12_HEAP_FLAG_NONE,
283  &meta_desc, D3D12_RESOURCE_STATE_COMMON, NULL,
284  &IID_ID3D12Resource, (void **)&pic->resolved_metadata);
285 
286  if (FAILED(hr)) {
287  av_log(avctx, AV_LOG_ERROR, "Failed to create output metadata buffer.\n");
288  return AVERROR_UNKNOWN;
289  }
290 
291  return 0;
292 }
293 
295  FFHWBaseEncodePicture *base_pic)
296 {
297  FFHWBaseEncodeContext *base_ctx = avctx->priv_data;
299  D3D12VAEncodePicture *pic = base_pic->priv;
300  AVD3D12VAFramesContext *frames_hwctx = base_ctx->input_frames->hwctx;
301  int err, i, j;
302  HRESULT hr;
304  void *ptr;
305  size_t bit_len;
306  ID3D12CommandAllocator *command_allocator = NULL;
307  ID3D12VideoEncodeCommandList2 *cmd_list = ctx->command_list;
308  D3D12_RESOURCE_BARRIER barriers[32] = { 0 };
309  D3D12_VIDEO_ENCODE_REFERENCE_FRAMES d3d12_refs = { 0 };
310  int barriers_ref_index = 0;
311  D3D12_RESOURCE_BARRIER *barriers_ref = NULL;
312 
313  D3D12_VIDEO_ENCODER_SEQUENCE_CONTROL_FLAGS seq_flags = D3D12_VIDEO_ENCODER_SEQUENCE_CONTROL_FLAG_NONE;
314 
315  // Request intra refresh if enabled
316  if (ctx->intra_refresh.Mode != D3D12_VIDEO_ENCODER_INTRA_REFRESH_MODE_NONE) {
317  seq_flags |= D3D12_VIDEO_ENCODER_SEQUENCE_CONTROL_FLAG_REQUEST_INTRA_REFRESH;
318  }
319 
320  D3D12_VIDEO_ENCODER_ENCODEFRAME_INPUT_ARGUMENTS input_args = {
321  .SequenceControlDesc = {
322  .Flags = seq_flags,
323  .IntraRefreshConfig = ctx->intra_refresh,
324  .RateControl = ctx->rc,
325  .PictureTargetResolution = ctx->resolution,
326  .SelectedLayoutMode = D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_FULL_FRAME,
327  .FrameSubregionsLayoutData = ctx->subregions_layout,
328  .CodecGopSequence = ctx->gop,
329  },
330  .pInputFrame = pic->input_surface->texture,
331  .InputFrameSubresource = 0,
332  };
333 
334  D3D12_VIDEO_ENCODER_ENCODEFRAME_OUTPUT_ARGUMENTS output_args = { 0 };
335 
336  D3D12_VIDEO_ENCODER_RESOLVE_METADATA_INPUT_ARGUMENTS input_metadata = {
337  .EncoderCodec = ctx->codec->d3d12_codec,
338  .EncoderProfile = ctx->profile->d3d12_profile,
339  .EncoderInputFormat = frames_hwctx->format,
340  .EncodedPictureEffectiveResolution = ctx->resolution,
341  };
342 
343  D3D12_VIDEO_ENCODER_RESOLVE_METADATA_OUTPUT_ARGUMENTS output_metadata = { 0 };
344 
345  memset(data, 0, sizeof(data));
346 
347  av_log(avctx, AV_LOG_DEBUG, "Issuing encode for pic %"PRId64"/%"PRId64" "
348  "as type %s.\n", base_pic->display_order, base_pic->encode_order,
350  if (base_pic->nb_refs[0] == 0 && base_pic->nb_refs[1] == 0) {
351  av_log(avctx, AV_LOG_DEBUG, "No reference pictures.\n");
352  } else {
353  av_log(avctx, AV_LOG_DEBUG, "L0 refers to");
354  for (i = 0; i < base_pic->nb_refs[0]; i++) {
355  av_log(avctx, AV_LOG_DEBUG, " %"PRId64"/%"PRId64,
356  base_pic->refs[0][i]->display_order, base_pic->refs[0][i]->encode_order);
357  }
358  av_log(avctx, AV_LOG_DEBUG, ".\n");
359 
360  if (base_pic->nb_refs[1]) {
361  av_log(avctx, AV_LOG_DEBUG, "L1 refers to");
362  for (i = 0; i < base_pic->nb_refs[1]; i++) {
363  av_log(avctx, AV_LOG_DEBUG, " %"PRId64"/%"PRId64,
364  base_pic->refs[1][i]->display_order, base_pic->refs[1][i]->encode_order);
365  }
366  av_log(avctx, AV_LOG_DEBUG, ".\n");
367  }
368  }
369 
370  av_assert0(!base_pic->encode_issued);
371  for (i = 0; i < base_pic->nb_refs[0]; i++) {
372  av_assert0(base_pic->refs[0][i]);
373  av_assert0(base_pic->refs[0][i]->encode_issued);
374  }
375  for (i = 0; i < base_pic->nb_refs[1]; i++) {
376  av_assert0(base_pic->refs[1][i]);
377  av_assert0(base_pic->refs[1][i]->encode_issued);
378  }
379 
380  av_log(avctx, AV_LOG_DEBUG, "Input surface is %p.\n", pic->input_surface->texture);
381 
382  pic->recon_surface = (AVD3D12VAFrame *)base_pic->recon_image->data[0];
383  av_log(avctx, AV_LOG_DEBUG, "Recon surface is %p.\n",
384  pic->recon_surface->texture);
385 
386  pic->subresource_index = ctx->is_texture_array ? pic->recon_surface->subresource_index : 0;
387 
388  pic->output_buffer_ref = av_buffer_pool_get(ctx->output_buffer_pool);
389  if (!pic->output_buffer_ref) {
390  err = AVERROR(ENOMEM);
391  goto fail;
392  }
393  pic->output_buffer = (ID3D12Resource *)pic->output_buffer_ref->data;
394  av_log(avctx, AV_LOG_DEBUG, "Output buffer is %p.\n",
395  pic->output_buffer);
396 
397  err = d3d12va_encode_create_metadata_buffers(avctx, pic);
398  if (err < 0)
399  goto fail;
400 
401  // Process ROI side data if present and supported
404  if (sd && base_ctx->roi_allowed) {
405  err = d3d12va_encode_setup_roi(avctx, pic, sd->data, sd->size);
406  if (err < 0)
407  goto fail;
408 
409  // Enable delta QP flag in rate control only if supported
410  input_args.SequenceControlDesc.RateControl.Flags |= D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_DELTA_QP;
411  av_log(avctx, AV_LOG_DEBUG, "ROI delta QP map created with %d blocks (region size: %d pixels).\n",
412  pic->qp_map_size, ctx->qp_map_region_size);
413  }
414 
415  if (ctx->codec->init_picture_params) {
416  err = ctx->codec->init_picture_params(avctx, base_pic);
417  if (err < 0) {
418  av_log(avctx, AV_LOG_ERROR, "Failed to initialise picture "
419  "parameters: %d.\n", err);
420  goto fail;
421  }
422  }
423 
424  if (base_pic->type == FF_HW_PICTURE_TYPE_IDR) {
425  if (ctx->codec->write_sequence_header) {
426  bit_len = 8 * sizeof(data);
427  err = ctx->codec->write_sequence_header(avctx, data, &bit_len);
428  if (err < 0) {
429  av_log(avctx, AV_LOG_ERROR, "Failed to write per-sequence "
430  "header: %d.\n", err);
431  goto fail;
432  }
433  pic->header_size = (int)bit_len / 8;
434  pic->aligned_header_size = pic->header_size % ctx->req.CompressedBitstreamBufferAccessAlignment ?
435  FFALIGN(pic->header_size, ctx->req.CompressedBitstreamBufferAccessAlignment) :
436  pic->header_size;
437 
438  hr = ID3D12Resource_Map(pic->output_buffer, 0, NULL, (void **)&ptr);
439  if (FAILED(hr)) {
440  err = AVERROR_UNKNOWN;
441  goto fail;
442  }
443 
444  memcpy(ptr, data, pic->aligned_header_size);
445  ID3D12Resource_Unmap(pic->output_buffer, 0, NULL);
446  }
447  }
448 
449  d3d12_refs.NumTexture2Ds = base_pic->nb_refs[0] + base_pic->nb_refs[1];
450  if (d3d12_refs.NumTexture2Ds) {
451  d3d12_refs.ppTexture2Ds = av_calloc(d3d12_refs.NumTexture2Ds,
452  sizeof(*d3d12_refs.ppTexture2Ds));
453  if (!d3d12_refs.ppTexture2Ds) {
454  err = AVERROR(ENOMEM);
455  goto fail;
456  }
457 
458  if (ctx->is_texture_array) {
459  d3d12_refs.pSubresources = av_calloc(d3d12_refs.NumTexture2Ds,
460  sizeof(*d3d12_refs.pSubresources));
461  if (!d3d12_refs.pSubresources) {
462  err = AVERROR(ENOMEM);
463  goto fail;
464  }
465  }
466 
467  i = 0;
468  for (j = 0; j < base_pic->nb_refs[0]; j++) {
469  d3d12_refs.ppTexture2Ds[i] = ((D3D12VAEncodePicture *)base_pic->refs[0][j]->priv)->recon_surface->texture;
470  if (ctx->is_texture_array)
471  d3d12_refs.pSubresources[i] = ((D3D12VAEncodePicture *)base_pic->refs[0][j]->priv)->subresource_index;
472  i++;
473  }
474  for (j = 0; j < base_pic->nb_refs[1]; j++) {
475  d3d12_refs.ppTexture2Ds[i] = ((D3D12VAEncodePicture *)base_pic->refs[1][j]->priv)->recon_surface->texture;
476  if (ctx->is_texture_array)
477  d3d12_refs.pSubresources[i] = ((D3D12VAEncodePicture *)base_pic->refs[1][j]->priv)->subresource_index;
478  i++;
479  }
480  }
481 
482  input_args.PictureControlDesc.IntraRefreshFrameIndex = ctx->intra_refresh_frame_index;
483  if (base_pic->is_reference)
484  input_args.PictureControlDesc.Flags |= D3D12_VIDEO_ENCODER_PICTURE_CONTROL_FLAG_USED_AS_REFERENCE_PICTURE;
485 
486  input_args.PictureControlDesc.PictureControlCodecData = pic->pic_ctl;
487  input_args.PictureControlDesc.ReferenceFrames = d3d12_refs;
488  input_args.CurrentFrameBitstreamMetadataSize = pic->aligned_header_size;
489 
490  output_args.Bitstream.pBuffer = pic->output_buffer;
491  output_args.Bitstream.FrameStartOffset = pic->aligned_header_size;
492  output_args.ReconstructedPicture.pReconstructedPicture = pic->recon_surface->texture;
493  output_args.ReconstructedPicture.ReconstructedPictureSubresource = ctx->is_texture_array ? pic->subresource_index : 0;
494  output_args.EncoderOutputMetadata.pBuffer = pic->encoded_metadata;
495  output_args.EncoderOutputMetadata.Offset = 0;
496 
497  input_metadata.HWLayoutMetadata.pBuffer = pic->encoded_metadata;
498  input_metadata.HWLayoutMetadata.Offset = 0;
499 
500  output_metadata.ResolvedLayoutMetadata.pBuffer = pic->resolved_metadata;
501  output_metadata.ResolvedLayoutMetadata.Offset = 0;
502 
503  err = d3d12va_get_valid_command_allocator(avctx, &command_allocator);
504  if (err < 0)
505  goto fail;
506 
507  hr = ID3D12CommandAllocator_Reset(command_allocator);
508  if (FAILED(hr)) {
509  err = AVERROR_UNKNOWN;
510  goto fail;
511  }
512 
513  hr = ID3D12VideoEncodeCommandList2_Reset(cmd_list, command_allocator);
514  if (FAILED(hr)) {
515  err = AVERROR_UNKNOWN;
516  goto fail;
517  }
518 
519 #define TRANSITION_BARRIER(res, subres, before, after) \
520  (D3D12_RESOURCE_BARRIER) { \
521  .Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION, \
522  .Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE, \
523  .Transition = { \
524  .pResource = res, \
525  .Subresource = subres, \
526  .StateBefore = before, \
527  .StateAfter = after, \
528  }, \
529  }
530 
531  barriers[0] = TRANSITION_BARRIER(pic->input_surface->texture,
532  D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES,
533  D3D12_RESOURCE_STATE_COMMON,
534  D3D12_RESOURCE_STATE_VIDEO_ENCODE_READ);
535  barriers[1] = TRANSITION_BARRIER(pic->output_buffer,
536  D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES,
537  D3D12_RESOURCE_STATE_COMMON,
538  D3D12_RESOURCE_STATE_VIDEO_ENCODE_WRITE);
539  barriers[2] = TRANSITION_BARRIER(pic->encoded_metadata,
540  D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES,
541  D3D12_RESOURCE_STATE_COMMON,
542  D3D12_RESOURCE_STATE_VIDEO_ENCODE_WRITE);
543  barriers[3] = TRANSITION_BARRIER(pic->resolved_metadata,
544  D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES,
545  D3D12_RESOURCE_STATE_COMMON,
546  D3D12_RESOURCE_STATE_VIDEO_ENCODE_WRITE);
547 
548  ID3D12VideoEncodeCommandList2_ResourceBarrier(cmd_list, 4, barriers);
549 
550  if (ctx->is_texture_array)
551  barriers_ref = av_calloc(base_ctx->recon_frames->initial_pool_size * ctx->plane_count,
552  sizeof(D3D12_RESOURCE_BARRIER));
553  else
554  barriers_ref = av_calloc(MAX_DPB_SIZE, sizeof(D3D12_RESOURCE_BARRIER));
555 
556  if (ctx->is_texture_array) {
557  D3D12_RESOURCE_DESC references_tex_array_desc = { 0 };
558  pic->recon_surface->texture->lpVtbl->GetDesc(pic->recon_surface->texture, &references_tex_array_desc);
559 
560  for (uint32_t reference_subresource = 0; reference_subresource < references_tex_array_desc.DepthOrArraySize;
561  reference_subresource++) {
562 
563  uint32_t array_size = references_tex_array_desc.DepthOrArraySize;
564  uint32_t mip_slice = reference_subresource % references_tex_array_desc.MipLevels;
565  uint32_t array_slice = (reference_subresource / references_tex_array_desc.MipLevels) % array_size;
566 
567  for (uint32_t plane_slice = 0; plane_slice < ctx->plane_count; plane_slice++) {
568  uint32_t outputSubresource = mip_slice + array_slice * references_tex_array_desc.MipLevels +
569  plane_slice * references_tex_array_desc.MipLevels * array_size;
570  if (reference_subresource == pic->subresource_index) {
571  barriers_ref[barriers_ref_index++] = TRANSITION_BARRIER(pic->recon_surface->texture, outputSubresource,
572  D3D12_RESOURCE_STATE_COMMON,
573  D3D12_RESOURCE_STATE_VIDEO_ENCODE_WRITE);
574  } else {
575  barriers_ref[barriers_ref_index++] = TRANSITION_BARRIER(pic->recon_surface->texture, outputSubresource,
576  D3D12_RESOURCE_STATE_COMMON,
577  D3D12_RESOURCE_STATE_VIDEO_ENCODE_READ);
578  }
579  }
580  }
581  } else {
582  barriers_ref[barriers_ref_index++] = TRANSITION_BARRIER(pic->recon_surface->texture,
583  D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES,
584  D3D12_RESOURCE_STATE_COMMON,
585  D3D12_RESOURCE_STATE_VIDEO_ENCODE_WRITE);
586 
587  if (d3d12_refs.NumTexture2Ds) {
588  for (i = 0; i < d3d12_refs.NumTexture2Ds; i++)
589  barriers_ref[barriers_ref_index++] = TRANSITION_BARRIER(d3d12_refs.ppTexture2Ds[i],
590  D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES,
591  D3D12_RESOURCE_STATE_COMMON,
592  D3D12_RESOURCE_STATE_VIDEO_ENCODE_READ);
593  }
594  }
595  ID3D12VideoEncodeCommandList2_ResourceBarrier(cmd_list, barriers_ref_index, barriers_ref);
596 
597  ID3D12VideoEncodeCommandList2_EncodeFrame(cmd_list, ctx->encoder, ctx->encoder_heap,
598  &input_args, &output_args);
599 
600  barriers[3] = TRANSITION_BARRIER(pic->encoded_metadata,
601  D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES,
602  D3D12_RESOURCE_STATE_VIDEO_ENCODE_WRITE,
603  D3D12_RESOURCE_STATE_VIDEO_ENCODE_READ);
604 
605  ID3D12VideoEncodeCommandList2_ResourceBarrier(cmd_list, 1, &barriers[3]);
606 
607  ID3D12VideoEncodeCommandList2_ResolveEncoderOutputMetadata(cmd_list, &input_metadata, &output_metadata);
608 
609  if (barriers_ref_index > 0) {
610  for (i = 0; i < barriers_ref_index; i++)
611  FFSWAP(D3D12_RESOURCE_STATES, barriers_ref[i].Transition.StateBefore, barriers_ref[i].Transition.StateAfter);
612 
613  ID3D12VideoEncodeCommandList2_ResourceBarrier(cmd_list, barriers_ref_index,
614  barriers_ref);
615  }
616 
617  barriers[0] = TRANSITION_BARRIER(pic->input_surface->texture,
618  D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES,
619  D3D12_RESOURCE_STATE_VIDEO_ENCODE_READ,
620  D3D12_RESOURCE_STATE_COMMON);
621  barriers[1] = TRANSITION_BARRIER(pic->output_buffer,
622  D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES,
623  D3D12_RESOURCE_STATE_VIDEO_ENCODE_WRITE,
624  D3D12_RESOURCE_STATE_COMMON);
625  barriers[2] = TRANSITION_BARRIER(pic->encoded_metadata,
626  D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES,
627  D3D12_RESOURCE_STATE_VIDEO_ENCODE_READ,
628  D3D12_RESOURCE_STATE_COMMON);
629  barriers[3] = TRANSITION_BARRIER(pic->resolved_metadata,
630  D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES,
631  D3D12_RESOURCE_STATE_VIDEO_ENCODE_WRITE,
632  D3D12_RESOURCE_STATE_COMMON);
633 
634  ID3D12VideoEncodeCommandList2_ResourceBarrier(cmd_list, 4, barriers);
635 
636  hr = ID3D12VideoEncodeCommandList2_Close(cmd_list);
637  if (FAILED(hr)) {
638  err = AVERROR_UNKNOWN;
639  goto fail;
640  }
641 
642  hr = ID3D12CommandQueue_Wait(ctx->command_queue, pic->input_surface->sync_ctx.fence,
644  if (FAILED(hr)) {
645  err = AVERROR_UNKNOWN;
646  goto fail;
647  }
648 
649  ID3D12CommandQueue_ExecuteCommandLists(ctx->command_queue, 1, (ID3D12CommandList **)&ctx->command_list);
650 
651  hr = ID3D12CommandQueue_Signal(ctx->command_queue, pic->input_surface->sync_ctx.fence,
653  if (FAILED(hr)) {
654  err = AVERROR_UNKNOWN;
655  goto fail;
656  }
657 
658  hr = ID3D12CommandQueue_Signal(ctx->command_queue, ctx->sync_ctx.fence, ++ctx->sync_ctx.fence_value);
659  if (FAILED(hr)) {
660  err = AVERROR_UNKNOWN;
661  goto fail;
662  }
663 
664  err = d3d12va_discard_command_allocator(avctx, command_allocator, ctx->sync_ctx.fence_value);
665  if (err < 0)
666  goto fail;
667 
668  pic->fence_value = ctx->sync_ctx.fence_value;
669 
670  // Update intra refresh frame index for next frame
671  if (ctx->intra_refresh.Mode != D3D12_VIDEO_ENCODER_INTRA_REFRESH_MODE_NONE) {
672  ctx->intra_refresh_frame_index =
673  (ctx->intra_refresh_frame_index + 1) % ctx->intra_refresh.IntraRefreshDuration;
674  }
675 
676  if (d3d12_refs.ppTexture2Ds)
677  av_freep(&d3d12_refs.ppTexture2Ds);
678 
679  if (ctx->is_texture_array && d3d12_refs.pSubresources)
680  av_freep(&d3d12_refs.pSubresources);
681 
682  if (barriers_ref)
683  av_freep(&barriers_ref);
684 
685  return 0;
686 
687 fail:
688  if (command_allocator)
689  d3d12va_discard_command_allocator(avctx, command_allocator, ctx->sync_ctx.fence_value);
690 
691  if (d3d12_refs.ppTexture2Ds)
692  av_freep(&d3d12_refs.ppTexture2Ds);
693 
694  if (ctx->is_texture_array && d3d12_refs.pSubresources)
695  av_freep(&d3d12_refs.pSubresources);
696 
697  if (barriers_ref)
698  av_freep(&barriers_ref);
699 
700  if (ctx->codec->free_picture_params)
701  ctx->codec->free_picture_params(pic);
702 
704  pic->output_buffer = NULL;
707  return err;
708 }
709 
711  FFHWBaseEncodePicture *base_pic)
712 {
713  D3D12VAEncodePicture *pic = base_pic->priv;
714 
715  d3d12va_encode_wait(avctx, base_pic);
716 
717  if (pic->output_buffer_ref) {
718  av_log(avctx, AV_LOG_DEBUG, "Discard output for pic "
719  "%"PRId64"/%"PRId64".\n",
720  base_pic->display_order, base_pic->encode_order);
721 
723  pic->output_buffer = NULL;
724  }
725 
728 
729  return 0;
730 }
731 
733 {
735 
736  switch (ctx->rc.Mode)
737  {
738  case D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE_CQP:
739  av_freep(&ctx->rc.ConfigParams.pConfiguration_CQP);
740  break;
741  case D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE_CBR:
742  av_freep(&ctx->rc.ConfigParams.pConfiguration_CBR);
743  break;
744  case D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE_VBR:
745  av_freep(&ctx->rc.ConfigParams.pConfiguration_VBR);
746  break;
747  case D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE_QVBR:
748  av_freep(&ctx->rc.ConfigParams.pConfiguration_QVBR);
749  break;
750  default:
751  break;
752  }
753 
754  return 0;
755 }
756 
758 {
760  D3D12VAEncodePicture *priv = pic->priv;
761  AVFrame *frame = pic->input_image;
762 
763  if (ctx->codec->picture_priv_data_size > 0) {
764  pic->codec_priv = av_mallocz(ctx->codec->picture_priv_data_size);
765  if (!pic->codec_priv)
766  return AVERROR(ENOMEM);
767  }
768 
769  priv->input_surface = (AVD3D12VAFrame *)frame->data[0];
770 
771  return 0;
772 }
773 
775 {
777  D3D12VAEncodePicture *priv = pic->priv;
778 
779  if (pic->encode_issued)
780  d3d12va_encode_discard(avctx, pic);
781 
782  if (ctx->codec->free_picture_params)
783  ctx->codec->free_picture_params(priv);
784 
785  // Free ROI QP map if allocated
786  av_freep(&priv->qp_map);
787 
788  return 0;
789 }
790 
792  D3D12VAEncodePicture *pic, size_t *size)
793 {
794  D3D12_VIDEO_ENCODER_OUTPUT_METADATA *meta = NULL;
795  uint8_t *data;
796  HRESULT hr;
797  int err;
798 
799  hr = ID3D12Resource_Map(pic->resolved_metadata, 0, NULL, (void **)&data);
800  if (FAILED(hr)) {
801  err = AVERROR_UNKNOWN;
802  return err;
803  }
804 
805  meta = (D3D12_VIDEO_ENCODER_OUTPUT_METADATA *)data;
806 
807  if (meta->EncodeErrorFlags != D3D12_VIDEO_ENCODER_ENCODE_ERROR_FLAG_NO_ERROR) {
808  av_log(avctx, AV_LOG_ERROR, "Encode failed %"PRIu64"\n", meta->EncodeErrorFlags);
809  err = AVERROR(EINVAL);
810  return err;
811  }
812 
813  if (meta->EncodedBitstreamWrittenBytesCount == 0) {
814  av_log(avctx, AV_LOG_ERROR, "No bytes were written to encoded bitstream\n");
815  err = AVERROR(EINVAL);
816  return err;
817  }
818 
819  *size = meta->EncodedBitstreamWrittenBytesCount;
820 
821  ID3D12Resource_Unmap(pic->resolved_metadata, 0, NULL);
822 
823  return 0;
824 }
825 
828 {
829  int err;
830  uint8_t *ptr, *mapped_data;
831  size_t total_size = 0;
832  HRESULT hr;
833 
834  err = d3d12va_encode_get_buffer_size(avctx, pic, &total_size);
835  if (err < 0)
836  goto end;
837 
838  total_size += pic->header_size;
839  av_log(avctx, AV_LOG_DEBUG, "Output buffer size %zu\n", total_size);
840 
841  hr = ID3D12Resource_Map(pic->output_buffer, 0, NULL, (void **)&mapped_data);
842  if (FAILED(hr)) {
843  err = AVERROR_UNKNOWN;
844  goto end;
845  }
846 
847  err = ff_get_encode_buffer(avctx, pkt, total_size, 0);
848  if (err < 0)
849  goto end;
850  ptr = pkt->data;
851 
852  memcpy(ptr, mapped_data, pic->header_size);
853 
854  ptr += pic->header_size;
855  mapped_data += pic->aligned_header_size;
856  total_size -= pic->header_size;
857 
858  memcpy(ptr, mapped_data, total_size);
859 
860  ID3D12Resource_Unmap(pic->output_buffer, 0, NULL);
861 
862 end:
864  pic->output_buffer = NULL;
865  return err;
866 }
867 
869  FFHWBaseEncodePicture *base_pic, AVPacket *pkt)
870 {
872  FFHWBaseEncodeContext *base_ctx = avctx->priv_data;
873  D3D12VAEncodePicture *pic = base_pic->priv;
874  AVPacket *pkt_ptr = pkt;
875  int err = 0;
876 
877  err = d3d12va_encode_wait(avctx, base_pic);
878  if (err < 0)
879  return err;
880 
881  if (ctx->codec->get_coded_data)
882  err = ctx->codec->get_coded_data(avctx, pic, pkt);
883  else
884  err = d3d12va_encode_get_coded_data(avctx, pic, pkt);
885 
886  if (err < 0)
887  return err;
888 
889  av_log(avctx, AV_LOG_DEBUG, "Output read for pic %"PRId64"/%"PRId64".\n",
890  base_pic->display_order, base_pic->encode_order);
891 
893  pkt_ptr, 0);
894 
895  return 0;
896 }
897 
899 {
900  FFHWBaseEncodeContext *base_ctx = avctx->priv_data;
903  const AVPixFmtDescriptor *desc;
904  int i, depth;
905 
907  if (!desc) {
908  av_log(avctx, AV_LOG_ERROR, "Invalid input pixfmt (%d).\n",
909  base_ctx->input_frames->sw_format);
910  return AVERROR(EINVAL);
911  }
912 
913  depth = desc->comp[0].depth;
914  for (i = 1; i < desc->nb_components; i++) {
915  if (desc->comp[i].depth != depth) {
916  av_log(avctx, AV_LOG_ERROR, "Invalid input pixfmt (%s).\n",
917  desc->name);
918  return AVERROR(EINVAL);
919  }
920  }
921  av_log(avctx, AV_LOG_VERBOSE, "Input surface format is %s.\n",
922  desc->name);
923 
924  av_assert0(ctx->codec->profiles);
925  for (i = 0; (ctx->codec->profiles[i].av_profile !=
926  AV_PROFILE_UNKNOWN); i++) {
927  profile = &ctx->codec->profiles[i];
928  if (depth != profile->depth ||
929  desc->nb_components != profile->nb_components)
930  continue;
931  if (desc->nb_components > 1 &&
932  (desc->log2_chroma_w != profile->log2_chroma_w ||
933  desc->log2_chroma_h != profile->log2_chroma_h))
934  continue;
935  if (avctx->profile != profile->av_profile &&
936  avctx->profile != AV_PROFILE_UNKNOWN)
937  continue;
938 
939  ctx->profile = profile;
940  break;
941  }
942  if (!ctx->profile) {
943  av_log(avctx, AV_LOG_ERROR, "No usable encoding profile found.\n");
944  return AVERROR(ENOSYS);
945  }
946 
947  avctx->profile = profile->av_profile;
948  return 0;
949 }
950 
952  // Bitrate Quality
953  // | Maxrate | HRD/VBV
954  { 0 }, // | | | |
955  { RC_MODE_CQP, "CQP", 0, 0, 1, 0, D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE_CQP },
956  { RC_MODE_CBR, "CBR", 1, 0, 0, 1, D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE_CBR },
957  { RC_MODE_VBR, "VBR", 1, 1, 0, 1, D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE_VBR },
958  { RC_MODE_QVBR, "QVBR", 1, 1, 1, 1, D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE_QVBR },
959 };
960 
962 {
963  HRESULT hr;
965  D3D12_FEATURE_DATA_VIDEO_ENCODER_RATE_CONTROL_MODE d3d12_rc_mode = {
966  .Codec = ctx->codec->d3d12_codec,
967  };
968 
969  if (!rc_mode->d3d12_mode)
970  return 0;
971 
972  d3d12_rc_mode.IsSupported = 0;
973  d3d12_rc_mode.RateControlMode = rc_mode->d3d12_mode;
974 
975  hr = ID3D12VideoDevice3_CheckFeatureSupport(ctx->video_device3,
976  D3D12_FEATURE_VIDEO_ENCODER_RATE_CONTROL_MODE,
977  &d3d12_rc_mode, sizeof(d3d12_rc_mode));
978  if (FAILED(hr)) {
979  av_log(avctx, AV_LOG_ERROR, "Failed to check rate control support.\n");
980  return 0;
981  }
982 
983  return d3d12_rc_mode.IsSupported;
984 }
985 
987 {
989  int64_t rc_target_bitrate;
990  int64_t rc_peak_bitrate;
991  int rc_quality;
992  int64_t hrd_buffer_size;
993  int64_t hrd_initial_buffer_fullness;
994  int fr_num, fr_den;
996 
997 #define SET_QP_RANGE(ctl) do { \
998  if (avctx->qmin > 0 || avctx->qmax > 0) { \
999  ctl->MinQP = avctx->qmin; \
1000  ctl->MaxQP = avctx->qmax; \
1001  ctx->rc.Flags |= D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_QP_RANGE; \
1002  } \
1003  } while(0)
1004 
1005 #define SET_MAX_FRAME_SIZE(ctl) do { \
1006  if (ctx->max_frame_size > 0) { \
1007  ctl->MaxFrameBitSize = ctx->max_frame_size * 8; \
1008  ctx->rc.Flags |= D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_MAX_FRAME_SIZE; \
1009  } \
1010  } while(0)
1011 
1012  // Rate control mode selection:
1013  // * If the user has set a mode explicitly with the rc_mode option,
1014  // use it and fail if it is not available.
1015  // * If an explicit QP option has been set, use CQP.
1016  // * If the codec is CQ-only, use CQP.
1017  // * If the QSCALE avcodec option is set, use CQP.
1018  // * If bitrate and quality are both set, try QVBR.
1019  // * If quality is set, try CQP.
1020  // * If bitrate and maxrate are set and have the same value, try CBR.
1021  // * If a bitrate is set, try VBR, then CBR.
1022  // * If no bitrate is set, try CQP.
1023 
1024 #define TRY_RC_MODE(mode, fail) do { \
1025  rc_mode = &d3d12va_encode_rc_modes[mode]; \
1026  if (!(rc_mode->d3d12_mode && check_rate_control_support(avctx, rc_mode))) { \
1027  if (fail) { \
1028  av_log(avctx, AV_LOG_ERROR, "Driver does not support %s " \
1029  "RC mode.\n", rc_mode->name); \
1030  return AVERROR(EINVAL); \
1031  } \
1032  av_log(avctx, AV_LOG_DEBUG, "Driver does not support %s " \
1033  "RC mode.\n", rc_mode->name); \
1034  rc_mode = NULL; \
1035  } else { \
1036  goto rc_mode_found; \
1037  } \
1038  } while (0)
1039 
1040  if (ctx->explicit_rc_mode)
1041  TRY_RC_MODE(ctx->explicit_rc_mode, 1);
1042 
1043  if (ctx->explicit_qp)
1045 
1048 
1049  if (avctx->flags & AV_CODEC_FLAG_QSCALE)
1051 
1052  if (avctx->bit_rate > 0 && avctx->global_quality > 0)
1054 
1055  if (avctx->global_quality > 0) {
1057  }
1058 
1059  if (avctx->bit_rate > 0 && avctx->rc_max_rate == avctx->bit_rate)
1061 
1062  if (avctx->bit_rate > 0) {
1065  } else {
1067  }
1068 
1069  av_log(avctx, AV_LOG_ERROR, "Driver does not support any "
1070  "RC mode compatible with selected options.\n");
1071  return AVERROR(EINVAL);
1072 
1073 rc_mode_found:
1074  if (rc_mode->bitrate) {
1075  if (avctx->bit_rate <= 0) {
1076  av_log(avctx, AV_LOG_ERROR, "Bitrate must be set for %s "
1077  "RC mode.\n", rc_mode->name);
1078  return AVERROR(EINVAL);
1079  }
1080 
1081  if (rc_mode->maxrate) {
1082  if (avctx->rc_max_rate > 0) {
1083  if (avctx->rc_max_rate < avctx->bit_rate) {
1084  av_log(avctx, AV_LOG_ERROR, "Invalid bitrate settings: "
1085  "bitrate (%"PRId64") must not be greater than "
1086  "maxrate (%"PRId64").\n", avctx->bit_rate,
1087  avctx->rc_max_rate);
1088  return AVERROR(EINVAL);
1089  }
1090  rc_target_bitrate = avctx->bit_rate;
1091  rc_peak_bitrate = avctx->rc_max_rate;
1092  } else {
1093  // We only have a target bitrate, but this mode requires
1094  // that a maximum rate be supplied as well. Since the
1095  // user does not want this to be a constraint, arbitrarily
1096  // pick a maximum rate of double the target rate.
1097  rc_target_bitrate = avctx->bit_rate;
1098  rc_peak_bitrate = 2 * avctx->bit_rate;
1099  }
1100  } else {
1101  if (avctx->rc_max_rate > avctx->bit_rate) {
1102  av_log(avctx, AV_LOG_WARNING, "Max bitrate is ignored "
1103  "in %s RC mode.\n", rc_mode->name);
1104  }
1105  rc_target_bitrate = avctx->bit_rate;
1106  rc_peak_bitrate = 0;
1107  }
1108  } else {
1109  rc_target_bitrate = 0;
1110  rc_peak_bitrate = 0;
1111  }
1112 
1113  if (rc_mode->quality) {
1114  if (ctx->explicit_qp) {
1115  rc_quality = ctx->explicit_qp;
1116  } else if (avctx->global_quality > 0) {
1117  if (avctx->flags & AV_CODEC_FLAG_QSCALE)
1118  rc_quality = avctx->global_quality / FF_QP2LAMBDA;
1119  else
1120  rc_quality = avctx->global_quality;
1121  } else {
1122  rc_quality = ctx->codec->default_quality;
1123  av_log(avctx, AV_LOG_WARNING, "No quality level set; "
1124  "using default (%d).\n", rc_quality);
1125  }
1126  } else {
1127  rc_quality = 0;
1128  }
1129 
1130  if (rc_mode->hrd) {
1131  if (avctx->rc_buffer_size)
1132  hrd_buffer_size = avctx->rc_buffer_size;
1133  else if (avctx->rc_max_rate > 0)
1134  hrd_buffer_size = avctx->rc_max_rate;
1135  else
1136  hrd_buffer_size = avctx->bit_rate;
1137  if (avctx->rc_initial_buffer_occupancy) {
1138  if (avctx->rc_initial_buffer_occupancy > hrd_buffer_size) {
1139  av_log(avctx, AV_LOG_ERROR, "Invalid RC buffer settings: "
1140  "must have initial buffer size (%d) <= "
1141  "buffer size (%"PRId64").\n",
1142  avctx->rc_initial_buffer_occupancy, hrd_buffer_size);
1143  return AVERROR(EINVAL);
1144  }
1145  hrd_initial_buffer_fullness = avctx->rc_initial_buffer_occupancy;
1146  } else {
1147  hrd_initial_buffer_fullness = hrd_buffer_size * 3 / 4;
1148  }
1149  } else {
1150  if (avctx->rc_buffer_size || avctx->rc_initial_buffer_occupancy) {
1151  av_log(avctx, AV_LOG_WARNING, "Buffering settings are ignored "
1152  "in %s RC mode.\n", rc_mode->name);
1153  }
1154 
1155  hrd_buffer_size = 0;
1156  hrd_initial_buffer_fullness = 0;
1157  }
1158 
1159  if (rc_target_bitrate > UINT32_MAX ||
1160  hrd_buffer_size > UINT32_MAX ||
1161  hrd_initial_buffer_fullness > UINT32_MAX) {
1162  av_log(avctx, AV_LOG_ERROR, "RC parameters of 2^32 or "
1163  "greater are not supported by D3D12.\n");
1164  return AVERROR(EINVAL);
1165  }
1166 
1167  ctx->rc_quality = rc_quality;
1168 
1169  av_log(avctx, AV_LOG_VERBOSE, "RC mode: %s.\n", rc_mode->name);
1170 
1171  if (rc_mode->quality)
1172  av_log(avctx, AV_LOG_VERBOSE, "RC quality: %d.\n", rc_quality);
1173 
1174  if (rc_mode->hrd) {
1175  av_log(avctx, AV_LOG_VERBOSE, "RC buffer: %"PRId64" bits, "
1176  "initial fullness %"PRId64" bits.\n",
1177  hrd_buffer_size, hrd_initial_buffer_fullness);
1178  }
1179 
1180  if (avctx->framerate.num > 0 && avctx->framerate.den > 0)
1181  av_reduce(&fr_num, &fr_den,
1182  avctx->framerate.num, avctx->framerate.den, 65535);
1183  else
1184  av_reduce(&fr_num, &fr_den,
1185  avctx->time_base.den, avctx->time_base.num, 65535);
1186 
1187  av_log(avctx, AV_LOG_VERBOSE, "RC framerate: %d/%d (%.2f fps).\n",
1188  fr_num, fr_den, (double)fr_num / fr_den);
1189 
1190  ctx->rc.Flags = D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_NONE;
1191  ctx->rc.TargetFrameRate.Numerator = fr_num;
1192  ctx->rc.TargetFrameRate.Denominator = fr_den;
1193  ctx->rc.Mode = rc_mode->d3d12_mode;
1194 
1195  switch (rc_mode->mode) {
1196  case RC_MODE_CQP:
1197  // cqp ConfigParams will be updated in ctx->codec->configure.
1198  break;
1199  case RC_MODE_CBR: {
1200  D3D12_VIDEO_ENCODER_RATE_CONTROL_CBR *cbr_ctl;
1201 
1202  ctx->rc.ConfigParams.DataSize = sizeof(D3D12_VIDEO_ENCODER_RATE_CONTROL_CBR);
1203  cbr_ctl = av_mallocz(ctx->rc.ConfigParams.DataSize);
1204  if (!cbr_ctl)
1205  return AVERROR(ENOMEM);
1206 
1207  cbr_ctl->TargetBitRate = rc_target_bitrate;
1208  cbr_ctl->VBVCapacity = hrd_buffer_size;
1209  cbr_ctl->InitialVBVFullness = hrd_initial_buffer_fullness;
1210  ctx->rc.Flags |= D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_VBV_SIZES;
1211 
1212  SET_QP_RANGE(cbr_ctl);
1213  SET_MAX_FRAME_SIZE(cbr_ctl);
1214 
1215  ctx->rc.ConfigParams.pConfiguration_CBR = cbr_ctl;
1216  break;
1217  }
1218  case RC_MODE_VBR: {
1219  D3D12_VIDEO_ENCODER_RATE_CONTROL_VBR *vbr_ctl;
1220 
1221  ctx->rc.ConfigParams.DataSize = sizeof(D3D12_VIDEO_ENCODER_RATE_CONTROL_VBR);
1222  vbr_ctl = av_mallocz(ctx->rc.ConfigParams.DataSize);
1223  if (!vbr_ctl)
1224  return AVERROR(ENOMEM);
1225 
1226  vbr_ctl->TargetAvgBitRate = rc_target_bitrate;
1227  vbr_ctl->PeakBitRate = rc_peak_bitrate;
1228  vbr_ctl->VBVCapacity = hrd_buffer_size;
1229  vbr_ctl->InitialVBVFullness = hrd_initial_buffer_fullness;
1230  ctx->rc.Flags |= D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_VBV_SIZES;
1231 
1232  SET_QP_RANGE(vbr_ctl);
1233  SET_MAX_FRAME_SIZE(vbr_ctl);
1234 
1235  ctx->rc.ConfigParams.pConfiguration_VBR = vbr_ctl;
1236  break;
1237  }
1238  case RC_MODE_QVBR: {
1239  D3D12_VIDEO_ENCODER_RATE_CONTROL_QVBR *qvbr_ctl;
1240 
1241  ctx->rc.ConfigParams.DataSize = sizeof(D3D12_VIDEO_ENCODER_RATE_CONTROL_QVBR);
1242  qvbr_ctl = av_mallocz(ctx->rc.ConfigParams.DataSize);
1243  if (!qvbr_ctl)
1244  return AVERROR(ENOMEM);
1245 
1246  qvbr_ctl->TargetAvgBitRate = rc_target_bitrate;
1247  qvbr_ctl->PeakBitRate = rc_peak_bitrate;
1248  qvbr_ctl->ConstantQualityTarget = rc_quality;
1249 
1250  SET_QP_RANGE(qvbr_ctl);
1251  SET_MAX_FRAME_SIZE(qvbr_ctl);
1252 
1253  ctx->rc.ConfigParams.pConfiguration_QVBR = qvbr_ctl;
1254  break;
1255  }
1256  default:
1257  break;
1258  }
1259  return 0;
1260 }
1261 
1263 {
1264  FFHWBaseEncodeContext *base_ctx = avctx->priv_data;
1266  AVD3D12VAFramesContext *hwctx = base_ctx->input_frames->hwctx;
1267  HRESULT hr;
1268 
1269  if (ctx->me_precision == D3D12_VIDEO_ENCODER_MOTION_ESTIMATION_PRECISION_MODE_MAXIMUM)
1270  return 0;
1271 
1272  D3D12_VIDEO_ENCODER_PROFILE_DESC profile = { 0 };
1273  D3D12_VIDEO_ENCODER_PROFILE_H264 h264_profile = D3D12_VIDEO_ENCODER_PROFILE_H264_MAIN;
1274  D3D12_VIDEO_ENCODER_PROFILE_HEVC hevc_profile = D3D12_VIDEO_ENCODER_PROFILE_HEVC_MAIN;
1275 #if CONFIG_AV1_D3D12VA_ENCODER
1276  D3D12_VIDEO_ENCODER_AV1_PROFILE av1_profile = D3D12_VIDEO_ENCODER_AV1_PROFILE_MAIN;
1277 #endif
1278 
1279  D3D12_VIDEO_ENCODER_LEVEL_SETTING level = { 0 };
1280  D3D12_VIDEO_ENCODER_LEVELS_H264 h264_level = { 0 };
1281  D3D12_VIDEO_ENCODER_LEVEL_TIER_CONSTRAINTS_HEVC hevc_level = { 0 };
1282 #if CONFIG_AV1_D3D12VA_ENCODER
1283  D3D12_VIDEO_ENCODER_AV1_LEVEL_TIER_CONSTRAINTS av1_level = { 0 };
1284 #endif
1285 
1286  switch (ctx->codec->d3d12_codec) {
1287  case D3D12_VIDEO_ENCODER_CODEC_H264:
1288  profile.DataSize = sizeof(D3D12_VIDEO_ENCODER_PROFILE_H264);
1289  profile.pH264Profile = &h264_profile;
1290  level.DataSize = sizeof(D3D12_VIDEO_ENCODER_LEVELS_H264);
1291  level.pH264LevelSetting = &h264_level;
1292  break;
1293  case D3D12_VIDEO_ENCODER_CODEC_HEVC:
1294  profile.DataSize = sizeof(D3D12_VIDEO_ENCODER_PROFILE_HEVC);
1295  profile.pHEVCProfile = &hevc_profile;
1296  level.DataSize = sizeof(D3D12_VIDEO_ENCODER_LEVEL_TIER_CONSTRAINTS_HEVC);
1297  level.pHEVCLevelSetting = &hevc_level;
1298  break;
1299 #if CONFIG_AV1_D3D12VA_ENCODER
1300  case D3D12_VIDEO_ENCODER_CODEC_AV1:
1301  profile.DataSize = sizeof(D3D12_VIDEO_ENCODER_AV1_PROFILE);
1302  profile.pAV1Profile = &av1_profile;
1303  level.DataSize = sizeof(D3D12_VIDEO_ENCODER_AV1_LEVEL_TIER_CONSTRAINTS);
1304  level.pAV1LevelSetting = &av1_level;
1305  break;
1306 #endif
1307  default:
1308  av_assert0(0);
1309  }
1310 
1311  D3D12_FEATURE_DATA_VIDEO_ENCODER_SUPPORT support = {
1312  .NodeIndex = 0,
1313  .Codec = ctx->codec->d3d12_codec,
1314  .InputFormat = hwctx->format,
1315  .RateControl = ctx->rc,
1316  .IntraRefresh = D3D12_VIDEO_ENCODER_INTRA_REFRESH_MODE_NONE,
1317  .SubregionFrameEncoding = D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_FULL_FRAME,
1318  .ResolutionsListCount = 1,
1319  .pResolutionList = &ctx->resolution,
1320  .CodecGopSequence = ctx->gop,
1321  .MaxReferenceFramesInDPB = MAX_DPB_SIZE - 1,
1322  .CodecConfiguration = ctx->codec_conf,
1323  .SuggestedProfile = profile,
1324  .SuggestedLevel = level,
1325  .pResolutionDependentSupport = &ctx->res_limits,
1326  };
1327 
1328  hr = ID3D12VideoDevice3_CheckFeatureSupport(ctx->video_device3, D3D12_FEATURE_VIDEO_ENCODER_SUPPORT,
1329  &support, sizeof(support));
1330  if (FAILED(hr)) {
1331  av_log(avctx, AV_LOG_ERROR, "Failed to check encoder support for motion estimation.\n");
1332  return AVERROR(EINVAL);
1333  }
1334 
1335  if (!(support.SupportFlags & D3D12_VIDEO_ENCODER_SUPPORT_FLAG_MOTION_ESTIMATION_PRECISION_MODE_LIMIT_AVAILABLE)) {
1336  av_log(avctx, AV_LOG_ERROR, "Hardware does not support motion estimation "
1337  "precision mode limits.\n");
1338  return AVERROR(ENOTSUP);
1339  }
1340 
1341  av_log(avctx, AV_LOG_VERBOSE, "Hardware supports motion estimation "
1342  "precision mode limits.\n");
1343 
1344  return 0;
1345 }
1346 
1348 {
1349  FFHWBaseEncodeContext *base_ctx = avctx->priv_data;
1351  uint32_t ref_l0, ref_l1;
1352  int err;
1353  HRESULT hr;
1354  D3D12_FEATURE_DATA_VIDEO_ENCODER_CODEC_PICTURE_CONTROL_SUPPORT support;
1355  union {
1356  D3D12_VIDEO_ENCODER_CODEC_PICTURE_CONTROL_SUPPORT_H264 h264;
1357  D3D12_VIDEO_ENCODER_CODEC_PICTURE_CONTROL_SUPPORT_HEVC hevc;
1358 #if CONFIG_AV1_D3D12VA_ENCODER
1359  D3D12_VIDEO_ENCODER_CODEC_AV1_PICTURE_CONTROL_SUPPORT av1;
1360 #endif
1361  } codec_support;
1362 
1363  support.NodeIndex = 0;
1364  support.Codec = ctx->codec->d3d12_codec;
1365  support.Profile = ctx->profile->d3d12_profile;
1366 
1367  switch (ctx->codec->d3d12_codec) {
1368  case D3D12_VIDEO_ENCODER_CODEC_H264:
1369  support.PictureSupport.DataSize = sizeof(codec_support.h264);
1370  support.PictureSupport.pH264Support = &codec_support.h264;
1371  break;
1372 
1373  case D3D12_VIDEO_ENCODER_CODEC_HEVC:
1374  support.PictureSupport.DataSize = sizeof(codec_support.hevc);
1375  support.PictureSupport.pHEVCSupport = &codec_support.hevc;
1376  break;
1377 
1378 #if CONFIG_AV1_D3D12VA_ENCODER
1379  case D3D12_VIDEO_ENCODER_CODEC_AV1:
1380  memset(&codec_support.av1, 0, sizeof(codec_support.av1));
1381  support.PictureSupport.DataSize = sizeof(codec_support.av1);
1382  support.PictureSupport.pAV1Support = &codec_support.av1;
1383  break;
1384 #endif
1385  default:
1386  av_assert0(0);
1387  }
1388 
1389  hr = ID3D12VideoDevice3_CheckFeatureSupport(ctx->video_device3, D3D12_FEATURE_VIDEO_ENCODER_CODEC_PICTURE_CONTROL_SUPPORT,
1390  &support, sizeof(support));
1391  if (FAILED(hr))
1392  return AVERROR(EINVAL);
1393 
1394  if (support.IsSupported) {
1395  switch (ctx->codec->d3d12_codec) {
1396  case D3D12_VIDEO_ENCODER_CODEC_H264:
1397  ref_l0 = FFMIN(support.PictureSupport.pH264Support->MaxL0ReferencesForP,
1398  support.PictureSupport.pH264Support->MaxL1ReferencesForB ?
1399  support.PictureSupport.pH264Support->MaxL1ReferencesForB : UINT_MAX);
1400  ref_l1 = support.PictureSupport.pH264Support->MaxL1ReferencesForB;
1401  break;
1402 
1403  case D3D12_VIDEO_ENCODER_CODEC_HEVC:
1404  ref_l0 = FFMIN(support.PictureSupport.pHEVCSupport->MaxL0ReferencesForP,
1405  support.PictureSupport.pHEVCSupport->MaxL1ReferencesForB ?
1406  support.PictureSupport.pHEVCSupport->MaxL1ReferencesForB : UINT_MAX);
1407  ref_l1 = support.PictureSupport.pHEVCSupport->MaxL1ReferencesForB;
1408  break;
1409 
1410 #if CONFIG_AV1_D3D12VA_ENCODER
1411  case D3D12_VIDEO_ENCODER_CODEC_AV1:
1412  ref_l0 = support.PictureSupport.pAV1Support->MaxUniqueReferencesPerFrame;
1413  // AV1 doesn't use traditional L1 references like H.264/HEVC
1414  ref_l1 = 0;
1415  break;
1416 #endif
1417  default:
1418  av_assert0(0);
1419  }
1420  } else {
1421  ref_l0 = ref_l1 = 0;
1422  }
1423 
1424  if (ref_l0 > 0 && ref_l1 > 0 && ctx->bi_not_empty) {
1425  base_ctx->p_to_gpb = 1;
1426  av_log(avctx, AV_LOG_VERBOSE, "Driver does not support P-frames, "
1427  "replacing them with B-frames.\n");
1428  }
1429 
1430  err = ff_hw_base_init_gop_structure(base_ctx, avctx, ref_l0, ref_l1, ctx->codec->flags, 0);
1431  if (err < 0)
1432  return err;
1433 
1434  return 0;
1435 }
1436 
1438 {
1439  FFHWBaseEncodeContext *base_ctx = avctx->priv_data;
1441 
1442  if (ctx->intra_refresh.Mode == D3D12_VIDEO_ENCODER_INTRA_REFRESH_MODE_NONE)
1443  return 0;
1444 
1445  // Check for SDK API availability
1446 #if CONFIG_D3D12_INTRA_REFRESH
1447  HRESULT hr;
1448  D3D12_VIDEO_ENCODER_LEVEL_SETTING level = { 0 };
1449  D3D12_VIDEO_ENCODER_LEVELS_H264 h264_level = { 0 };
1450  D3D12_VIDEO_ENCODER_LEVEL_TIER_CONSTRAINTS_HEVC hevc_level = { 0 };
1451 #if CONFIG_AV1_D3D12VA_ENCODER
1452  D3D12_VIDEO_ENCODER_AV1_LEVEL_TIER_CONSTRAINTS av1_level = { 0 };
1453 #endif
1454 
1455  switch (ctx->codec->d3d12_codec) {
1456  case D3D12_VIDEO_ENCODER_CODEC_H264:
1457  level.DataSize = sizeof(D3D12_VIDEO_ENCODER_LEVELS_H264);
1458  level.pH264LevelSetting = &h264_level;
1459  break;
1460  case D3D12_VIDEO_ENCODER_CODEC_HEVC:
1461  level.DataSize = sizeof(D3D12_VIDEO_ENCODER_LEVEL_TIER_CONSTRAINTS_HEVC);
1462  level.pHEVCLevelSetting = &hevc_level;
1463  break;
1464 #if CONFIG_AV1_D3D12VA_ENCODER
1465  case D3D12_VIDEO_ENCODER_CODEC_AV1:
1466  level.DataSize = sizeof(D3D12_VIDEO_ENCODER_AV1_LEVEL_TIER_CONSTRAINTS);
1467  level.pAV1LevelSetting = &av1_level;
1468  break;
1469 #endif
1470  default:
1471  av_assert0(0);
1472  }
1473 
1474  D3D12_FEATURE_DATA_VIDEO_ENCODER_INTRA_REFRESH_MODE intra_refresh_support = {
1475  .NodeIndex = 0,
1476  .Codec = ctx->codec->d3d12_codec,
1477  .Profile = ctx->profile->d3d12_profile,
1478  .Level = level,
1479  .IntraRefreshMode = ctx->intra_refresh.Mode,
1480  };
1481 
1482  hr = ID3D12VideoDevice3_CheckFeatureSupport(ctx->video_device3,
1483  D3D12_FEATURE_VIDEO_ENCODER_INTRA_REFRESH_MODE,
1484  &intra_refresh_support, sizeof(intra_refresh_support));
1485 
1486  if (FAILED(hr) || !intra_refresh_support.IsSupported) {
1487  av_log(avctx, AV_LOG_ERROR, "Requested intra refresh mode not supported by driver.\n");
1488  return AVERROR(ENOTSUP);
1489  }
1490 #else
1491  // Older SDK - validation will occur in init_sequence_params via D3D12_FEATURE_VIDEO_ENCODER_SUPPORT
1492  av_log(avctx, AV_LOG_VERBOSE, "Intra refresh explicit check not available in this SDK.\n"
1493  "Support will be validated during encoder initialization.\n");
1494 #endif
1495 
1496  // Set duration: use GOP size if not specified
1497  if (ctx->intra_refresh.IntraRefreshDuration == 0) {
1498  ctx->intra_refresh.IntraRefreshDuration = base_ctx->gop_size;
1499  av_log(avctx, AV_LOG_VERBOSE, "Intra refresh duration set to GOP size: %d\n",
1500  ctx->intra_refresh.IntraRefreshDuration);
1501  }
1502 
1503  // Initialize frame index
1504  ctx->intra_refresh_frame_index = 0;
1505 
1506  av_log(avctx, AV_LOG_VERBOSE, "Intra refresh: mode=%d, duration=%d frames\n",
1507  ctx->intra_refresh.Mode, ctx->intra_refresh.IntraRefreshDuration);
1508 
1509  return 0;
1510 }
1511 
1513 {
1514  FFHWBaseEncodeContext *base_ctx = avctx->priv_data;
1516  AVD3D12VAFramesContext *frames_hwctx = base_ctx->input_frames->hwctx;
1517  HRESULT hr;
1518 
1519  D3D12_VIDEO_ENCODER_DESC desc = {
1520  .NodeMask = 0,
1521  .Flags = D3D12_VIDEO_ENCODER_FLAG_NONE,
1522  .EncodeCodec = ctx->codec->d3d12_codec,
1523  .EncodeProfile = ctx->profile->d3d12_profile,
1524  .InputFormat = frames_hwctx->format,
1525  .CodecConfiguration = ctx->codec_conf,
1526  .MaxMotionEstimationPrecision = ctx->me_precision,
1527  };
1528 
1529  hr = ID3D12VideoDevice3_CreateVideoEncoder(ctx->video_device3, &desc, &IID_ID3D12VideoEncoder,
1530  (void **)&ctx->encoder);
1531  if (FAILED(hr)) {
1532  av_log(avctx, AV_LOG_ERROR, "Failed to create encoder.\n");
1533  return AVERROR(EINVAL);
1534  }
1535 
1536  return 0;
1537 }
1538 
1540 {
1542  HRESULT hr;
1543 
1544  D3D12_VIDEO_ENCODER_HEAP_DESC desc = {
1545  .NodeMask = 0,
1546  .Flags = D3D12_VIDEO_ENCODER_HEAP_FLAG_NONE,
1547  .EncodeCodec = ctx->codec->d3d12_codec,
1548  .EncodeProfile = ctx->profile->d3d12_profile,
1549  .EncodeLevel = ctx->level,
1550  .ResolutionsListCount = 1,
1551  .pResolutionList = &ctx->resolution,
1552  };
1553 
1554  hr = ID3D12VideoDevice3_CreateVideoEncoderHeap(ctx->video_device3, &desc,
1555  &IID_ID3D12VideoEncoderHeap, (void **)&ctx->encoder_heap);
1556  if (FAILED(hr)) {
1557  av_log(avctx, AV_LOG_ERROR, "Failed to create encoder heap.\n");
1558  return AVERROR(EINVAL);
1559  }
1560 
1561  return 0;
1562 }
1563 
1564 static void d3d12va_encode_free_buffer(void *opaque, uint8_t *data)
1565 {
1566  ID3D12Resource *pResource;
1567 
1568  pResource = (ID3D12Resource *)data;
1569  D3D12_OBJECT_RELEASE(pResource);
1570 }
1571 
1573 {
1574  AVCodecContext *avctx = opaque;
1575  FFHWBaseEncodeContext *base_ctx = avctx->priv_data;
1577  ID3D12Resource *pResource = NULL;
1578  HRESULT hr;
1579  AVBufferRef *ref;
1580  D3D12_HEAP_PROPERTIES heap_props;
1581  D3D12_HEAP_TYPE heap_type = D3D12_HEAP_TYPE_READBACK;
1582 
1583  D3D12_RESOURCE_DESC desc = {
1584  .Dimension = D3D12_RESOURCE_DIMENSION_BUFFER,
1585  .Alignment = 0,
1586  .Width = FFALIGN(3 * base_ctx->surface_width * base_ctx->surface_height + (1 << 16),
1587  D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT),
1588  .Height = 1,
1589  .DepthOrArraySize = 1,
1590  .MipLevels = 1,
1591  .Format = DXGI_FORMAT_UNKNOWN,
1592  .SampleDesc = { .Count = 1, .Quality = 0 },
1593  .Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR,
1594  .Flags = D3D12_RESOURCE_FLAG_NONE,
1595  };
1596 
1597  ctx->hwctx->device->lpVtbl->GetCustomHeapProperties(ctx->hwctx->device, &heap_props, 0, heap_type);
1598 
1599  hr = ID3D12Device_CreateCommittedResource(ctx->hwctx->device, &heap_props, D3D12_HEAP_FLAG_NONE,
1600  &desc, D3D12_RESOURCE_STATE_COMMON, NULL, &IID_ID3D12Resource,
1601  (void **)&pResource);
1602 
1603  if (FAILED(hr)) {
1604  av_log(avctx, AV_LOG_ERROR, "Failed to create d3d12 buffer.\n");
1605  return NULL;
1606  }
1607 
1608  ref = av_buffer_create((uint8_t *)(uintptr_t)pResource,
1609  sizeof(pResource),
1611  avctx, AV_BUFFER_FLAG_READONLY);
1612  if (!ref) {
1613  D3D12_OBJECT_RELEASE(pResource);
1614  return NULL;
1615  }
1616 
1617  return ref;
1618 }
1619 
1621 {
1622  FFHWBaseEncodeContext *base_ctx = avctx->priv_data;
1624  AVD3D12VAFramesContext *frames_ctx = base_ctx->input_frames->hwctx;
1625  HRESULT hr;
1626 
1627  ctx->req.NodeIndex = 0;
1628  ctx->req.Codec = ctx->codec->d3d12_codec;
1629  ctx->req.Profile = ctx->profile->d3d12_profile;
1630  ctx->req.InputFormat = frames_ctx->format;
1631  ctx->req.PictureTargetResolution = ctx->resolution;
1632 
1633  hr = ID3D12VideoDevice3_CheckFeatureSupport(ctx->video_device3,
1634  D3D12_FEATURE_VIDEO_ENCODER_RESOURCE_REQUIREMENTS,
1635  &ctx->req, sizeof(ctx->req));
1636  if (FAILED(hr)) {
1637  av_log(avctx, AV_LOG_ERROR, "Failed to check encoder resource requirements support.\n");
1638  return AVERROR(EINVAL);
1639  }
1640 
1641  if (!ctx->req.IsSupported) {
1642  av_log(avctx, AV_LOG_ERROR, "Encoder resource requirements unsupported.\n");
1643  return AVERROR(EINVAL);
1644  }
1645 
1646  ctx->output_buffer_pool = av_buffer_pool_init2(sizeof(ID3D12Resource *), avctx,
1648  if (!ctx->output_buffer_pool)
1649  return AVERROR(ENOMEM);
1650 
1651  return 0;
1652 }
1653 
1655 {
1657  ID3D12CommandAllocator *command_allocator = NULL;
1658  int err = AVERROR_UNKNOWN;
1659  HRESULT hr;
1660 
1661  D3D12_COMMAND_QUEUE_DESC queue_desc = {
1662  .Type = D3D12_COMMAND_LIST_TYPE_VIDEO_ENCODE,
1663  .Priority = 0,
1664  .Flags = D3D12_COMMAND_QUEUE_FLAG_NONE,
1665  .NodeMask = 0,
1666  };
1667 
1670  if (!ctx->allocator_queue)
1671  return AVERROR(ENOMEM);
1672 
1673  hr = ID3D12Device_CreateFence(ctx->hwctx->device, 0, D3D12_FENCE_FLAG_NONE,
1674  &IID_ID3D12Fence, (void **)&ctx->sync_ctx.fence);
1675  if (FAILED(hr)) {
1676  av_log(avctx, AV_LOG_ERROR, "Failed to create fence(%lx)\n", (long)hr);
1677  err = AVERROR_UNKNOWN;
1678  goto fail;
1679  }
1680 
1681  ctx->sync_ctx.event = CreateEvent(NULL, FALSE, FALSE, NULL);
1682  if (!ctx->sync_ctx.event)
1683  goto fail;
1684 
1685  err = d3d12va_get_valid_command_allocator(avctx, &command_allocator);
1686  if (err < 0)
1687  goto fail;
1688 
1689  hr = ID3D12Device_CreateCommandQueue(ctx->hwctx->device, &queue_desc,
1690  &IID_ID3D12CommandQueue, (void **)&ctx->command_queue);
1691  if (FAILED(hr)) {
1692  av_log(avctx, AV_LOG_ERROR, "Failed to create command queue(%lx)\n", (long)hr);
1693  err = AVERROR_UNKNOWN;
1694  goto fail;
1695  }
1696 
1697  hr = ID3D12Device_CreateCommandList(ctx->hwctx->device, 0, queue_desc.Type,
1698  command_allocator, NULL, &IID_ID3D12CommandList,
1699  (void **)&ctx->command_list);
1700  if (FAILED(hr)) {
1701  av_log(avctx, AV_LOG_ERROR, "Failed to create command list(%lx)\n", (long)hr);
1702  err = AVERROR_UNKNOWN;
1703  goto fail;
1704  }
1705 
1706  hr = ID3D12VideoEncodeCommandList2_Close(ctx->command_list);
1707  if (FAILED(hr)) {
1708  av_log(avctx, AV_LOG_ERROR, "Failed to close the command list(%lx)\n", (long)hr);
1709  err = AVERROR_UNKNOWN;
1710  goto fail;
1711  }
1712 
1713  ID3D12CommandQueue_ExecuteCommandLists(ctx->command_queue, 1, (ID3D12CommandList **)&ctx->command_list);
1714 
1715  err = d3d12va_sync_with_gpu(avctx);
1716  if (err < 0)
1717  goto fail;
1718 
1719  err = d3d12va_discard_command_allocator(avctx, command_allocator, ctx->sync_ctx.fence_value);
1720  if (err < 0)
1721  goto fail;
1722 
1723  return 0;
1724 
1725 fail:
1726  D3D12_OBJECT_RELEASE(command_allocator);
1727  return err;
1728 }
1729 
1731 {
1732  FFHWBaseEncodeContext *base_ctx = avctx->priv_data;
1734  AVD3D12VAFramesContext *hwctx;
1735  enum AVPixelFormat recon_format;
1736  int err;
1737 
1738  err = ff_hw_base_get_recon_format(base_ctx, NULL, &recon_format);
1739  if (err < 0)
1740  return err;
1741 
1742  base_ctx->recon_frames_ref = av_hwframe_ctx_alloc(base_ctx->device_ref);
1743  if (!base_ctx->recon_frames_ref)
1744  return AVERROR(ENOMEM);
1745 
1746  base_ctx->recon_frames = (AVHWFramesContext *)base_ctx->recon_frames_ref->data;
1747  hwctx = (AVD3D12VAFramesContext *)base_ctx->recon_frames->hwctx;
1748 
1749  base_ctx->recon_frames->format = AV_PIX_FMT_D3D12;
1750  base_ctx->recon_frames->sw_format = recon_format;
1751  base_ctx->recon_frames->width = base_ctx->surface_width;
1752  base_ctx->recon_frames->height = base_ctx->surface_height;
1753 
1754  hwctx->resource_flags = D3D12_RESOURCE_FLAG_VIDEO_ENCODE_REFERENCE_ONLY |
1755  D3D12_RESOURCE_FLAG_DENY_SHADER_RESOURCE;
1756  if (ctx->is_texture_array) {
1757  base_ctx->recon_frames->initial_pool_size = MAX_DPB_SIZE + 1;
1759  }
1760 
1761  err = av_hwframe_ctx_init(base_ctx->recon_frames_ref);
1762  if (err < 0) {
1763  av_log(avctx, AV_LOG_ERROR, "Failed to initialise reconstructed "
1764  "frame context: %d.\n", err);
1765  return err;
1766  }
1767 
1768  return 0;
1769 }
1770 
1772  .priv_size = sizeof(D3D12VAEncodePicture),
1773 
1775 
1776  .issue = &d3d12va_encode_issue,
1777 
1779 
1780  .free = &d3d12va_encode_free,
1781 };
1782 
1784 {
1785  return ff_hw_base_encode_receive_packet(avctx->priv_data, avctx, pkt);
1786 }
1787 
1789 {
1790  FFHWBaseEncodeContext *base_ctx = avctx->priv_data;
1792  D3D12_FEATURE_DATA_VIDEO_FEATURE_AREA_SUPPORT support = { 0 };
1793  D3D12_FEATURE_DATA_FORMAT_INFO format_info = { 0 };
1794  int err;
1795  HRESULT hr;
1796 
1797  err = ff_hw_base_encode_init(avctx, base_ctx);
1798  if (err < 0)
1799  goto fail;
1800 
1801  base_ctx->op = &d3d12va_type;
1802 
1803  ctx->hwctx = base_ctx->device->hwctx;
1804 
1805  ctx->resolution.Width = base_ctx->input_frames->width;
1806  ctx->resolution.Height = base_ctx->input_frames->height;
1807 
1808  hr = ID3D12Device_QueryInterface(ctx->hwctx->device, &IID_ID3D12Device3, (void **)&ctx->device3);
1809  if (FAILED(hr)) {
1810  av_log(avctx, AV_LOG_ERROR, "ID3D12Device3 interface is not supported.\n");
1811  err = AVERROR_UNKNOWN;
1812  goto fail;
1813  }
1814 
1815  hr = ID3D12Device3_QueryInterface(ctx->device3, &IID_ID3D12VideoDevice3, (void **)&ctx->video_device3);
1816  if (FAILED(hr)) {
1817  av_log(avctx, AV_LOG_ERROR, "ID3D12VideoDevice3 interface is not supported.\n");
1818  err = AVERROR_UNKNOWN;
1819  goto fail;
1820  }
1821 
1822  if (FAILED(ID3D12VideoDevice3_CheckFeatureSupport(ctx->video_device3, D3D12_FEATURE_VIDEO_FEATURE_AREA_SUPPORT,
1823  &support, sizeof(support))) && !support.VideoEncodeSupport) {
1824  av_log(avctx, AV_LOG_ERROR, "D3D12 video device has no video encoder support.\n");
1825  err = AVERROR(EINVAL);
1826  goto fail;
1827  }
1828 
1829  format_info.Format = ((AVD3D12VAFramesContext *)base_ctx->input_frames->hwctx)->format;
1830  if (FAILED(ID3D12VideoDevice_CheckFeatureSupport(ctx->hwctx->device, D3D12_FEATURE_FORMAT_INFO,
1831  &format_info, sizeof(format_info)))) {
1832  av_log(avctx, AV_LOG_ERROR, "Failed to query format plane count: %#lx\n", hr);
1833  err = AVERROR_EXTERNAL;
1834  goto fail;
1835  }
1836  ctx->plane_count = format_info.PlaneCount;
1837 
1838  err = d3d12va_encode_set_profile(avctx);
1839  if (err < 0)
1840  goto fail;
1841 
1842  if (ctx->codec->set_tile) {
1843  err = ctx->codec->set_tile(avctx);
1844  if (err < 0)
1845  goto fail;
1846  }
1847 
1848  err = d3d12va_encode_init_rate_control(avctx);
1849  if (err < 0)
1850  goto fail;
1851 
1852  if (ctx->codec->get_encoder_caps) {
1853  err = ctx->codec->get_encoder_caps(avctx);
1854  if (err < 0)
1855  goto fail;
1856  }
1857 
1858  err = d3d12va_encode_init_gop_structure(avctx);
1859  if (err < 0)
1860  goto fail;
1861 
1862  err = d3d12va_encode_init_intra_refresh(avctx);
1863  if (err < 0)
1864  goto fail;
1865 
1866  if (!(ctx->codec->flags & FF_HW_FLAG_SLICE_CONTROL) && avctx->slices > 0) {
1867  av_log(avctx, AV_LOG_WARNING, "Multiple slices were requested "
1868  "but this codec does not support controlling slices.\n");
1869  }
1870 
1872  if (err < 0)
1873  goto fail;
1874 
1876  if (err < 0)
1877  goto fail;
1878 
1879  if (ctx->codec->configure) {
1880  err = ctx->codec->configure(avctx);
1881  if (err < 0)
1882  goto fail;
1883  }
1884 
1886  if (err < 0)
1887  goto fail;
1888 
1889  if (ctx->codec->init_sequence_params) {
1890  err = ctx->codec->init_sequence_params(avctx);
1891  if (err < 0) {
1892  av_log(avctx, AV_LOG_ERROR, "Codec sequence initialisation "
1893  "failed: %d.\n", err);
1894  goto fail;
1895  }
1896  }
1897 
1898  if (ctx->codec->set_level) {
1899  err = ctx->codec->set_level(avctx);
1900  if (err < 0)
1901  goto fail;
1902  }
1903 
1905  if (err < 0)
1906  goto fail;
1907 
1908  base_ctx->output_delay = base_ctx->b_per_p;
1909  base_ctx->decode_delay = base_ctx->max_b_depth;
1910 
1911  err = d3d12va_create_encoder(avctx);
1912  if (err < 0)
1913  goto fail;
1914 
1915  err = d3d12va_create_encoder_heap(avctx);
1916  if (err < 0)
1917  goto fail;
1918 
1919  base_ctx->async_encode = 1;
1920  base_ctx->encode_fifo = av_fifo_alloc2(base_ctx->async_depth,
1921  sizeof(D3D12VAEncodePicture *), 0);
1922  if (!base_ctx->encode_fifo)
1923  return AVERROR(ENOMEM);
1924 
1925  return 0;
1926 
1927 fail:
1928  return err;
1929 }
1930 
1932 {
1933  int num_allocator = 0;
1934  FFHWBaseEncodeContext *base_ctx = avctx->priv_data;
1936  FFHWBaseEncodePicture *pic, *next;
1937  CommandAllocator allocator;
1938 
1939  if (!base_ctx->frame)
1940  return 0;
1941 
1942  for (pic = base_ctx->pic_start; pic; pic = next) {
1943  next = pic->next;
1944  d3d12va_encode_free(avctx, pic);
1945  }
1946 
1948 
1949  av_buffer_pool_uninit(&ctx->output_buffer_pool);
1950 
1951  D3D12_OBJECT_RELEASE(ctx->command_list);
1952  D3D12_OBJECT_RELEASE(ctx->command_queue);
1953 
1954  if (ctx->allocator_queue) {
1955  while (av_fifo_read(ctx->allocator_queue, &allocator, 1) >= 0) {
1956  num_allocator++;
1958  }
1959 
1960  av_log(avctx, AV_LOG_VERBOSE, "Total number of command allocators reused: %d\n", num_allocator);
1961  }
1962 
1963  av_fifo_freep2(&ctx->allocator_queue);
1964 
1965  D3D12_OBJECT_RELEASE(ctx->sync_ctx.fence);
1966  if (ctx->sync_ctx.event)
1967  CloseHandle(ctx->sync_ctx.event);
1968 
1969  D3D12_OBJECT_RELEASE(ctx->encoder_heap);
1970  D3D12_OBJECT_RELEASE(ctx->encoder);
1971  D3D12_OBJECT_RELEASE(ctx->video_device3);
1972  D3D12_OBJECT_RELEASE(ctx->device3);
1973 
1974  ff_hw_base_encode_close(base_ctx);
1975 
1976  return 0;
1977 }
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:898
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
av_frame_get_side_data
AVFrameSideData * av_frame_get_side_data(const AVFrame *frame, enum AVFrameSideDataType type)
Definition: frame.c:659
FFHWBaseEncodePicture::priv
void * priv
Definition: hw_base_encode.h:63
av_clip_int8
#define av_clip_int8
Definition: common.h:109
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:1730
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:826
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
D3D12VAEncodePicture::qp_map_size
int qp_map_size
Definition: d3d12va_encode.h:63
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:868
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:774
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:216
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:951
check_rate_control_support
static int check_rate_control_support(AVCodecContext *avctx, const D3D12VAEncodeRCMode *rc_mode)
Definition: d3d12va_encode.c:961
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:791
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
AVFrameSideData::size
size_t size
Definition: frame.h:285
AVRegionOfInterest
Structure describing a single Region Of Interest.
Definition: frame.h:353
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:294
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
AVRegionOfInterest::bottom
int bottom
Definition: frame.h:369
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:1539
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:710
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:108
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
av_clip_int16
#define av_clip_int16
Definition: common.h:115
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
AVRegionOfInterest::self_size
uint32_t self_size
Must be set to the size of this data structure (that is, sizeof(AVRegionOfInterest)).
Definition: frame.h:358
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
d3d12va_encode_setup_roi
static int d3d12va_encode_setup_roi(AVCodecContext *avctx, D3D12VAEncodePicture *pic, const uint8_t *data, size_t size)
Definition: d3d12va_encode.c:143
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:1564
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:242
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:1654
ff_d3d12va_encode_init
int ff_d3d12va_encode_init(AVCodecContext *avctx)
Definition: d3d12va_encode.c:1788
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:1771
MAX_DPB_SIZE
#define MAX_DPB_SIZE
Definition: hw_base_encode.h:26
D3D12VAEncodeProfile
Definition: d3d12va_encode.h:66
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
AVFrameSideData::data
uint8_t * data
Definition: frame.h:284
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
FFHWBaseEncodeContext::roi_allowed
int roi_allowed
Definition: hw_base_encode.h:201
RC_MODE_QVBR
@ RC_MODE_QVBR
Definition: d3d12va_encode.h:103
AVRegionOfInterest::right
int right
Definition: frame.h:371
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:1572
HW_CONFIG_ENCODER_FRAMES
#define HW_CONFIG_ENCODER_FRAMES(format, device_type_)
Definition: hwconfig.h:98
D3D12VAEncodePicture::qp_map
void * qp_map
Definition: d3d12va_encode.h:62
AVRegionOfInterest::left
int left
Definition: frame.h:370
d3d12va_encode_init
static int d3d12va_encode_init(AVCodecContext *avctx, FFHWBaseEncodePicture *pic)
Definition: d3d12va_encode.c:757
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
AVRegionOfInterest::top
int top
Distance in pixels from the top edge of the frame to the top and bottom edges and from the left edge ...
Definition: frame.h:368
internal.h
TRY_RC_MODE
#define TRY_RC_MODE(mode, fail)
RC_MODE_VBR
@ RC_MODE_VBR
Definition: d3d12va_encode.h:102
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:1437
profile
int profile
Definition: mxfenc.c:2297
AVCodecContext::height
int height
Definition: avcodec.h:600
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:1512
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:986
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:150
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:1620
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:1262
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:732
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
AVFrameSideData
Structure to hold side data for an AVFrame.
Definition: frame.h:282
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:1931
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:1783
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:1347
AVCodecContext::width
int width
picture width / height.
Definition: avcodec.h:600
FFHWBaseEncodeContext::recon_frames
AVHWFramesContext * recon_frames
Definition: hw_base_encode.h:157
AV_FRAME_DATA_REGIONS_OF_INTEREST
@ AV_FRAME_DATA_REGIONS_OF_INTEREST
Regions Of Interest, the data is an array of AVRegionOfInterest type, the number of array element is ...
Definition: frame.h:165
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
AVRegionOfInterest::qoffset
AVRational qoffset
Quantisation offset.
Definition: frame.h:395
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:100
TRANSITION_BARRIER
#define TRANSITION_BARRIER(res, subres, before, after)
RC_MODE_CBR
@ RC_MODE_CBR
Definition: d3d12va_encode.h:101