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 "avcodec.h"
33 #include "d3d12va_encode.h"
34 #include "encode.h"
35 
37  HW_CONFIG_ENCODER_FRAMES(D3D12, D3D12VA),
38  NULL,
39 };
40 
42 {
43  uint64_t completion = ID3D12Fence_GetCompletedValue(psync_ctx->fence);
44  if (completion < psync_ctx->fence_value) {
45  if (FAILED(ID3D12Fence_SetEventOnCompletion(psync_ctx->fence, psync_ctx->fence_value, psync_ctx->event)))
46  return AVERROR(EINVAL);
47 
48  WaitForSingleObjectEx(psync_ctx->event, INFINITE, FALSE);
49  }
50 
51  return 0;
52 }
53 
55 {
57 
58  DX_CHECK(ID3D12CommandQueue_Signal(ctx->command_queue, ctx->sync_ctx.fence, ++ctx->sync_ctx.fence_value));
59  return d3d12va_fence_completion(&ctx->sync_ctx);
60 
61 fail:
62  return AVERROR(EINVAL);
63 }
64 
65 typedef struct CommandAllocator {
66  ID3D12CommandAllocator *command_allocator;
67  uint64_t fence_value;
69 
70 static int d3d12va_get_valid_command_allocator(AVCodecContext *avctx, ID3D12CommandAllocator **ppAllocator)
71 {
72  HRESULT hr;
74  CommandAllocator allocator;
75 
76  if (av_fifo_peek(ctx->allocator_queue, &allocator, 1, 0) >= 0) {
77  uint64_t completion = ID3D12Fence_GetCompletedValue(ctx->sync_ctx.fence);
78  if (completion >= allocator.fence_value) {
79  *ppAllocator = allocator.command_allocator;
80  av_fifo_read(ctx->allocator_queue, &allocator, 1);
81  return 0;
82  }
83  }
84 
85  hr = ID3D12Device_CreateCommandAllocator(ctx->hwctx->device, D3D12_COMMAND_LIST_TYPE_VIDEO_ENCODE,
86  &IID_ID3D12CommandAllocator, (void **)ppAllocator);
87  if (FAILED(hr)) {
88  av_log(avctx, AV_LOG_ERROR, "Failed to create a new command allocator!\n");
89  return AVERROR(EINVAL);
90  }
91 
92  return 0;
93 }
94 
95 static int d3d12va_discard_command_allocator(AVCodecContext *avctx, ID3D12CommandAllocator *pAllocator, uint64_t fence_value)
96 {
98 
99  CommandAllocator allocator = {
100  .command_allocator = pAllocator,
101  .fence_value = fence_value,
102  };
103 
104  av_fifo_write(ctx->allocator_queue, &allocator, 1);
105 
106  return 0;
107 }
108 
110  FFHWBaseEncodePicture *base_pic)
111 {
113  D3D12VAEncodePicture *pic = base_pic->priv;
114  uint64_t completion;
115 
116  av_assert0(base_pic->encode_issued);
117 
118  if (base_pic->encode_complete) {
119  // Already waited for this picture.
120  return 0;
121  }
122 
123  completion = ID3D12Fence_GetCompletedValue(ctx->sync_ctx.fence);
124  if (completion < pic->fence_value) {
125  if (FAILED(ID3D12Fence_SetEventOnCompletion(ctx->sync_ctx.fence, pic->fence_value,
126  ctx->sync_ctx.event)))
127  return AVERROR(EINVAL);
128 
129  WaitForSingleObjectEx(ctx->sync_ctx.event, INFINITE, FALSE);
130  }
131 
132  av_log(avctx, AV_LOG_DEBUG, "Sync to pic %"PRId64"/%"PRId64" "
133  "(input surface %p).\n", base_pic->display_order,
134  base_pic->encode_order, pic->input_surface->texture);
135 
136  av_frame_free(&base_pic->input_image);
137 
138  base_pic->encode_complete = 1;
139  return 0;
140 }
141 
144 {
146  int width = sizeof(D3D12_VIDEO_ENCODER_OUTPUT_METADATA) + sizeof(D3D12_VIDEO_ENCODER_FRAME_SUBREGION_METADATA);
147  D3D12_HEAP_PROPERTIES encoded_meta_props = { .Type = D3D12_HEAP_TYPE_DEFAULT }, resolved_meta_props;
148  D3D12_HEAP_TYPE resolved_heap_type = D3D12_HEAP_TYPE_READBACK;
149  HRESULT hr;
150 
151  D3D12_RESOURCE_DESC meta_desc = {
152  .Dimension = D3D12_RESOURCE_DIMENSION_BUFFER,
153  .Alignment = 0,
154  .Width = ctx->req.MaxEncoderOutputMetadataBufferSize,
155  .Height = 1,
156  .DepthOrArraySize = 1,
157  .MipLevels = 1,
158  .Format = DXGI_FORMAT_UNKNOWN,
159  .SampleDesc = { .Count = 1, .Quality = 0 },
160  .Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR,
161  .Flags = D3D12_RESOURCE_FLAG_NONE,
162  };
163 
164  hr = ID3D12Device_CreateCommittedResource(ctx->hwctx->device, &encoded_meta_props, D3D12_HEAP_FLAG_NONE,
165  &meta_desc, D3D12_RESOURCE_STATE_COMMON, NULL,
166  &IID_ID3D12Resource, (void **)&pic->encoded_metadata);
167  if (FAILED(hr)) {
168  av_log(avctx, AV_LOG_ERROR, "Failed to create metadata buffer.\n");
169  return AVERROR_UNKNOWN;
170  }
171 
172  ctx->hwctx->device->lpVtbl->GetCustomHeapProperties(ctx->hwctx->device, &resolved_meta_props, 0, resolved_heap_type);
173 
174  meta_desc.Width = width;
175 
176  hr = ID3D12Device_CreateCommittedResource(ctx->hwctx->device, &resolved_meta_props, D3D12_HEAP_FLAG_NONE,
177  &meta_desc, D3D12_RESOURCE_STATE_COMMON, NULL,
178  &IID_ID3D12Resource, (void **)&pic->resolved_metadata);
179 
180  if (FAILED(hr)) {
181  av_log(avctx, AV_LOG_ERROR, "Failed to create output metadata buffer.\n");
182  return AVERROR_UNKNOWN;
183  }
184 
185  return 0;
186 }
187 
189  FFHWBaseEncodePicture *base_pic)
190 {
191  FFHWBaseEncodeContext *base_ctx = avctx->priv_data;
193  D3D12VAEncodePicture *pic = base_pic->priv;
194  AVD3D12VAFramesContext *frames_hwctx = base_ctx->input_frames->hwctx;
195  int err, i, j;
196  HRESULT hr;
198  void *ptr;
199  size_t bit_len;
200  ID3D12CommandAllocator *command_allocator = NULL;
201  ID3D12VideoEncodeCommandList2 *cmd_list = ctx->command_list;
202  D3D12_RESOURCE_BARRIER barriers[32] = { 0 };
203  D3D12_VIDEO_ENCODE_REFERENCE_FRAMES d3d12_refs = { 0 };
204 
205  D3D12_VIDEO_ENCODER_ENCODEFRAME_INPUT_ARGUMENTS input_args = {
206  .SequenceControlDesc = {
207  .Flags = D3D12_VIDEO_ENCODER_SEQUENCE_CONTROL_FLAG_NONE,
208  .IntraRefreshConfig = { 0 },
209  .RateControl = ctx->rc,
210  .PictureTargetResolution = ctx->resolution,
211  .SelectedLayoutMode = D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_FULL_FRAME,
212  .FrameSubregionsLayoutData = { 0 },
213  .CodecGopSequence = ctx->gop,
214  },
215  .pInputFrame = pic->input_surface->texture,
216  .InputFrameSubresource = 0,
217  };
218 
219  D3D12_VIDEO_ENCODER_ENCODEFRAME_OUTPUT_ARGUMENTS output_args = { 0 };
220 
221  D3D12_VIDEO_ENCODER_RESOLVE_METADATA_INPUT_ARGUMENTS input_metadata = {
222  .EncoderCodec = ctx->codec->d3d12_codec,
223  .EncoderProfile = ctx->profile->d3d12_profile,
224  .EncoderInputFormat = frames_hwctx->format,
225  .EncodedPictureEffectiveResolution = ctx->resolution,
226  };
227 
228  D3D12_VIDEO_ENCODER_RESOLVE_METADATA_OUTPUT_ARGUMENTS output_metadata = { 0 };
229 
230  memset(data, 0, sizeof(data));
231 
232  av_log(avctx, AV_LOG_DEBUG, "Issuing encode for pic %"PRId64"/%"PRId64" "
233  "as type %s.\n", base_pic->display_order, base_pic->encode_order,
235  if (base_pic->nb_refs[0] == 0 && base_pic->nb_refs[1] == 0) {
236  av_log(avctx, AV_LOG_DEBUG, "No reference pictures.\n");
237  } else {
238  av_log(avctx, AV_LOG_DEBUG, "L0 refers to");
239  for (i = 0; i < base_pic->nb_refs[0]; i++) {
240  av_log(avctx, AV_LOG_DEBUG, " %"PRId64"/%"PRId64,
241  base_pic->refs[0][i]->display_order, base_pic->refs[0][i]->encode_order);
242  }
243  av_log(avctx, AV_LOG_DEBUG, ".\n");
244 
245  if (base_pic->nb_refs[1]) {
246  av_log(avctx, AV_LOG_DEBUG, "L1 refers to");
247  for (i = 0; i < base_pic->nb_refs[1]; i++) {
248  av_log(avctx, AV_LOG_DEBUG, " %"PRId64"/%"PRId64,
249  base_pic->refs[1][i]->display_order, base_pic->refs[1][i]->encode_order);
250  }
251  av_log(avctx, AV_LOG_DEBUG, ".\n");
252  }
253  }
254 
255  av_assert0(!base_pic->encode_issued);
256  for (i = 0; i < base_pic->nb_refs[0]; i++) {
257  av_assert0(base_pic->refs[0][i]);
258  av_assert0(base_pic->refs[0][i]->encode_issued);
259  }
260  for (i = 0; i < base_pic->nb_refs[1]; i++) {
261  av_assert0(base_pic->refs[1][i]);
262  av_assert0(base_pic->refs[1][i]->encode_issued);
263  }
264 
265  av_log(avctx, AV_LOG_DEBUG, "Input surface is %p.\n", pic->input_surface->texture);
266 
267  pic->recon_surface = (AVD3D12VAFrame *)base_pic->recon_image->data[0];
268  av_log(avctx, AV_LOG_DEBUG, "Recon surface is %p.\n",
269  pic->recon_surface->texture);
270 
271  pic->output_buffer_ref = av_buffer_pool_get(ctx->output_buffer_pool);
272  if (!pic->output_buffer_ref) {
273  err = AVERROR(ENOMEM);
274  goto fail;
275  }
276  pic->output_buffer = (ID3D12Resource *)pic->output_buffer_ref->data;
277  av_log(avctx, AV_LOG_DEBUG, "Output buffer is %p.\n",
278  pic->output_buffer);
279 
280  err = d3d12va_encode_create_metadata_buffers(avctx, pic);
281  if (err < 0)
282  goto fail;
283 
284  if (ctx->codec->init_picture_params) {
285  err = ctx->codec->init_picture_params(avctx, base_pic);
286  if (err < 0) {
287  av_log(avctx, AV_LOG_ERROR, "Failed to initialise picture "
288  "parameters: %d.\n", err);
289  goto fail;
290  }
291  }
292 
293  if (base_pic->type == FF_HW_PICTURE_TYPE_IDR) {
294  if (ctx->codec->write_sequence_header) {
295  bit_len = 8 * sizeof(data);
296  err = ctx->codec->write_sequence_header(avctx, data, &bit_len);
297  if (err < 0) {
298  av_log(avctx, AV_LOG_ERROR, "Failed to write per-sequence "
299  "header: %d.\n", err);
300  goto fail;
301  }
302  pic->header_size = (int)bit_len / 8;
303  pic->aligned_header_size = pic->header_size % ctx->req.CompressedBitstreamBufferAccessAlignment ?
304  FFALIGN(pic->header_size, ctx->req.CompressedBitstreamBufferAccessAlignment) :
305  pic->header_size;
306 
307  hr = ID3D12Resource_Map(pic->output_buffer, 0, NULL, (void **)&ptr);
308  if (FAILED(hr)) {
309  err = AVERROR_UNKNOWN;
310  goto fail;
311  }
312 
313  memcpy(ptr, data, pic->aligned_header_size);
314  ID3D12Resource_Unmap(pic->output_buffer, 0, NULL);
315  }
316  }
317 
318  d3d12_refs.NumTexture2Ds = base_pic->nb_refs[0] + base_pic->nb_refs[1];
319  if (d3d12_refs.NumTexture2Ds) {
320  d3d12_refs.ppTexture2Ds = av_calloc(d3d12_refs.NumTexture2Ds,
321  sizeof(*d3d12_refs.ppTexture2Ds));
322  if (!d3d12_refs.ppTexture2Ds) {
323  err = AVERROR(ENOMEM);
324  goto fail;
325  }
326 
327  i = 0;
328  for (j = 0; j < base_pic->nb_refs[0]; j++)
329  d3d12_refs.ppTexture2Ds[i++] = ((D3D12VAEncodePicture *)base_pic->refs[0][j]->priv)->recon_surface->texture;
330  for (j = 0; j < base_pic->nb_refs[1]; j++)
331  d3d12_refs.ppTexture2Ds[i++] = ((D3D12VAEncodePicture *)base_pic->refs[1][j]->priv)->recon_surface->texture;
332  }
333 
334  input_args.PictureControlDesc.IntraRefreshFrameIndex = 0;
335  if (base_pic->is_reference)
336  input_args.PictureControlDesc.Flags |= D3D12_VIDEO_ENCODER_PICTURE_CONTROL_FLAG_USED_AS_REFERENCE_PICTURE;
337 
338  input_args.PictureControlDesc.PictureControlCodecData = pic->pic_ctl;
339  input_args.PictureControlDesc.ReferenceFrames = d3d12_refs;
340  input_args.CurrentFrameBitstreamMetadataSize = pic->aligned_header_size;
341 
342  output_args.Bitstream.pBuffer = pic->output_buffer;
343  output_args.Bitstream.FrameStartOffset = pic->aligned_header_size;
344  output_args.ReconstructedPicture.pReconstructedPicture = pic->recon_surface->texture;
345  output_args.ReconstructedPicture.ReconstructedPictureSubresource = 0;
346  output_args.EncoderOutputMetadata.pBuffer = pic->encoded_metadata;
347  output_args.EncoderOutputMetadata.Offset = 0;
348 
349  input_metadata.HWLayoutMetadata.pBuffer = pic->encoded_metadata;
350  input_metadata.HWLayoutMetadata.Offset = 0;
351 
352  output_metadata.ResolvedLayoutMetadata.pBuffer = pic->resolved_metadata;
353  output_metadata.ResolvedLayoutMetadata.Offset = 0;
354 
355  err = d3d12va_get_valid_command_allocator(avctx, &command_allocator);
356  if (err < 0)
357  goto fail;
358 
359  hr = ID3D12CommandAllocator_Reset(command_allocator);
360  if (FAILED(hr)) {
361  err = AVERROR_UNKNOWN;
362  goto fail;
363  }
364 
365  hr = ID3D12VideoEncodeCommandList2_Reset(cmd_list, command_allocator);
366  if (FAILED(hr)) {
367  err = AVERROR_UNKNOWN;
368  goto fail;
369  }
370 
371 #define TRANSITION_BARRIER(res, before, after) \
372  (D3D12_RESOURCE_BARRIER) { \
373  .Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION, \
374  .Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE, \
375  .Transition = { \
376  .pResource = res, \
377  .Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES, \
378  .StateBefore = before, \
379  .StateAfter = after, \
380  }, \
381  }
382 
383  barriers[0] = TRANSITION_BARRIER(pic->input_surface->texture,
384  D3D12_RESOURCE_STATE_COMMON,
385  D3D12_RESOURCE_STATE_VIDEO_ENCODE_READ);
386  barriers[1] = TRANSITION_BARRIER(pic->output_buffer,
387  D3D12_RESOURCE_STATE_COMMON,
388  D3D12_RESOURCE_STATE_VIDEO_ENCODE_WRITE);
389  barriers[2] = TRANSITION_BARRIER(pic->recon_surface->texture,
390  D3D12_RESOURCE_STATE_COMMON,
391  D3D12_RESOURCE_STATE_VIDEO_ENCODE_WRITE);
392  barriers[3] = TRANSITION_BARRIER(pic->encoded_metadata,
393  D3D12_RESOURCE_STATE_COMMON,
394  D3D12_RESOURCE_STATE_VIDEO_ENCODE_WRITE);
395  barriers[4] = TRANSITION_BARRIER(pic->resolved_metadata,
396  D3D12_RESOURCE_STATE_COMMON,
397  D3D12_RESOURCE_STATE_VIDEO_ENCODE_WRITE);
398 
399  ID3D12VideoEncodeCommandList2_ResourceBarrier(cmd_list, 5, barriers);
400 
401  if (d3d12_refs.NumTexture2Ds) {
402  D3D12_RESOURCE_BARRIER refs_barriers[3];
403 
404  for (i = 0; i < d3d12_refs.NumTexture2Ds; i++)
405  refs_barriers[i] = TRANSITION_BARRIER(d3d12_refs.ppTexture2Ds[i],
406  D3D12_RESOURCE_STATE_COMMON,
407  D3D12_RESOURCE_STATE_VIDEO_ENCODE_READ);
408 
409  ID3D12VideoEncodeCommandList2_ResourceBarrier(cmd_list, d3d12_refs.NumTexture2Ds,
410  refs_barriers);
411  }
412 
413  ID3D12VideoEncodeCommandList2_EncodeFrame(cmd_list, ctx->encoder, ctx->encoder_heap,
414  &input_args, &output_args);
415 
416  barriers[3] = TRANSITION_BARRIER(pic->encoded_metadata,
417  D3D12_RESOURCE_STATE_VIDEO_ENCODE_WRITE,
418  D3D12_RESOURCE_STATE_VIDEO_ENCODE_READ);
419 
420  ID3D12VideoEncodeCommandList2_ResourceBarrier(cmd_list, 1, &barriers[3]);
421 
422  ID3D12VideoEncodeCommandList2_ResolveEncoderOutputMetadata(cmd_list, &input_metadata, &output_metadata);
423 
424  if (d3d12_refs.NumTexture2Ds) {
425  D3D12_RESOURCE_BARRIER refs_barriers[3];
426 
427  for (i = 0; i < d3d12_refs.NumTexture2Ds; i++)
428  refs_barriers[i] = TRANSITION_BARRIER(d3d12_refs.ppTexture2Ds[i],
429  D3D12_RESOURCE_STATE_VIDEO_ENCODE_READ,
430  D3D12_RESOURCE_STATE_COMMON);
431 
432  ID3D12VideoEncodeCommandList2_ResourceBarrier(cmd_list, d3d12_refs.NumTexture2Ds,
433  refs_barriers);
434  }
435 
436  barriers[0] = TRANSITION_BARRIER(pic->input_surface->texture,
437  D3D12_RESOURCE_STATE_VIDEO_ENCODE_READ,
438  D3D12_RESOURCE_STATE_COMMON);
439  barriers[1] = TRANSITION_BARRIER(pic->output_buffer,
440  D3D12_RESOURCE_STATE_VIDEO_ENCODE_WRITE,
441  D3D12_RESOURCE_STATE_COMMON);
442  barriers[2] = TRANSITION_BARRIER(pic->recon_surface->texture,
443  D3D12_RESOURCE_STATE_VIDEO_ENCODE_WRITE,
444  D3D12_RESOURCE_STATE_COMMON);
445  barriers[3] = TRANSITION_BARRIER(pic->encoded_metadata,
446  D3D12_RESOURCE_STATE_VIDEO_ENCODE_READ,
447  D3D12_RESOURCE_STATE_COMMON);
448  barriers[4] = TRANSITION_BARRIER(pic->resolved_metadata,
449  D3D12_RESOURCE_STATE_VIDEO_ENCODE_WRITE,
450  D3D12_RESOURCE_STATE_COMMON);
451 
452  ID3D12VideoEncodeCommandList2_ResourceBarrier(cmd_list, 5, barriers);
453 
454  hr = ID3D12VideoEncodeCommandList2_Close(cmd_list);
455  if (FAILED(hr)) {
456  err = AVERROR_UNKNOWN;
457  goto fail;
458  }
459 
460  hr = ID3D12CommandQueue_Wait(ctx->command_queue, pic->input_surface->sync_ctx.fence,
462  if (FAILED(hr)) {
463  err = AVERROR_UNKNOWN;
464  goto fail;
465  }
466 
467  ID3D12CommandQueue_ExecuteCommandLists(ctx->command_queue, 1, (ID3D12CommandList **)&ctx->command_list);
468 
469  hr = ID3D12CommandQueue_Signal(ctx->command_queue, pic->input_surface->sync_ctx.fence,
471  if (FAILED(hr)) {
472  err = AVERROR_UNKNOWN;
473  goto fail;
474  }
475 
476  hr = ID3D12CommandQueue_Signal(ctx->command_queue, ctx->sync_ctx.fence, ++ctx->sync_ctx.fence_value);
477  if (FAILED(hr)) {
478  err = AVERROR_UNKNOWN;
479  goto fail;
480  }
481 
482  err = d3d12va_discard_command_allocator(avctx, command_allocator, ctx->sync_ctx.fence_value);
483  if (err < 0)
484  goto fail;
485 
486  pic->fence_value = ctx->sync_ctx.fence_value;
487 
488  if (d3d12_refs.ppTexture2Ds)
489  av_freep(&d3d12_refs.ppTexture2Ds);
490 
491  return 0;
492 
493 fail:
494  if (command_allocator)
495  d3d12va_discard_command_allocator(avctx, command_allocator, ctx->sync_ctx.fence_value);
496 
497  if (d3d12_refs.ppTexture2Ds)
498  av_freep(&d3d12_refs.ppTexture2Ds);
499 
500  if (ctx->codec->free_picture_params)
501  ctx->codec->free_picture_params(pic);
502 
504  pic->output_buffer = NULL;
507  return err;
508 }
509 
511  FFHWBaseEncodePicture *base_pic)
512 {
513  D3D12VAEncodePicture *pic = base_pic->priv;
514 
515  d3d12va_encode_wait(avctx, base_pic);
516 
517  if (pic->output_buffer_ref) {
518  av_log(avctx, AV_LOG_DEBUG, "Discard output for pic "
519  "%"PRId64"/%"PRId64".\n",
520  base_pic->display_order, base_pic->encode_order);
521 
523  pic->output_buffer = NULL;
524  }
525 
528 
529  return 0;
530 }
531 
533 {
535 
536  switch (ctx->rc.Mode)
537  {
538  case D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE_CQP:
539  av_freep(&ctx->rc.ConfigParams.pConfiguration_CQP);
540  break;
541  case D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE_CBR:
542  av_freep(&ctx->rc.ConfigParams.pConfiguration_CBR);
543  break;
544  case D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE_VBR:
545  av_freep(&ctx->rc.ConfigParams.pConfiguration_VBR);
546  break;
547  case D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE_QVBR:
548  av_freep(&ctx->rc.ConfigParams.pConfiguration_QVBR);
549  break;
550  default:
551  break;
552  }
553 
554  return 0;
555 }
556 
558 {
560  D3D12VAEncodePicture *priv = pic->priv;
561  AVFrame *frame = pic->input_image;
562 
563  if (ctx->codec->picture_priv_data_size > 0) {
564  pic->codec_priv = av_mallocz(ctx->codec->picture_priv_data_size);
565  if (!pic->codec_priv)
566  return AVERROR(ENOMEM);
567  }
568 
569  priv->input_surface = (AVD3D12VAFrame *)frame->data[0];
570 
571  return 0;
572 }
573 
575 {
577  D3D12VAEncodePicture *priv = pic->priv;
578 
579  if (pic->encode_issued)
580  d3d12va_encode_discard(avctx, pic);
581 
582  if (ctx->codec->free_picture_params)
583  ctx->codec->free_picture_params(priv);
584 
585  return 0;
586 }
587 
589  D3D12VAEncodePicture *pic, size_t *size)
590 {
591  D3D12_VIDEO_ENCODER_OUTPUT_METADATA *meta = NULL;
592  uint8_t *data;
593  HRESULT hr;
594  int err;
595 
596  hr = ID3D12Resource_Map(pic->resolved_metadata, 0, NULL, (void **)&data);
597  if (FAILED(hr)) {
598  err = AVERROR_UNKNOWN;
599  return err;
600  }
601 
602  meta = (D3D12_VIDEO_ENCODER_OUTPUT_METADATA *)data;
603 
604  if (meta->EncodeErrorFlags != D3D12_VIDEO_ENCODER_ENCODE_ERROR_FLAG_NO_ERROR) {
605  av_log(avctx, AV_LOG_ERROR, "Encode failed %"PRIu64"\n", meta->EncodeErrorFlags);
606  err = AVERROR(EINVAL);
607  return err;
608  }
609 
610  if (meta->EncodedBitstreamWrittenBytesCount == 0) {
611  av_log(avctx, AV_LOG_ERROR, "No bytes were written to encoded bitstream\n");
612  err = AVERROR(EINVAL);
613  return err;
614  }
615 
616  *size = meta->EncodedBitstreamWrittenBytesCount;
617 
618  ID3D12Resource_Unmap(pic->resolved_metadata, 0, NULL);
619 
620  return 0;
621 }
622 
625 {
626  int err;
627  uint8_t *ptr, *mapped_data;
628  size_t total_size = 0;
629  HRESULT hr;
630 
631  err = d3d12va_encode_get_buffer_size(avctx, pic, &total_size);
632  if (err < 0)
633  goto end;
634 
635  total_size += pic->header_size;
636  av_log(avctx, AV_LOG_DEBUG, "Output buffer size %"SIZE_SPECIFIER"\n", total_size);
637 
638  hr = ID3D12Resource_Map(pic->output_buffer, 0, NULL, (void **)&mapped_data);
639  if (FAILED(hr)) {
640  err = AVERROR_UNKNOWN;
641  goto end;
642  }
643 
644  err = ff_get_encode_buffer(avctx, pkt, total_size, 0);
645  if (err < 0)
646  goto end;
647  ptr = pkt->data;
648 
649  memcpy(ptr, mapped_data, pic->header_size);
650 
651  ptr += pic->header_size;
652  mapped_data += pic->aligned_header_size;
653  total_size -= pic->header_size;
654 
655  memcpy(ptr, mapped_data, total_size);
656 
657  ID3D12Resource_Unmap(pic->output_buffer, 0, NULL);
658 
659 end:
661  pic->output_buffer = NULL;
662  return err;
663 }
664 
666  FFHWBaseEncodePicture *base_pic, AVPacket *pkt)
667 {
668  FFHWBaseEncodeContext *base_ctx = avctx->priv_data;
669  D3D12VAEncodePicture *pic = base_pic->priv;
670  AVPacket *pkt_ptr = pkt;
671  int err;
672 
673  err = d3d12va_encode_wait(avctx, base_pic);
674  if (err < 0)
675  return err;
676 
677  err = d3d12va_encode_get_coded_data(avctx, pic, pkt);
678  if (err < 0)
679  return err;
680 
681  av_log(avctx, AV_LOG_DEBUG, "Output read for pic %"PRId64"/%"PRId64".\n",
682  base_pic->display_order, base_pic->encode_order);
683 
685  pkt_ptr, 0);
686 
687  return 0;
688 }
689 
691 {
692  FFHWBaseEncodeContext *base_ctx = avctx->priv_data;
695  const AVPixFmtDescriptor *desc;
696  int i, depth;
697 
699  if (!desc) {
700  av_log(avctx, AV_LOG_ERROR, "Invalid input pixfmt (%d).\n",
701  base_ctx->input_frames->sw_format);
702  return AVERROR(EINVAL);
703  }
704 
705  depth = desc->comp[0].depth;
706  for (i = 1; i < desc->nb_components; i++) {
707  if (desc->comp[i].depth != depth) {
708  av_log(avctx, AV_LOG_ERROR, "Invalid input pixfmt (%s).\n",
709  desc->name);
710  return AVERROR(EINVAL);
711  }
712  }
713  av_log(avctx, AV_LOG_VERBOSE, "Input surface format is %s.\n",
714  desc->name);
715 
716  av_assert0(ctx->codec->profiles);
717  for (i = 0; (ctx->codec->profiles[i].av_profile !=
718  AV_PROFILE_UNKNOWN); i++) {
719  profile = &ctx->codec->profiles[i];
720  if (depth != profile->depth ||
721  desc->nb_components != profile->nb_components)
722  continue;
723  if (desc->nb_components > 1 &&
724  (desc->log2_chroma_w != profile->log2_chroma_w ||
725  desc->log2_chroma_h != profile->log2_chroma_h))
726  continue;
727  if (avctx->profile != profile->av_profile &&
728  avctx->profile != AV_PROFILE_UNKNOWN)
729  continue;
730 
731  ctx->profile = profile;
732  break;
733  }
734  if (!ctx->profile) {
735  av_log(avctx, AV_LOG_ERROR, "No usable encoding profile found.\n");
736  return AVERROR(ENOSYS);
737  }
738 
739  avctx->profile = profile->av_profile;
740  return 0;
741 }
742 
744  // Bitrate Quality
745  // | Maxrate | HRD/VBV
746  { 0 }, // | | | |
747  { RC_MODE_CQP, "CQP", 0, 0, 1, 0, D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE_CQP },
748  { RC_MODE_CBR, "CBR", 1, 0, 0, 1, D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE_CBR },
749  { RC_MODE_VBR, "VBR", 1, 1, 0, 1, D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE_VBR },
750  { RC_MODE_QVBR, "QVBR", 1, 1, 1, 1, D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE_QVBR },
751 };
752 
754 {
755  HRESULT hr;
757  D3D12_FEATURE_DATA_VIDEO_ENCODER_RATE_CONTROL_MODE d3d12_rc_mode = {
758  .Codec = ctx->codec->d3d12_codec,
759  };
760 
761  if (!rc_mode->d3d12_mode)
762  return 0;
763 
764  d3d12_rc_mode.IsSupported = 0;
765  d3d12_rc_mode.RateControlMode = rc_mode->d3d12_mode;
766 
767  hr = ID3D12VideoDevice3_CheckFeatureSupport(ctx->video_device3,
768  D3D12_FEATURE_VIDEO_ENCODER_RATE_CONTROL_MODE,
769  &d3d12_rc_mode, sizeof(d3d12_rc_mode));
770  if (FAILED(hr)) {
771  av_log(avctx, AV_LOG_ERROR, "Failed to check rate control support.\n");
772  return 0;
773  }
774 
775  return d3d12_rc_mode.IsSupported;
776 }
777 
779 {
781  int64_t rc_target_bitrate;
782  int64_t rc_peak_bitrate;
783  int rc_quality;
784  int64_t hrd_buffer_size;
785  int64_t hrd_initial_buffer_fullness;
786  int fr_num, fr_den;
788 
789  // Rate control mode selection:
790  // * If the user has set a mode explicitly with the rc_mode option,
791  // use it and fail if it is not available.
792  // * If an explicit QP option has been set, use CQP.
793  // * If the codec is CQ-only, use CQP.
794  // * If the QSCALE avcodec option is set, use CQP.
795  // * If bitrate and quality are both set, try QVBR.
796  // * If quality is set, try CQP.
797  // * If bitrate and maxrate are set and have the same value, try CBR.
798  // * If a bitrate is set, try VBR, then CBR.
799  // * If no bitrate is set, try CQP.
800 
801 #define TRY_RC_MODE(mode, fail) do { \
802  rc_mode = &d3d12va_encode_rc_modes[mode]; \
803  if (!(rc_mode->d3d12_mode && check_rate_control_support(avctx, rc_mode))) { \
804  if (fail) { \
805  av_log(avctx, AV_LOG_ERROR, "Driver does not support %s " \
806  "RC mode.\n", rc_mode->name); \
807  return AVERROR(EINVAL); \
808  } \
809  av_log(avctx, AV_LOG_DEBUG, "Driver does not support %s " \
810  "RC mode.\n", rc_mode->name); \
811  rc_mode = NULL; \
812  } else { \
813  goto rc_mode_found; \
814  } \
815  } while (0)
816 
817  if (ctx->explicit_rc_mode)
818  TRY_RC_MODE(ctx->explicit_rc_mode, 1);
819 
820  if (ctx->explicit_qp)
822 
825 
826  if (avctx->flags & AV_CODEC_FLAG_QSCALE)
828 
829  if (avctx->bit_rate > 0 && avctx->global_quality > 0)
831 
832  if (avctx->global_quality > 0) {
834  }
835 
836  if (avctx->bit_rate > 0 && avctx->rc_max_rate == avctx->bit_rate)
838 
839  if (avctx->bit_rate > 0) {
842  } else {
844  }
845 
846  av_log(avctx, AV_LOG_ERROR, "Driver does not support any "
847  "RC mode compatible with selected options.\n");
848  return AVERROR(EINVAL);
849 
850 rc_mode_found:
851  if (rc_mode->bitrate) {
852  if (avctx->bit_rate <= 0) {
853  av_log(avctx, AV_LOG_ERROR, "Bitrate must be set for %s "
854  "RC mode.\n", rc_mode->name);
855  return AVERROR(EINVAL);
856  }
857 
858  if (rc_mode->maxrate) {
859  if (avctx->rc_max_rate > 0) {
860  if (avctx->rc_max_rate < avctx->bit_rate) {
861  av_log(avctx, AV_LOG_ERROR, "Invalid bitrate settings: "
862  "bitrate (%"PRId64") must not be greater than "
863  "maxrate (%"PRId64").\n", avctx->bit_rate,
864  avctx->rc_max_rate);
865  return AVERROR(EINVAL);
866  }
867  rc_target_bitrate = avctx->bit_rate;
868  rc_peak_bitrate = avctx->rc_max_rate;
869  } else {
870  // We only have a target bitrate, but this mode requires
871  // that a maximum rate be supplied as well. Since the
872  // user does not want this to be a constraint, arbitrarily
873  // pick a maximum rate of double the target rate.
874  rc_target_bitrate = avctx->bit_rate;
875  rc_peak_bitrate = 2 * avctx->bit_rate;
876  }
877  } else {
878  if (avctx->rc_max_rate > avctx->bit_rate) {
879  av_log(avctx, AV_LOG_WARNING, "Max bitrate is ignored "
880  "in %s RC mode.\n", rc_mode->name);
881  }
882  rc_target_bitrate = avctx->bit_rate;
883  rc_peak_bitrate = 0;
884  }
885  } else {
886  rc_target_bitrate = 0;
887  rc_peak_bitrate = 0;
888  }
889 
890  if (rc_mode->quality) {
891  if (ctx->explicit_qp) {
892  rc_quality = ctx->explicit_qp;
893  } else if (avctx->global_quality > 0) {
894  if (avctx->flags & AV_CODEC_FLAG_QSCALE)
895  rc_quality = avctx->global_quality / FF_QP2LAMBDA;
896  else
897  rc_quality = avctx->global_quality;
898  } else {
899  rc_quality = ctx->codec->default_quality;
900  av_log(avctx, AV_LOG_WARNING, "No quality level set; "
901  "using default (%d).\n", rc_quality);
902  }
903  } else {
904  rc_quality = 0;
905  }
906 
907  if (rc_mode->hrd) {
908  if (avctx->rc_buffer_size)
909  hrd_buffer_size = avctx->rc_buffer_size;
910  else if (avctx->rc_max_rate > 0)
911  hrd_buffer_size = avctx->rc_max_rate;
912  else
913  hrd_buffer_size = avctx->bit_rate;
914  if (avctx->rc_initial_buffer_occupancy) {
915  if (avctx->rc_initial_buffer_occupancy > hrd_buffer_size) {
916  av_log(avctx, AV_LOG_ERROR, "Invalid RC buffer settings: "
917  "must have initial buffer size (%d) <= "
918  "buffer size (%"PRId64").\n",
919  avctx->rc_initial_buffer_occupancy, hrd_buffer_size);
920  return AVERROR(EINVAL);
921  }
922  hrd_initial_buffer_fullness = avctx->rc_initial_buffer_occupancy;
923  } else {
924  hrd_initial_buffer_fullness = hrd_buffer_size * 3 / 4;
925  }
926  } else {
927  if (avctx->rc_buffer_size || avctx->rc_initial_buffer_occupancy) {
928  av_log(avctx, AV_LOG_WARNING, "Buffering settings are ignored "
929  "in %s RC mode.\n", rc_mode->name);
930  }
931 
932  hrd_buffer_size = 0;
933  hrd_initial_buffer_fullness = 0;
934  }
935 
936  if (rc_target_bitrate > UINT32_MAX ||
937  hrd_buffer_size > UINT32_MAX ||
938  hrd_initial_buffer_fullness > UINT32_MAX) {
939  av_log(avctx, AV_LOG_ERROR, "RC parameters of 2^32 or "
940  "greater are not supported by D3D12.\n");
941  return AVERROR(EINVAL);
942  }
943 
944  ctx->rc_quality = rc_quality;
945 
946  av_log(avctx, AV_LOG_VERBOSE, "RC mode: %s.\n", rc_mode->name);
947 
948  if (rc_mode->quality)
949  av_log(avctx, AV_LOG_VERBOSE, "RC quality: %d.\n", rc_quality);
950 
951  if (rc_mode->hrd) {
952  av_log(avctx, AV_LOG_VERBOSE, "RC buffer: %"PRId64" bits, "
953  "initial fullness %"PRId64" bits.\n",
954  hrd_buffer_size, hrd_initial_buffer_fullness);
955  }
956 
957  if (avctx->framerate.num > 0 && avctx->framerate.den > 0)
958  av_reduce(&fr_num, &fr_den,
959  avctx->framerate.num, avctx->framerate.den, 65535);
960  else
961  av_reduce(&fr_num, &fr_den,
962  avctx->time_base.den, avctx->time_base.num, 65535);
963 
964  av_log(avctx, AV_LOG_VERBOSE, "RC framerate: %d/%d (%.2f fps).\n",
965  fr_num, fr_den, (double)fr_num / fr_den);
966 
967  ctx->rc.Flags = D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_NONE;
968  ctx->rc.TargetFrameRate.Numerator = fr_num;
969  ctx->rc.TargetFrameRate.Denominator = fr_den;
970  ctx->rc.Mode = rc_mode->d3d12_mode;
971 
972  switch (rc_mode->mode) {
973  case RC_MODE_CQP:
974  // cqp ConfigParams will be updated in ctx->codec->configure.
975  break;
976  case RC_MODE_CBR: {
977  D3D12_VIDEO_ENCODER_RATE_CONTROL_CBR *cbr_ctl;
978 
979  ctx->rc.ConfigParams.DataSize = sizeof(D3D12_VIDEO_ENCODER_RATE_CONTROL_CBR);
980  cbr_ctl = av_mallocz(ctx->rc.ConfigParams.DataSize);
981  if (!cbr_ctl)
982  return AVERROR(ENOMEM);
983 
984  cbr_ctl->TargetBitRate = rc_target_bitrate;
985  cbr_ctl->VBVCapacity = hrd_buffer_size;
986  cbr_ctl->InitialVBVFullness = hrd_initial_buffer_fullness;
987  ctx->rc.Flags |= D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_VBV_SIZES;
988 
989  if (avctx->qmin > 0 || avctx->qmax > 0) {
990  cbr_ctl->MinQP = avctx->qmin;
991  cbr_ctl->MaxQP = avctx->qmax;
992  ctx->rc.Flags |= D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_QP_RANGE;
993  }
994 
995  if (ctx->max_frame_size > 0) {
996  cbr_ctl->MaxFrameBitSize = ctx->max_frame_size * 8;
997  ctx->rc.Flags |= D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_MAX_FRAME_SIZE;
998  }
999 
1000  ctx->rc.ConfigParams.pConfiguration_CBR = cbr_ctl;
1001  break;
1002  }
1003  case RC_MODE_VBR: {
1004  D3D12_VIDEO_ENCODER_RATE_CONTROL_VBR *vbr_ctl;
1005 
1006  ctx->rc.ConfigParams.DataSize = sizeof(D3D12_VIDEO_ENCODER_RATE_CONTROL_VBR);
1007  vbr_ctl = av_mallocz(ctx->rc.ConfigParams.DataSize);
1008  if (!vbr_ctl)
1009  return AVERROR(ENOMEM);
1010 
1011  vbr_ctl->TargetAvgBitRate = rc_target_bitrate;
1012  vbr_ctl->PeakBitRate = rc_peak_bitrate;
1013  vbr_ctl->VBVCapacity = hrd_buffer_size;
1014  vbr_ctl->InitialVBVFullness = hrd_initial_buffer_fullness;
1015  ctx->rc.Flags |= D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_VBV_SIZES;
1016 
1017  if (avctx->qmin > 0 || avctx->qmax > 0) {
1018  vbr_ctl->MinQP = avctx->qmin;
1019  vbr_ctl->MaxQP = avctx->qmax;
1020  ctx->rc.Flags |= D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_QP_RANGE;
1021  }
1022 
1023  if (ctx->max_frame_size > 0) {
1024  vbr_ctl->MaxFrameBitSize = ctx->max_frame_size * 8;
1025  ctx->rc.Flags |= D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_MAX_FRAME_SIZE;
1026  }
1027 
1028  ctx->rc.ConfigParams.pConfiguration_VBR = vbr_ctl;
1029  break;
1030  }
1031  case RC_MODE_QVBR: {
1032  D3D12_VIDEO_ENCODER_RATE_CONTROL_QVBR *qvbr_ctl;
1033 
1034  ctx->rc.ConfigParams.DataSize = sizeof(D3D12_VIDEO_ENCODER_RATE_CONTROL_QVBR);
1035  qvbr_ctl = av_mallocz(ctx->rc.ConfigParams.DataSize);
1036  if (!qvbr_ctl)
1037  return AVERROR(ENOMEM);
1038 
1039  qvbr_ctl->TargetAvgBitRate = rc_target_bitrate;
1040  qvbr_ctl->PeakBitRate = rc_peak_bitrate;
1041  qvbr_ctl->ConstantQualityTarget = rc_quality;
1042 
1043  if (avctx->qmin > 0 || avctx->qmax > 0) {
1044  qvbr_ctl->MinQP = avctx->qmin;
1045  qvbr_ctl->MaxQP = avctx->qmax;
1046  ctx->rc.Flags |= D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_QP_RANGE;
1047  }
1048 
1049  if (ctx->max_frame_size > 0) {
1050  qvbr_ctl->MaxFrameBitSize = ctx->max_frame_size * 8;
1051  ctx->rc.Flags |= D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_MAX_FRAME_SIZE;
1052  }
1053 
1054  ctx->rc.ConfigParams.pConfiguration_QVBR = qvbr_ctl;
1055  break;
1056  }
1057  default:
1058  break;
1059  }
1060  return 0;
1061 }
1062 
1064 {
1065  FFHWBaseEncodeContext *base_ctx = avctx->priv_data;
1067  uint32_t ref_l0, ref_l1;
1068  int err;
1069  HRESULT hr;
1070  D3D12_FEATURE_DATA_VIDEO_ENCODER_CODEC_PICTURE_CONTROL_SUPPORT support;
1071  union {
1072  D3D12_VIDEO_ENCODER_CODEC_PICTURE_CONTROL_SUPPORT_H264 h264;
1073  D3D12_VIDEO_ENCODER_CODEC_PICTURE_CONTROL_SUPPORT_HEVC hevc;
1074  } codec_support;
1075 
1076  support.NodeIndex = 0;
1077  support.Codec = ctx->codec->d3d12_codec;
1078  support.Profile = ctx->profile->d3d12_profile;
1079 
1080  switch (ctx->codec->d3d12_codec) {
1081  case D3D12_VIDEO_ENCODER_CODEC_H264:
1082  support.PictureSupport.DataSize = sizeof(codec_support.h264);
1083  support.PictureSupport.pH264Support = &codec_support.h264;
1084  break;
1085 
1086  case D3D12_VIDEO_ENCODER_CODEC_HEVC:
1087  support.PictureSupport.DataSize = sizeof(codec_support.hevc);
1088  support.PictureSupport.pHEVCSupport = &codec_support.hevc;
1089  break;
1090 
1091  default:
1092  av_assert0(0);
1093  }
1094 
1095  hr = ID3D12VideoDevice3_CheckFeatureSupport(ctx->video_device3, D3D12_FEATURE_VIDEO_ENCODER_CODEC_PICTURE_CONTROL_SUPPORT,
1096  &support, sizeof(support));
1097  if (FAILED(hr))
1098  return AVERROR(EINVAL);
1099 
1100  if (support.IsSupported) {
1101  switch (ctx->codec->d3d12_codec) {
1102  case D3D12_VIDEO_ENCODER_CODEC_H264:
1103  ref_l0 = FFMIN(support.PictureSupport.pH264Support->MaxL0ReferencesForP,
1104  support.PictureSupport.pH264Support->MaxL1ReferencesForB ?
1105  support.PictureSupport.pH264Support->MaxL1ReferencesForB : UINT_MAX);
1106  ref_l1 = support.PictureSupport.pH264Support->MaxL1ReferencesForB;
1107  break;
1108 
1109  case D3D12_VIDEO_ENCODER_CODEC_HEVC:
1110  ref_l0 = FFMIN(support.PictureSupport.pHEVCSupport->MaxL0ReferencesForP,
1111  support.PictureSupport.pHEVCSupport->MaxL1ReferencesForB ?
1112  support.PictureSupport.pHEVCSupport->MaxL1ReferencesForB : UINT_MAX);
1113  ref_l1 = support.PictureSupport.pHEVCSupport->MaxL1ReferencesForB;
1114  break;
1115 
1116  default:
1117  av_assert0(0);
1118  }
1119  } else {
1120  ref_l0 = ref_l1 = 0;
1121  }
1122 
1123  if (ref_l0 > 0 && ref_l1 > 0 && ctx->bi_not_empty) {
1124  base_ctx->p_to_gpb = 1;
1125  av_log(avctx, AV_LOG_VERBOSE, "Driver does not support P-frames, "
1126  "replacing them with B-frames.\n");
1127  }
1128 
1129  err = ff_hw_base_init_gop_structure(base_ctx, avctx, ref_l0, ref_l1, ctx->codec->flags, 0);
1130  if (err < 0)
1131  return err;
1132 
1133  return 0;
1134 }
1135 
1137 {
1138  FFHWBaseEncodeContext *base_ctx = avctx->priv_data;
1140  AVD3D12VAFramesContext *frames_hwctx = base_ctx->input_frames->hwctx;
1141  HRESULT hr;
1142 
1143  D3D12_VIDEO_ENCODER_DESC desc = {
1144  .NodeMask = 0,
1145  .Flags = D3D12_VIDEO_ENCODER_FLAG_NONE,
1146  .EncodeCodec = ctx->codec->d3d12_codec,
1147  .EncodeProfile = ctx->profile->d3d12_profile,
1148  .InputFormat = frames_hwctx->format,
1149  .CodecConfiguration = ctx->codec_conf,
1150  .MaxMotionEstimationPrecision = D3D12_VIDEO_ENCODER_MOTION_ESTIMATION_PRECISION_MODE_MAXIMUM,
1151  };
1152 
1153  hr = ID3D12VideoDevice3_CreateVideoEncoder(ctx->video_device3, &desc, &IID_ID3D12VideoEncoder,
1154  (void **)&ctx->encoder);
1155  if (FAILED(hr)) {
1156  av_log(avctx, AV_LOG_ERROR, "Failed to create encoder.\n");
1157  return AVERROR(EINVAL);
1158  }
1159 
1160  return 0;
1161 }
1162 
1164 {
1166  HRESULT hr;
1167 
1168  D3D12_VIDEO_ENCODER_HEAP_DESC desc = {
1169  .NodeMask = 0,
1170  .Flags = D3D12_VIDEO_ENCODER_HEAP_FLAG_NONE,
1171  .EncodeCodec = ctx->codec->d3d12_codec,
1172  .EncodeProfile = ctx->profile->d3d12_profile,
1173  .EncodeLevel = ctx->level,
1174  .ResolutionsListCount = 1,
1175  .pResolutionList = &ctx->resolution,
1176  };
1177 
1178  hr = ID3D12VideoDevice3_CreateVideoEncoderHeap(ctx->video_device3, &desc,
1179  &IID_ID3D12VideoEncoderHeap, (void **)&ctx->encoder_heap);
1180  if (FAILED(hr)) {
1181  av_log(avctx, AV_LOG_ERROR, "Failed to create encoder heap.\n");
1182  return AVERROR(EINVAL);
1183  }
1184 
1185  return 0;
1186 }
1187 
1188 static void d3d12va_encode_free_buffer(void *opaque, uint8_t *data)
1189 {
1190  ID3D12Resource *pResource;
1191 
1192  pResource = (ID3D12Resource *)data;
1193  D3D12_OBJECT_RELEASE(pResource);
1194 }
1195 
1197 {
1198  AVCodecContext *avctx = opaque;
1199  FFHWBaseEncodeContext *base_ctx = avctx->priv_data;
1201  ID3D12Resource *pResource = NULL;
1202  HRESULT hr;
1203  AVBufferRef *ref;
1204  D3D12_HEAP_PROPERTIES heap_props;
1205  D3D12_HEAP_TYPE heap_type = D3D12_HEAP_TYPE_READBACK;
1206 
1207  D3D12_RESOURCE_DESC desc = {
1208  .Dimension = D3D12_RESOURCE_DIMENSION_BUFFER,
1209  .Alignment = 0,
1210  .Width = FFALIGN(3 * base_ctx->surface_width * base_ctx->surface_height + (1 << 16),
1211  D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT),
1212  .Height = 1,
1213  .DepthOrArraySize = 1,
1214  .MipLevels = 1,
1215  .Format = DXGI_FORMAT_UNKNOWN,
1216  .SampleDesc = { .Count = 1, .Quality = 0 },
1217  .Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR,
1218  .Flags = D3D12_RESOURCE_FLAG_NONE,
1219  };
1220 
1221  ctx->hwctx->device->lpVtbl->GetCustomHeapProperties(ctx->hwctx->device, &heap_props, 0, heap_type);
1222 
1223  hr = ID3D12Device_CreateCommittedResource(ctx->hwctx->device, &heap_props, D3D12_HEAP_FLAG_NONE,
1224  &desc, D3D12_RESOURCE_STATE_COMMON, NULL, &IID_ID3D12Resource,
1225  (void **)&pResource);
1226 
1227  if (FAILED(hr)) {
1228  av_log(avctx, AV_LOG_ERROR, "Failed to create d3d12 buffer.\n");
1229  return NULL;
1230  }
1231 
1232  ref = av_buffer_create((uint8_t *)(uintptr_t)pResource,
1233  sizeof(pResource),
1235  avctx, AV_BUFFER_FLAG_READONLY);
1236  if (!ref) {
1237  D3D12_OBJECT_RELEASE(pResource);
1238  return NULL;
1239  }
1240 
1241  return ref;
1242 }
1243 
1245 {
1246  FFHWBaseEncodeContext *base_ctx = avctx->priv_data;
1248  AVD3D12VAFramesContext *frames_ctx = base_ctx->input_frames->hwctx;
1249  HRESULT hr;
1250 
1251  ctx->req.NodeIndex = 0;
1252  ctx->req.Codec = ctx->codec->d3d12_codec;
1253  ctx->req.Profile = ctx->profile->d3d12_profile;
1254  ctx->req.InputFormat = frames_ctx->format;
1255  ctx->req.PictureTargetResolution = ctx->resolution;
1256 
1257  hr = ID3D12VideoDevice3_CheckFeatureSupport(ctx->video_device3,
1258  D3D12_FEATURE_VIDEO_ENCODER_RESOURCE_REQUIREMENTS,
1259  &ctx->req, sizeof(ctx->req));
1260  if (FAILED(hr)) {
1261  av_log(avctx, AV_LOG_ERROR, "Failed to check encoder resource requirements support.\n");
1262  return AVERROR(EINVAL);
1263  }
1264 
1265  if (!ctx->req.IsSupported) {
1266  av_log(avctx, AV_LOG_ERROR, "Encoder resource requirements unsupported.\n");
1267  return AVERROR(EINVAL);
1268  }
1269 
1270  ctx->output_buffer_pool = av_buffer_pool_init2(sizeof(ID3D12Resource *), avctx,
1272  if (!ctx->output_buffer_pool)
1273  return AVERROR(ENOMEM);
1274 
1275  return 0;
1276 }
1277 
1279 {
1281  ID3D12CommandAllocator *command_allocator = NULL;
1282  int err = AVERROR_UNKNOWN;
1283  HRESULT hr;
1284 
1285  D3D12_COMMAND_QUEUE_DESC queue_desc = {
1286  .Type = D3D12_COMMAND_LIST_TYPE_VIDEO_ENCODE,
1287  .Priority = 0,
1288  .Flags = D3D12_COMMAND_QUEUE_FLAG_NONE,
1289  .NodeMask = 0,
1290  };
1291 
1294  if (!ctx->allocator_queue)
1295  return AVERROR(ENOMEM);
1296 
1297  hr = ID3D12Device_CreateFence(ctx->hwctx->device, 0, D3D12_FENCE_FLAG_NONE,
1298  &IID_ID3D12Fence, (void **)&ctx->sync_ctx.fence);
1299  if (FAILED(hr)) {
1300  av_log(avctx, AV_LOG_ERROR, "Failed to create fence(%lx)\n", (long)hr);
1301  err = AVERROR_UNKNOWN;
1302  goto fail;
1303  }
1304 
1305  ctx->sync_ctx.event = CreateEvent(NULL, FALSE, FALSE, NULL);
1306  if (!ctx->sync_ctx.event)
1307  goto fail;
1308 
1309  err = d3d12va_get_valid_command_allocator(avctx, &command_allocator);
1310  if (err < 0)
1311  goto fail;
1312 
1313  hr = ID3D12Device_CreateCommandQueue(ctx->hwctx->device, &queue_desc,
1314  &IID_ID3D12CommandQueue, (void **)&ctx->command_queue);
1315  if (FAILED(hr)) {
1316  av_log(avctx, AV_LOG_ERROR, "Failed to create command queue(%lx)\n", (long)hr);
1317  err = AVERROR_UNKNOWN;
1318  goto fail;
1319  }
1320 
1321  hr = ID3D12Device_CreateCommandList(ctx->hwctx->device, 0, queue_desc.Type,
1322  command_allocator, NULL, &IID_ID3D12CommandList,
1323  (void **)&ctx->command_list);
1324  if (FAILED(hr)) {
1325  av_log(avctx, AV_LOG_ERROR, "Failed to create command list(%lx)\n", (long)hr);
1326  err = AVERROR_UNKNOWN;
1327  goto fail;
1328  }
1329 
1330  hr = ID3D12VideoEncodeCommandList2_Close(ctx->command_list);
1331  if (FAILED(hr)) {
1332  av_log(avctx, AV_LOG_ERROR, "Failed to close the command list(%lx)\n", (long)hr);
1333  err = AVERROR_UNKNOWN;
1334  goto fail;
1335  }
1336 
1337  ID3D12CommandQueue_ExecuteCommandLists(ctx->command_queue, 1, (ID3D12CommandList **)&ctx->command_list);
1338 
1339  err = d3d12va_sync_with_gpu(avctx);
1340  if (err < 0)
1341  goto fail;
1342 
1343  err = d3d12va_discard_command_allocator(avctx, command_allocator, ctx->sync_ctx.fence_value);
1344  if (err < 0)
1345  goto fail;
1346 
1347  return 0;
1348 
1349 fail:
1350  D3D12_OBJECT_RELEASE(command_allocator);
1351  return err;
1352 }
1353 
1355 {
1356  FFHWBaseEncodeContext *base_ctx = avctx->priv_data;
1357  AVD3D12VAFramesContext *hwctx;
1358  enum AVPixelFormat recon_format;
1359  int err;
1360 
1361  err = ff_hw_base_get_recon_format(base_ctx, NULL, &recon_format);
1362  if (err < 0)
1363  return err;
1364 
1365  base_ctx->recon_frames_ref = av_hwframe_ctx_alloc(base_ctx->device_ref);
1366  if (!base_ctx->recon_frames_ref)
1367  return AVERROR(ENOMEM);
1368 
1369  base_ctx->recon_frames = (AVHWFramesContext *)base_ctx->recon_frames_ref->data;
1370  hwctx = (AVD3D12VAFramesContext *)base_ctx->recon_frames->hwctx;
1371 
1372  base_ctx->recon_frames->format = AV_PIX_FMT_D3D12;
1373  base_ctx->recon_frames->sw_format = recon_format;
1374  base_ctx->recon_frames->width = base_ctx->surface_width;
1375  base_ctx->recon_frames->height = base_ctx->surface_height;
1376 
1377  hwctx->flags = D3D12_RESOURCE_FLAG_VIDEO_ENCODE_REFERENCE_ONLY |
1378  D3D12_RESOURCE_FLAG_DENY_SHADER_RESOURCE;
1379 
1380  err = av_hwframe_ctx_init(base_ctx->recon_frames_ref);
1381  if (err < 0) {
1382  av_log(avctx, AV_LOG_ERROR, "Failed to initialise reconstructed "
1383  "frame context: %d.\n", err);
1384  return err;
1385  }
1386 
1387  return 0;
1388 }
1389 
1391  .priv_size = sizeof(D3D12VAEncodePicture),
1392 
1394 
1395  .issue = &d3d12va_encode_issue,
1396 
1398 
1399  .free = &d3d12va_encode_free,
1400 };
1401 
1403 {
1404  return ff_hw_base_encode_receive_packet(avctx->priv_data, avctx, pkt);
1405 }
1406 
1408 {
1409  FFHWBaseEncodeContext *base_ctx = avctx->priv_data;
1411  D3D12_FEATURE_DATA_VIDEO_FEATURE_AREA_SUPPORT support = { 0 };
1412  int err;
1413  HRESULT hr;
1414 
1415  err = ff_hw_base_encode_init(avctx, base_ctx);
1416  if (err < 0)
1417  goto fail;
1418 
1419  base_ctx->op = &d3d12va_type;
1420 
1421  ctx->hwctx = base_ctx->device->hwctx;
1422 
1423  ctx->resolution.Width = base_ctx->input_frames->width;
1424  ctx->resolution.Height = base_ctx->input_frames->height;
1425 
1426  hr = ID3D12Device_QueryInterface(ctx->hwctx->device, &IID_ID3D12Device3, (void **)&ctx->device3);
1427  if (FAILED(hr)) {
1428  av_log(avctx, AV_LOG_ERROR, "ID3D12Device3 interface is not supported.\n");
1429  err = AVERROR_UNKNOWN;
1430  goto fail;
1431  }
1432 
1433  hr = ID3D12Device3_QueryInterface(ctx->device3, &IID_ID3D12VideoDevice3, (void **)&ctx->video_device3);
1434  if (FAILED(hr)) {
1435  av_log(avctx, AV_LOG_ERROR, "ID3D12VideoDevice3 interface is not supported.\n");
1436  err = AVERROR_UNKNOWN;
1437  goto fail;
1438  }
1439 
1440  if (FAILED(ID3D12VideoDevice3_CheckFeatureSupport(ctx->video_device3, D3D12_FEATURE_VIDEO_FEATURE_AREA_SUPPORT,
1441  &support, sizeof(support))) && !support.VideoEncodeSupport) {
1442  av_log(avctx, AV_LOG_ERROR, "D3D12 video device has no video encoder support.\n");
1443  err = AVERROR(EINVAL);
1444  goto fail;
1445  }
1446 
1447  err = d3d12va_encode_set_profile(avctx);
1448  if (err < 0)
1449  goto fail;
1450 
1451  err = d3d12va_encode_init_rate_control(avctx);
1452  if (err < 0)
1453  goto fail;
1454 
1455  if (ctx->codec->get_encoder_caps) {
1456  err = ctx->codec->get_encoder_caps(avctx);
1457  if (err < 0)
1458  goto fail;
1459  }
1460 
1461  err = d3d12va_encode_init_gop_structure(avctx);
1462  if (err < 0)
1463  goto fail;
1464 
1465  if (!(ctx->codec->flags & FF_HW_FLAG_SLICE_CONTROL) && avctx->slices > 0) {
1466  av_log(avctx, AV_LOG_WARNING, "Multiple slices were requested "
1467  "but this codec does not support controlling slices.\n");
1468  }
1469 
1471  if (err < 0)
1472  goto fail;
1473 
1475  if (err < 0)
1476  goto fail;
1477 
1479  if (err < 0)
1480  goto fail;
1481 
1482  if (ctx->codec->configure) {
1483  err = ctx->codec->configure(avctx);
1484  if (err < 0)
1485  goto fail;
1486  }
1487 
1488  if (ctx->codec->init_sequence_params) {
1489  err = ctx->codec->init_sequence_params(avctx);
1490  if (err < 0) {
1491  av_log(avctx, AV_LOG_ERROR, "Codec sequence initialisation "
1492  "failed: %d.\n", err);
1493  goto fail;
1494  }
1495  }
1496 
1497  if (ctx->codec->set_level) {
1498  err = ctx->codec->set_level(avctx);
1499  if (err < 0)
1500  goto fail;
1501  }
1502 
1503  base_ctx->output_delay = base_ctx->b_per_p;
1504  base_ctx->decode_delay = base_ctx->max_b_depth;
1505 
1506  err = d3d12va_create_encoder(avctx);
1507  if (err < 0)
1508  goto fail;
1509 
1510  err = d3d12va_create_encoder_heap(avctx);
1511  if (err < 0)
1512  goto fail;
1513 
1514  base_ctx->async_encode = 1;
1515  base_ctx->encode_fifo = av_fifo_alloc2(base_ctx->async_depth,
1516  sizeof(D3D12VAEncodePicture *), 0);
1517  if (!base_ctx->encode_fifo)
1518  return AVERROR(ENOMEM);
1519 
1520  return 0;
1521 
1522 fail:
1523  return err;
1524 }
1525 
1527 {
1528  int num_allocator = 0;
1529  FFHWBaseEncodeContext *base_ctx = avctx->priv_data;
1531  FFHWBaseEncodePicture *pic, *next;
1532  CommandAllocator allocator;
1533 
1534  if (!base_ctx->frame)
1535  return 0;
1536 
1537  for (pic = base_ctx->pic_start; pic; pic = next) {
1538  next = pic->next;
1539  d3d12va_encode_free(avctx, pic);
1540  }
1541 
1543 
1544  av_buffer_pool_uninit(&ctx->output_buffer_pool);
1545 
1546  D3D12_OBJECT_RELEASE(ctx->command_list);
1547  D3D12_OBJECT_RELEASE(ctx->command_queue);
1548 
1549  if (ctx->allocator_queue) {
1550  while (av_fifo_read(ctx->allocator_queue, &allocator, 1) >= 0) {
1551  num_allocator++;
1553  }
1554 
1555  av_log(avctx, AV_LOG_VERBOSE, "Total number of command allocators reused: %d\n", num_allocator);
1556  }
1557 
1558  av_fifo_freep2(&ctx->allocator_queue);
1559 
1560  D3D12_OBJECT_RELEASE(ctx->sync_ctx.fence);
1561  if (ctx->sync_ctx.event)
1562  CloseHandle(ctx->sync_ctx.event);
1563 
1564  D3D12_OBJECT_RELEASE(ctx->encoder_heap);
1565  D3D12_OBJECT_RELEASE(ctx->encoder);
1566  D3D12_OBJECT_RELEASE(ctx->video_device3);
1567  D3D12_OBJECT_RELEASE(ctx->device3);
1568 
1569  ff_hw_base_encode_close(base_ctx);
1570 
1571  return 0;
1572 }
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
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
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:690
AVERROR
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFrame structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample they are references to shared objects When the negotiation mechanism computes the intersection of the formats supported at each end of a all references to both lists are replaced with a reference to the intersection And when a single format is eventually chosen for a link amongst the remaining all references to the list are updated That means that if a filter requires that its input and output have the same format amongst a supported all it has to do is use a reference to the same list of formats query_formats can leave some formats unset and return AVERROR(EAGAIN) to cause the negotiation mechanism toagain later. That can be used by filters with complex requirements to use the format negotiated on one link to set the formats supported on another. Frame references ownership and permissions
FFHWBaseEncodePicture::priv
void * priv
Definition: hw_base_encode.h:63
FFHWBaseEncodePicture::codec_priv
void * codec_priv
Definition: hw_base_encode.h:65
av_pix_fmt_desc_get
const AVPixFmtDescriptor * av_pix_fmt_desc_get(enum AVPixelFormat pix_fmt)
Definition: pixdesc.c:3447
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:1354
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:558
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:623
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
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
AVCodecContext::qmax
int qmax
maximum quantizer
Definition: avcodec.h:1241
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:551
d3d12va_encode_output
static int d3d12va_encode_output(AVCodecContext *avctx, FFHWBaseEncodePicture *base_pic, AVPacket *pkt)
Definition: d3d12va_encode.c:665
ff_d3d12va_encode_hw_configs
const AVCodecHWConfigInternal *const ff_d3d12va_encode_hw_configs[]
Definition: d3d12va_encode.c:36
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:574
d3d12va_sync_with_gpu
static int d3d12va_sync_with_gpu(AVCodecContext *avctx)
Definition: d3d12va_encode.c:54
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:200
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:66
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:488
FFHWBaseEncodePicture::input_image
AVFrame * input_image
Definition: hw_base_encode.h:83
CommandAllocator::fence_value
uint64_t fence_value
Definition: d3d12va_encode.c:67
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:743
check_rate_control_support
static int check_rate_control_support(AVCodecContext *avctx, const D3D12VAEncodeRCMode *rc_mode)
Definition: d3d12va_encode.c:753
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:588
pkt
AVPacket * pkt
Definition: movenc.c:60
AV_LOG_ERROR
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:210
AV_PROFILE_UNKNOWN
#define AV_PROFILE_UNKNOWN
Definition: defs.h:65
d3d12va_encode_wait
static int d3d12va_encode_wait(AVCodecContext *avctx, FFHWBaseEncodePicture *base_pic)
Definition: d3d12va_encode.c:109
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:1298
AVHWFramesContext::height
int height
Definition: hwcontext.h:220
d3d12va_encode_issue
static int d3d12va_encode_issue(AVCodecContext *avctx, FFHWBaseEncodePicture *base_pic)
Definition: d3d12va_encode.c:188
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:1217
D3D12_OBJECT_RELEASE
#define D3D12_OBJECT_RELEASE(pInterface)
A release macro used by D3D12 objects highly frequently.
Definition: hwcontext_d3d12va_internal.h:51
D3D12VAEncodePicture::header_size
int header_size
Definition: d3d12va_encode.h:43
AV_BUFFER_FLAG_READONLY
#define AV_BUFFER_FLAG_READONLY
Always treat the buffer as read-only, even when it has only one reference.
Definition: buffer.h:114
AVFormatContext::flags
int flags
Flags modifying the (de)muxer behaviour.
Definition: avformat.h:1415
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:119
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:1163
AV_LOG_DEBUG
#define AV_LOG_DEBUG
Stuff which is only useful for libav* developers.
Definition: log.h:231
ctx
AVFormatContext * ctx
Definition: movenc.c:49
D3D12VAEncodePicture::pic_ctl
D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA pic_ctl
Definition: d3d12va_encode.h:55
AVD3D12VASyncContext
This struct is used to sync d3d12 execution.
Definition: hwcontext_d3d12va.h:84
d3d12va_encode_discard
static int d3d12va_encode_discard(AVCodecContext *avctx, FFHWBaseEncodePicture *base_pic)
Definition: d3d12va_encode.c:510
AVCodecContext::rc_max_rate
int64_t rc_max_rate
maximum bitrate
Definition: avcodec.h:1270
AVD3D12VASyncContext::fence
ID3D12Fence * fence
D3D12 fence object.
Definition: hwcontext_d3d12va.h:88
D3D12VAEncodeRCMode
Definition: d3d12va_encode.h:102
FFHWBaseEncodeContext::pic_start
FFHWBaseEncodePicture * pic_start
Definition: hw_base_encode.h:160
FFHWBaseEncodeContext::b_per_p
int b_per_p
Definition: hw_base_encode.h:189
AVCodecContext::rc_buffer_size
int rc_buffer_size
decoder bitstream buffer size
Definition: avcodec.h:1255
d3d12va_discard_command_allocator
static int d3d12va_discard_command_allocator(AVCodecContext *avctx, ID3D12CommandAllocator *pAllocator, uint64_t fence_value)
Definition: d3d12va_encode.c:95
D3D12VAEncodePicture::fence_value
int fence_value
Definition: d3d12va_encode.h:57
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
MAX_PARAM_BUFFER_SIZE
@ MAX_PARAM_BUFFER_SIZE
Definition: vaapi_encode.h:47
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:481
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:126
FF_HW_FLAG_CONSTANT_QUALITY_ONLY
@ FF_HW_FLAG_CONSTANT_QUALITY_ONLY
Definition: hw_base_encode.h:49
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:112
hwcontext_d3d12va.h
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
AVD3D12VAFramesContext::flags
D3D12_RESOURCE_FLAGS flags
Options for working with resources.
Definition: hwcontext_d3d12va.h:139
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:535
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:1188
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:142
FFHWBaseEncodeContext::frame
AVFrame * frame
Definition: hw_base_encode.h:211
init
int(* init)(AVBSFContext *ctx)
Definition: dts2pts.c:368
d3d12va_get_valid_command_allocator
static int d3d12va_get_valid_command_allocator(AVCodecContext *avctx, ID3D12CommandAllocator **ppAllocator)
Definition: d3d12va_encode.c:70
d3d12va_encode_create_command_objects
static int d3d12va_encode_create_command_objects(AVCodecContext *avctx)
Definition: d3d12va_encode.c:1278
ff_d3d12va_encode_init
int ff_d3d12va_encode_init(AVCodecContext *avctx)
Definition: d3d12va_encode.c:1407
FFHWBaseEncodePicture::nb_refs
int nb_refs[MAX_REFERENCE_LIST_NUM]
Definition: hw_base_encode.h:97
CommandAllocator
Definition: d3d12va_encode.c:65
d3d12va_type
static const FFHWEncodePictureOperation d3d12va_type
Definition: d3d12va_encode.c:1390
D3D12VAEncodeProfile
Definition: d3d12va_encode.h:60
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
AVCodecHWConfigInternal
Definition: hwconfig.h:25
FFHWBaseEncodeContext::p_to_gpb
int p_to_gpb
Definition: hw_base_encode.h:194
FF_HW_FLAG_SLICE_CONTROL
@ FF_HW_FLAG_SLICE_CONTROL
Definition: hw_base_encode.h:47
FFHWBaseEncodePicture::encode_order
int64_t encode_order
Definition: hw_base_encode.h:70
AVD3D12VAFrame
D3D12VA frame descriptor for pool allocation.
Definition: hwcontext_d3d12va.h:106
RC_MODE_QVBR
@ RC_MODE_QVBR
Definition: d3d12va_encode.h:97
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:1196
HW_CONFIG_ENCODER_FRAMES
#define HW_CONFIG_ENCODER_FRAMES(format, device_type_)
Definition: hwconfig.h:98
d3d12va_encode_init
static int d3d12va_encode_init(AVCodecContext *avctx, FFHWBaseEncodePicture *pic)
Definition: d3d12va_encode.c:557
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
internal.h
TRY_RC_MODE
#define TRY_RC_MODE(mode, fail)
RC_MODE_VBR
@ RC_MODE_VBR
Definition: d3d12va_encode.h:96
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:41
av_mallocz
void * av_mallocz(size_t size)
Allocate a memory block with alignment suitable for all memory accesses (including vectors if availab...
Definition: mem.c:256
profile
int profile
Definition: mxfenc.c:2278
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:1136
avcodec.h
AVD3D12VAFramesContext::format
DXGI_FORMAT format
DXGI_FORMAT format.
Definition: hwcontext_d3d12va.h:131
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:778
FFHWBaseEncodePicture
Definition: hw_base_encode.h:61
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:144
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
SIZE_SPECIFIER
#define SIZE_SPECIFIER
Definition: internal.h:129
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:1244
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:431
AVD3D12VASyncContext::event
HANDLE event
A handle to the event object that's raised when the fence reaches a certain value.
Definition: hwcontext_d3d12va.h:94
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:106
AVCodecContext::qmin
int qmin
minimum quantizer
Definition: avcodec.h:1234
AVRational::den
int den
Denominator.
Definition: rational.h:60
AVCodecContext::profile
int profile
profile
Definition: avcodec.h:1618
d3d12va_encode_free_rc_params
static int d3d12va_encode_free_rc_params(AVCodecContext *avctx)
Definition: d3d12va_encode.c:532
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
TRANSITION_BARRIER
#define TRANSITION_BARRIER(res, before, after)
FFHWBaseEncodeContext::surface_width
int surface_width
Definition: hw_base_encode.h:140
desc
const char * desc
Definition: libsvtav1.c:79
FF_HW_PICTURE_TYPE_IDR
@ FF_HW_PICTURE_TYPE_IDR
Definition: hw_base_encode.h:39
FFHWBaseEncodePicture::encode_complete
int encode_complete
Definition: hw_base_encode.h:81
mem.h
AVBufferRef
A reference to a data buffer.
Definition: buffer.h:82
AVPixFmtDescriptor
Descriptor that unambiguously describes how the bits of a pixel are stored in the up to 4 data planes...
Definition: pixdesc.h:69
ff_d3d12va_encode_close
int ff_d3d12va_encode_close(AVCodecContext *avctx)
Definition: d3d12va_encode.c:1526
FFALIGN
#define FFALIGN(x, a)
Definition: macros.h:78
AVCodecContext::slices
int slices
Number of slices.
Definition: avcodec.h:1021
ff_d3d12va_encode_receive_packet
int ff_d3d12va_encode_receive_packet(AVCodecContext *avctx, AVPacket *pkt)
Definition: d3d12va_encode.c:1402
AVPacket
This structure stores compressed data.
Definition: packet.h:535
AVCodecContext::priv_data
void * priv_data
Definition: avcodec.h:458
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:1063
FFHWBaseEncodeContext::recon_frames
AVHWFramesContext * recon_frames
Definition: hw_base_encode.h:157
DX_CHECK
#define DX_CHECK(hr)
A check macro used by D3D12 functions highly frequently.
Definition: hwcontext_d3d12va_internal.h:40
av_log
#define av_log(a,...)
Definition: tableprint_vlc.h:27
av_fifo_freep2
void av_fifo_freep2(AVFifo **f)
Free an AVFifo and reset pointer to NULL.
Definition: fifo.c:286
AVD3D12VASyncContext::fence_value
uint64_t fence_value
The fence value used for sync.
Definition: hwcontext_d3d12va.h:99
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:143
hwcontext_d3d12va_internal.h
FFHWBaseEncodePicture::display_order
int64_t display_order
Definition: hw_base_encode.h:69
AV_FIFO_FLAG_AUTO_GROW
#define AV_FIFO_FLAG_AUTO_GROW
Automatically resize the FIFO on writes, so that the data fits.
Definition: fifo.h:63
RC_MODE_CQP
@ RC_MODE_CQP
Definition: d3d12va_encode.h:94
RC_MODE_CBR
@ RC_MODE_CBR
Definition: d3d12va_encode.h:95