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