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