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