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  }
303 
304  pic->header_size = (int)bit_len / 8;
305  pic->aligned_header_size = pic->header_size % ctx->req.CompressedBitstreamBufferAccessAlignment ?
306  FFALIGN(pic->header_size, ctx->req.CompressedBitstreamBufferAccessAlignment) :
307  pic->header_size;
308 
309  hr = ID3D12Resource_Map(pic->output_buffer, 0, NULL, (void **)&ptr);
310  if (FAILED(hr)) {
311  err = AVERROR_UNKNOWN;
312  goto fail;
313  }
314 
315  memcpy(ptr, data, pic->aligned_header_size);
316  ID3D12Resource_Unmap(pic->output_buffer, 0, NULL);
317  }
318 
319  d3d12_refs.NumTexture2Ds = base_pic->nb_refs[0] + base_pic->nb_refs[1];
320  if (d3d12_refs.NumTexture2Ds) {
321  d3d12_refs.ppTexture2Ds = av_calloc(d3d12_refs.NumTexture2Ds,
322  sizeof(*d3d12_refs.ppTexture2Ds));
323  if (!d3d12_refs.ppTexture2Ds) {
324  err = AVERROR(ENOMEM);
325  goto fail;
326  }
327 
328  i = 0;
329  for (j = 0; j < base_pic->nb_refs[0]; j++)
330  d3d12_refs.ppTexture2Ds[i++] = ((D3D12VAEncodePicture *)base_pic->refs[0][j]->priv)->recon_surface->texture;
331  for (j = 0; j < base_pic->nb_refs[1]; j++)
332  d3d12_refs.ppTexture2Ds[i++] = ((D3D12VAEncodePicture *)base_pic->refs[1][j]->priv)->recon_surface->texture;
333  }
334 
335  input_args.PictureControlDesc.IntraRefreshFrameIndex = 0;
336  if (base_pic->is_reference)
337  input_args.PictureControlDesc.Flags |= D3D12_VIDEO_ENCODER_PICTURE_CONTROL_FLAG_USED_AS_REFERENCE_PICTURE;
338 
339  input_args.PictureControlDesc.PictureControlCodecData = pic->pic_ctl;
340  input_args.PictureControlDesc.ReferenceFrames = d3d12_refs;
341  input_args.CurrentFrameBitstreamMetadataSize = pic->aligned_header_size;
342 
343  output_args.Bitstream.pBuffer = pic->output_buffer;
344  output_args.Bitstream.FrameStartOffset = pic->aligned_header_size;
345  output_args.ReconstructedPicture.pReconstructedPicture = pic->recon_surface->texture;
346  output_args.ReconstructedPicture.ReconstructedPictureSubresource = 0;
347  output_args.EncoderOutputMetadata.pBuffer = pic->encoded_metadata;
348  output_args.EncoderOutputMetadata.Offset = 0;
349 
350  input_metadata.HWLayoutMetadata.pBuffer = pic->encoded_metadata;
351  input_metadata.HWLayoutMetadata.Offset = 0;
352 
353  output_metadata.ResolvedLayoutMetadata.pBuffer = pic->resolved_metadata;
354  output_metadata.ResolvedLayoutMetadata.Offset = 0;
355 
356  err = d3d12va_get_valid_command_allocator(avctx, &command_allocator);
357  if (err < 0)
358  goto fail;
359 
360  hr = ID3D12CommandAllocator_Reset(command_allocator);
361  if (FAILED(hr)) {
362  err = AVERROR_UNKNOWN;
363  goto fail;
364  }
365 
366  hr = ID3D12VideoEncodeCommandList2_Reset(cmd_list, command_allocator);
367  if (FAILED(hr)) {
368  err = AVERROR_UNKNOWN;
369  goto fail;
370  }
371 
372 #define TRANSITION_BARRIER(res, before, after) \
373  (D3D12_RESOURCE_BARRIER) { \
374  .Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION, \
375  .Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE, \
376  .Transition = { \
377  .pResource = res, \
378  .Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES, \
379  .StateBefore = before, \
380  .StateAfter = after, \
381  }, \
382  }
383 
384  barriers[0] = TRANSITION_BARRIER(pic->input_surface->texture,
385  D3D12_RESOURCE_STATE_COMMON,
386  D3D12_RESOURCE_STATE_VIDEO_ENCODE_READ);
387  barriers[1] = TRANSITION_BARRIER(pic->output_buffer,
388  D3D12_RESOURCE_STATE_COMMON,
389  D3D12_RESOURCE_STATE_VIDEO_ENCODE_WRITE);
390  barriers[2] = TRANSITION_BARRIER(pic->recon_surface->texture,
391  D3D12_RESOURCE_STATE_COMMON,
392  D3D12_RESOURCE_STATE_VIDEO_ENCODE_WRITE);
393  barriers[3] = TRANSITION_BARRIER(pic->encoded_metadata,
394  D3D12_RESOURCE_STATE_COMMON,
395  D3D12_RESOURCE_STATE_VIDEO_ENCODE_WRITE);
396  barriers[4] = TRANSITION_BARRIER(pic->resolved_metadata,
397  D3D12_RESOURCE_STATE_COMMON,
398  D3D12_RESOURCE_STATE_VIDEO_ENCODE_WRITE);
399 
400  ID3D12VideoEncodeCommandList2_ResourceBarrier(cmd_list, 5, barriers);
401 
402  if (d3d12_refs.NumTexture2Ds) {
403  D3D12_RESOURCE_BARRIER refs_barriers[3];
404 
405  for (i = 0; i < d3d12_refs.NumTexture2Ds; i++)
406  refs_barriers[i] = TRANSITION_BARRIER(d3d12_refs.ppTexture2Ds[i],
407  D3D12_RESOURCE_STATE_COMMON,
408  D3D12_RESOURCE_STATE_VIDEO_ENCODE_READ);
409 
410  ID3D12VideoEncodeCommandList2_ResourceBarrier(cmd_list, d3d12_refs.NumTexture2Ds,
411  refs_barriers);
412  }
413 
414  ID3D12VideoEncodeCommandList2_EncodeFrame(cmd_list, ctx->encoder, ctx->encoder_heap,
415  &input_args, &output_args);
416 
417  barriers[3] = TRANSITION_BARRIER(pic->encoded_metadata,
418  D3D12_RESOURCE_STATE_VIDEO_ENCODE_WRITE,
419  D3D12_RESOURCE_STATE_VIDEO_ENCODE_READ);
420 
421  ID3D12VideoEncodeCommandList2_ResourceBarrier(cmd_list, 1, &barriers[3]);
422 
423  ID3D12VideoEncodeCommandList2_ResolveEncoderOutputMetadata(cmd_list, &input_metadata, &output_metadata);
424 
425  if (d3d12_refs.NumTexture2Ds) {
426  D3D12_RESOURCE_BARRIER refs_barriers[3];
427 
428  for (i = 0; i < d3d12_refs.NumTexture2Ds; i++)
429  refs_barriers[i] = TRANSITION_BARRIER(d3d12_refs.ppTexture2Ds[i],
430  D3D12_RESOURCE_STATE_VIDEO_ENCODE_READ,
431  D3D12_RESOURCE_STATE_COMMON);
432 
433  ID3D12VideoEncodeCommandList2_ResourceBarrier(cmd_list, d3d12_refs.NumTexture2Ds,
434  refs_barriers);
435  }
436 
437  barriers[0] = TRANSITION_BARRIER(pic->input_surface->texture,
438  D3D12_RESOURCE_STATE_VIDEO_ENCODE_READ,
439  D3D12_RESOURCE_STATE_COMMON);
440  barriers[1] = TRANSITION_BARRIER(pic->output_buffer,
441  D3D12_RESOURCE_STATE_VIDEO_ENCODE_WRITE,
442  D3D12_RESOURCE_STATE_COMMON);
443  barriers[2] = TRANSITION_BARRIER(pic->recon_surface->texture,
444  D3D12_RESOURCE_STATE_VIDEO_ENCODE_WRITE,
445  D3D12_RESOURCE_STATE_COMMON);
446  barriers[3] = TRANSITION_BARRIER(pic->encoded_metadata,
447  D3D12_RESOURCE_STATE_VIDEO_ENCODE_READ,
448  D3D12_RESOURCE_STATE_COMMON);
449  barriers[4] = TRANSITION_BARRIER(pic->resolved_metadata,
450  D3D12_RESOURCE_STATE_VIDEO_ENCODE_WRITE,
451  D3D12_RESOURCE_STATE_COMMON);
452 
453  ID3D12VideoEncodeCommandList2_ResourceBarrier(cmd_list, 5, barriers);
454 
455  hr = ID3D12VideoEncodeCommandList2_Close(cmd_list);
456  if (FAILED(hr)) {
457  err = AVERROR_UNKNOWN;
458  goto fail;
459  }
460 
461  hr = ID3D12CommandQueue_Wait(ctx->command_queue, pic->input_surface->sync_ctx.fence,
463  if (FAILED(hr)) {
464  err = AVERROR_UNKNOWN;
465  goto fail;
466  }
467 
468  ID3D12CommandQueue_ExecuteCommandLists(ctx->command_queue, 1, (ID3D12CommandList **)&ctx->command_list);
469 
470  hr = ID3D12CommandQueue_Signal(ctx->command_queue, pic->input_surface->sync_ctx.fence,
472  if (FAILED(hr)) {
473  err = AVERROR_UNKNOWN;
474  goto fail;
475  }
476 
477  hr = ID3D12CommandQueue_Signal(ctx->command_queue, ctx->sync_ctx.fence, ++ctx->sync_ctx.fence_value);
478  if (FAILED(hr)) {
479  err = AVERROR_UNKNOWN;
480  goto fail;
481  }
482 
483  err = d3d12va_discard_command_allocator(avctx, command_allocator, ctx->sync_ctx.fence_value);
484  if (err < 0)
485  goto fail;
486 
487  pic->fence_value = ctx->sync_ctx.fence_value;
488 
489  if (d3d12_refs.ppTexture2Ds)
490  av_freep(&d3d12_refs.ppTexture2Ds);
491 
492  return 0;
493 
494 fail:
495  if (command_allocator)
496  d3d12va_discard_command_allocator(avctx, command_allocator, ctx->sync_ctx.fence_value);
497 
498  if (d3d12_refs.ppTexture2Ds)
499  av_freep(&d3d12_refs.ppTexture2Ds);
500 
501  if (ctx->codec->free_picture_params)
502  ctx->codec->free_picture_params(pic);
503 
505  pic->output_buffer = NULL;
508  return err;
509 }
510 
512  FFHWBaseEncodePicture *base_pic)
513 {
514  D3D12VAEncodePicture *pic = base_pic->priv;
515 
516  d3d12va_encode_wait(avctx, base_pic);
517 
518  if (pic->output_buffer_ref) {
519  av_log(avctx, AV_LOG_DEBUG, "Discard output for pic "
520  "%"PRId64"/%"PRId64".\n",
521  base_pic->display_order, base_pic->encode_order);
522 
524  pic->output_buffer = NULL;
525  }
526 
529 
530  return 0;
531 }
532 
534 {
536 
537  switch (ctx->rc.Mode)
538  {
539  case D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE_CQP:
540  av_freep(&ctx->rc.ConfigParams.pConfiguration_CQP);
541  break;
542  case D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE_CBR:
543  av_freep(&ctx->rc.ConfigParams.pConfiguration_CBR);
544  break;
545  case D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE_VBR:
546  av_freep(&ctx->rc.ConfigParams.pConfiguration_VBR);
547  break;
548  case D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE_QVBR:
549  av_freep(&ctx->rc.ConfigParams.pConfiguration_QVBR);
550  break;
551  default:
552  break;
553  }
554 
555  return 0;
556 }
557 
559 {
561  D3D12VAEncodePicture *priv = pic->priv;
562  AVFrame *frame = pic->input_image;
563 
564  if (ctx->codec->picture_priv_data_size > 0) {
565  pic->codec_priv = av_mallocz(ctx->codec->picture_priv_data_size);
566  if (!pic->codec_priv)
567  return AVERROR(ENOMEM);
568  }
569 
570  priv->input_surface = (AVD3D12VAFrame *)frame->data[0];
571 
572  return 0;
573 }
574 
576 {
578  D3D12VAEncodePicture *priv = pic->priv;
579 
580  if (pic->encode_issued)
581  d3d12va_encode_discard(avctx, pic);
582 
583  if (ctx->codec->free_picture_params)
584  ctx->codec->free_picture_params(priv);
585 
586  return 0;
587 }
588 
590  D3D12VAEncodePicture *pic, size_t *size)
591 {
592  D3D12_VIDEO_ENCODER_OUTPUT_METADATA *meta = NULL;
593  uint8_t *data;
594  HRESULT hr;
595  int err;
596 
597  hr = ID3D12Resource_Map(pic->resolved_metadata, 0, NULL, (void **)&data);
598  if (FAILED(hr)) {
599  err = AVERROR_UNKNOWN;
600  return err;
601  }
602 
603  meta = (D3D12_VIDEO_ENCODER_OUTPUT_METADATA *)data;
604 
605  if (meta->EncodeErrorFlags != D3D12_VIDEO_ENCODER_ENCODE_ERROR_FLAG_NO_ERROR) {
606  av_log(avctx, AV_LOG_ERROR, "Encode failed %"PRIu64"\n", meta->EncodeErrorFlags);
607  err = AVERROR(EINVAL);
608  return err;
609  }
610 
611  if (meta->EncodedBitstreamWrittenBytesCount == 0) {
612  av_log(avctx, AV_LOG_ERROR, "No bytes were written to encoded bitstream\n");
613  err = AVERROR(EINVAL);
614  return err;
615  }
616 
617  *size = meta->EncodedBitstreamWrittenBytesCount;
618 
619  ID3D12Resource_Unmap(pic->resolved_metadata, 0, NULL);
620 
621  return 0;
622 }
623 
626 {
627  int err;
628  uint8_t *ptr, *mapped_data;
629  size_t total_size = 0;
630  HRESULT hr;
631 
632  err = d3d12va_encode_get_buffer_size(avctx, pic, &total_size);
633  if (err < 0)
634  goto end;
635 
636  total_size += pic->header_size;
637  av_log(avctx, AV_LOG_DEBUG, "Output buffer size %"PRId64"\n", total_size);
638 
639  hr = ID3D12Resource_Map(pic->output_buffer, 0, NULL, (void **)&mapped_data);
640  if (FAILED(hr)) {
641  err = AVERROR_UNKNOWN;
642  goto end;
643  }
644 
645  err = ff_get_encode_buffer(avctx, pkt, total_size, 0);
646  if (err < 0)
647  goto end;
648  ptr = pkt->data;
649 
650  memcpy(ptr, mapped_data, pic->header_size);
651 
652  ptr += pic->header_size;
653  mapped_data += pic->aligned_header_size;
654  total_size -= pic->header_size;
655 
656  memcpy(ptr, mapped_data, total_size);
657 
658  ID3D12Resource_Unmap(pic->output_buffer, 0, NULL);
659 
660 end:
662  pic->output_buffer = NULL;
663  return err;
664 }
665 
667  FFHWBaseEncodePicture *base_pic, AVPacket *pkt)
668 {
669  FFHWBaseEncodeContext *base_ctx = avctx->priv_data;
670  D3D12VAEncodePicture *pic = base_pic->priv;
671  AVPacket *pkt_ptr = pkt;
672  int err;
673 
674  err = d3d12va_encode_wait(avctx, base_pic);
675  if (err < 0)
676  return err;
677 
678  err = d3d12va_encode_get_coded_data(avctx, pic, pkt);
679  if (err < 0)
680  return err;
681 
682  av_log(avctx, AV_LOG_DEBUG, "Output read for pic %"PRId64"/%"PRId64".\n",
683  base_pic->display_order, base_pic->encode_order);
684 
686  pkt_ptr, 0);
687 
688  return 0;
689 }
690 
692 {
693  FFHWBaseEncodeContext *base_ctx = avctx->priv_data;
696  const AVPixFmtDescriptor *desc;
697  int i, depth;
698 
700  if (!desc) {
701  av_log(avctx, AV_LOG_ERROR, "Invalid input pixfmt (%d).\n",
702  base_ctx->input_frames->sw_format);
703  return AVERROR(EINVAL);
704  }
705 
706  depth = desc->comp[0].depth;
707  for (i = 1; i < desc->nb_components; i++) {
708  if (desc->comp[i].depth != depth) {
709  av_log(avctx, AV_LOG_ERROR, "Invalid input pixfmt (%s).\n",
710  desc->name);
711  return AVERROR(EINVAL);
712  }
713  }
714  av_log(avctx, AV_LOG_VERBOSE, "Input surface format is %s.\n",
715  desc->name);
716 
717  av_assert0(ctx->codec->profiles);
718  for (i = 0; (ctx->codec->profiles[i].av_profile !=
719  AV_PROFILE_UNKNOWN); i++) {
720  profile = &ctx->codec->profiles[i];
721  if (depth != profile->depth ||
722  desc->nb_components != profile->nb_components)
723  continue;
724  if (desc->nb_components > 1 &&
725  (desc->log2_chroma_w != profile->log2_chroma_w ||
726  desc->log2_chroma_h != profile->log2_chroma_h))
727  continue;
728  if (avctx->profile != profile->av_profile &&
729  avctx->profile != AV_PROFILE_UNKNOWN)
730  continue;
731 
732  ctx->profile = profile;
733  break;
734  }
735  if (!ctx->profile) {
736  av_log(avctx, AV_LOG_ERROR, "No usable encoding profile found.\n");
737  return AVERROR(ENOSYS);
738  }
739 
740  avctx->profile = profile->av_profile;
741  return 0;
742 }
743 
745  // Bitrate Quality
746  // | Maxrate | HRD/VBV
747  { 0 }, // | | | |
748  { RC_MODE_CQP, "CQP", 0, 0, 1, 0, D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE_CQP },
749  { RC_MODE_CBR, "CBR", 1, 0, 0, 1, D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE_CBR },
750  { RC_MODE_VBR, "VBR", 1, 1, 0, 1, D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE_VBR },
751  { RC_MODE_QVBR, "QVBR", 1, 1, 1, 1, D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE_QVBR },
752 };
753 
755 {
756  HRESULT hr;
758  D3D12_FEATURE_DATA_VIDEO_ENCODER_RATE_CONTROL_MODE d3d12_rc_mode = {
759  .Codec = ctx->codec->d3d12_codec,
760  };
761 
762  if (!rc_mode->d3d12_mode)
763  return 0;
764 
765  d3d12_rc_mode.IsSupported = 0;
766  d3d12_rc_mode.RateControlMode = rc_mode->d3d12_mode;
767 
768  hr = ID3D12VideoDevice3_CheckFeatureSupport(ctx->video_device3,
769  D3D12_FEATURE_VIDEO_ENCODER_RATE_CONTROL_MODE,
770  &d3d12_rc_mode, sizeof(d3d12_rc_mode));
771  if (FAILED(hr)) {
772  av_log(avctx, AV_LOG_ERROR, "Failed to check rate control support.\n");
773  return 0;
774  }
775 
776  return d3d12_rc_mode.IsSupported;
777 }
778 
780 {
782  int64_t rc_target_bitrate;
783  int64_t rc_peak_bitrate;
784  int rc_quality;
785  int64_t hrd_buffer_size;
786  int64_t hrd_initial_buffer_fullness;
787  int fr_num, fr_den;
789 
790  // Rate control mode selection:
791  // * If the user has set a mode explicitly with the rc_mode option,
792  // use it and fail if it is not available.
793  // * If an explicit QP option has been set, use CQP.
794  // * If the codec is CQ-only, use CQP.
795  // * If the QSCALE avcodec option is set, use CQP.
796  // * If bitrate and quality are both set, try QVBR.
797  // * If quality is set, try CQP.
798  // * If bitrate and maxrate are set and have the same value, try CBR.
799  // * If a bitrate is set, try VBR, then CBR.
800  // * If no bitrate is set, try CQP.
801 
802 #define TRY_RC_MODE(mode, fail) do { \
803  rc_mode = &d3d12va_encode_rc_modes[mode]; \
804  if (!(rc_mode->d3d12_mode && check_rate_control_support(avctx, rc_mode))) { \
805  if (fail) { \
806  av_log(avctx, AV_LOG_ERROR, "Driver does not support %s " \
807  "RC mode.\n", rc_mode->name); \
808  return AVERROR(EINVAL); \
809  } \
810  av_log(avctx, AV_LOG_DEBUG, "Driver does not support %s " \
811  "RC mode.\n", rc_mode->name); \
812  rc_mode = NULL; \
813  } else { \
814  goto rc_mode_found; \
815  } \
816  } while (0)
817 
818  if (ctx->explicit_rc_mode)
819  TRY_RC_MODE(ctx->explicit_rc_mode, 1);
820 
821  if (ctx->explicit_qp)
823 
826 
827  if (avctx->flags & AV_CODEC_FLAG_QSCALE)
829 
830  if (avctx->bit_rate > 0 && avctx->global_quality > 0)
832 
833  if (avctx->global_quality > 0) {
835  }
836 
837  if (avctx->bit_rate > 0 && avctx->rc_max_rate == avctx->bit_rate)
839 
840  if (avctx->bit_rate > 0) {
843  } else {
845  }
846 
847  av_log(avctx, AV_LOG_ERROR, "Driver does not support any "
848  "RC mode compatible with selected options.\n");
849  return AVERROR(EINVAL);
850 
851 rc_mode_found:
852  if (rc_mode->bitrate) {
853  if (avctx->bit_rate <= 0) {
854  av_log(avctx, AV_LOG_ERROR, "Bitrate must be set for %s "
855  "RC mode.\n", rc_mode->name);
856  return AVERROR(EINVAL);
857  }
858 
859  if (rc_mode->maxrate) {
860  if (avctx->rc_max_rate > 0) {
861  if (avctx->rc_max_rate < avctx->bit_rate) {
862  av_log(avctx, AV_LOG_ERROR, "Invalid bitrate settings: "
863  "bitrate (%"PRId64") must not be greater than "
864  "maxrate (%"PRId64").\n", avctx->bit_rate,
865  avctx->rc_max_rate);
866  return AVERROR(EINVAL);
867  }
868  rc_target_bitrate = avctx->bit_rate;
869  rc_peak_bitrate = avctx->rc_max_rate;
870  } else {
871  // We only have a target bitrate, but this mode requires
872  // that a maximum rate be supplied as well. Since the
873  // user does not want this to be a constraint, arbitrarily
874  // pick a maximum rate of double the target rate.
875  rc_target_bitrate = avctx->bit_rate;
876  rc_peak_bitrate = 2 * avctx->bit_rate;
877  }
878  } else {
879  if (avctx->rc_max_rate > avctx->bit_rate) {
880  av_log(avctx, AV_LOG_WARNING, "Max bitrate is ignored "
881  "in %s RC mode.\n", rc_mode->name);
882  }
883  rc_target_bitrate = avctx->bit_rate;
884  rc_peak_bitrate = 0;
885  }
886  } else {
887  rc_target_bitrate = 0;
888  rc_peak_bitrate = 0;
889  }
890 
891  if (rc_mode->quality) {
892  if (ctx->explicit_qp) {
893  rc_quality = ctx->explicit_qp;
894  } else if (avctx->global_quality > 0) {
895  if (avctx->flags & AV_CODEC_FLAG_QSCALE)
896  rc_quality = avctx->global_quality / FF_QP2LAMBDA;
897  else
898  rc_quality = avctx->global_quality;
899  } else {
900  rc_quality = ctx->codec->default_quality;
901  av_log(avctx, AV_LOG_WARNING, "No quality level set; "
902  "using default (%d).\n", rc_quality);
903  }
904  } else {
905  rc_quality = 0;
906  }
907 
908  if (rc_mode->hrd) {
909  if (avctx->rc_buffer_size)
910  hrd_buffer_size = avctx->rc_buffer_size;
911  else if (avctx->rc_max_rate > 0)
912  hrd_buffer_size = avctx->rc_max_rate;
913  else
914  hrd_buffer_size = avctx->bit_rate;
915  if (avctx->rc_initial_buffer_occupancy) {
916  if (avctx->rc_initial_buffer_occupancy > hrd_buffer_size) {
917  av_log(avctx, AV_LOG_ERROR, "Invalid RC buffer settings: "
918  "must have initial buffer size (%d) <= "
919  "buffer size (%"PRId64").\n",
920  avctx->rc_initial_buffer_occupancy, hrd_buffer_size);
921  return AVERROR(EINVAL);
922  }
923  hrd_initial_buffer_fullness = avctx->rc_initial_buffer_occupancy;
924  } else {
925  hrd_initial_buffer_fullness = hrd_buffer_size * 3 / 4;
926  }
927  } else {
928  if (avctx->rc_buffer_size || avctx->rc_initial_buffer_occupancy) {
929  av_log(avctx, AV_LOG_WARNING, "Buffering settings are ignored "
930  "in %s RC mode.\n", rc_mode->name);
931  }
932 
933  hrd_buffer_size = 0;
934  hrd_initial_buffer_fullness = 0;
935  }
936 
937  if (rc_target_bitrate > UINT32_MAX ||
938  hrd_buffer_size > UINT32_MAX ||
939  hrd_initial_buffer_fullness > UINT32_MAX) {
940  av_log(avctx, AV_LOG_ERROR, "RC parameters of 2^32 or "
941  "greater are not supported by D3D12.\n");
942  return AVERROR(EINVAL);
943  }
944 
945  ctx->rc_quality = rc_quality;
946 
947  av_log(avctx, AV_LOG_VERBOSE, "RC mode: %s.\n", rc_mode->name);
948 
949  if (rc_mode->quality)
950  av_log(avctx, AV_LOG_VERBOSE, "RC quality: %d.\n", rc_quality);
951 
952  if (rc_mode->hrd) {
953  av_log(avctx, AV_LOG_VERBOSE, "RC buffer: %"PRId64" bits, "
954  "initial fullness %"PRId64" bits.\n",
955  hrd_buffer_size, hrd_initial_buffer_fullness);
956  }
957 
958  if (avctx->framerate.num > 0 && avctx->framerate.den > 0)
959  av_reduce(&fr_num, &fr_den,
960  avctx->framerate.num, avctx->framerate.den, 65535);
961  else
962  av_reduce(&fr_num, &fr_den,
963  avctx->time_base.den, avctx->time_base.num, 65535);
964 
965  av_log(avctx, AV_LOG_VERBOSE, "RC framerate: %d/%d (%.2f fps).\n",
966  fr_num, fr_den, (double)fr_num / fr_den);
967 
968  ctx->rc.Flags = D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_NONE;
969  ctx->rc.TargetFrameRate.Numerator = fr_num;
970  ctx->rc.TargetFrameRate.Denominator = fr_den;
971  ctx->rc.Mode = rc_mode->d3d12_mode;
972 
973  switch (rc_mode->mode) {
974  case RC_MODE_CQP:
975  // cqp ConfigParams will be updated in ctx->codec->configure.
976  break;
977 
978  case RC_MODE_CBR:
979  D3D12_VIDEO_ENCODER_RATE_CONTROL_CBR *cbr_ctl;
980 
981  ctx->rc.ConfigParams.DataSize = sizeof(D3D12_VIDEO_ENCODER_RATE_CONTROL_CBR);
982  cbr_ctl = av_mallocz(ctx->rc.ConfigParams.DataSize);
983  if (!cbr_ctl)
984  return AVERROR(ENOMEM);
985 
986  cbr_ctl->TargetBitRate = rc_target_bitrate;
987  cbr_ctl->VBVCapacity = hrd_buffer_size;
988  cbr_ctl->InitialVBVFullness = hrd_initial_buffer_fullness;
989  ctx->rc.Flags |= D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_VBV_SIZES;
990 
991  if (avctx->qmin > 0 || avctx->qmax > 0) {
992  cbr_ctl->MinQP = avctx->qmin;
993  cbr_ctl->MaxQP = avctx->qmax;
994  ctx->rc.Flags |= D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_QP_RANGE;
995  }
996 
997  ctx->rc.ConfigParams.pConfiguration_CBR = cbr_ctl;
998  break;
999 
1000  case RC_MODE_VBR:
1001  D3D12_VIDEO_ENCODER_RATE_CONTROL_VBR *vbr_ctl;
1002 
1003  ctx->rc.ConfigParams.DataSize = sizeof(D3D12_VIDEO_ENCODER_RATE_CONTROL_VBR);
1004  vbr_ctl = av_mallocz(ctx->rc.ConfigParams.DataSize);
1005  if (!vbr_ctl)
1006  return AVERROR(ENOMEM);
1007 
1008  vbr_ctl->TargetAvgBitRate = rc_target_bitrate;
1009  vbr_ctl->PeakBitRate = rc_peak_bitrate;
1010  vbr_ctl->VBVCapacity = hrd_buffer_size;
1011  vbr_ctl->InitialVBVFullness = hrd_initial_buffer_fullness;
1012  ctx->rc.Flags |= D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_VBV_SIZES;
1013 
1014  if (avctx->qmin > 0 || avctx->qmax > 0) {
1015  vbr_ctl->MinQP = avctx->qmin;
1016  vbr_ctl->MaxQP = avctx->qmax;
1017  ctx->rc.Flags |= D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_QP_RANGE;
1018  }
1019 
1020  ctx->rc.ConfigParams.pConfiguration_VBR = vbr_ctl;
1021  break;
1022 
1023  case RC_MODE_QVBR:
1024  D3D12_VIDEO_ENCODER_RATE_CONTROL_QVBR *qvbr_ctl;
1025 
1026  ctx->rc.ConfigParams.DataSize = sizeof(D3D12_VIDEO_ENCODER_RATE_CONTROL_QVBR);
1027  qvbr_ctl = av_mallocz(ctx->rc.ConfigParams.DataSize);
1028  if (!qvbr_ctl)
1029  return AVERROR(ENOMEM);
1030 
1031  qvbr_ctl->TargetAvgBitRate = rc_target_bitrate;
1032  qvbr_ctl->PeakBitRate = rc_peak_bitrate;
1033  qvbr_ctl->ConstantQualityTarget = rc_quality;
1034 
1035  if (avctx->qmin > 0 || avctx->qmax > 0) {
1036  qvbr_ctl->MinQP = avctx->qmin;
1037  qvbr_ctl->MaxQP = avctx->qmax;
1038  ctx->rc.Flags |= D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_QP_RANGE;
1039  }
1040 
1041  ctx->rc.ConfigParams.pConfiguration_QVBR = qvbr_ctl;
1042  break;
1043 
1044  default:
1045  break;
1046  }
1047  return 0;
1048 }
1049 
1051 {
1052  FFHWBaseEncodeContext *base_ctx = avctx->priv_data;
1054  uint32_t ref_l0, ref_l1;
1055  int err;
1056  HRESULT hr;
1057  D3D12_FEATURE_DATA_VIDEO_ENCODER_CODEC_PICTURE_CONTROL_SUPPORT support;
1058  union {
1059  D3D12_VIDEO_ENCODER_CODEC_PICTURE_CONTROL_SUPPORT_H264 h264;
1060  D3D12_VIDEO_ENCODER_CODEC_PICTURE_CONTROL_SUPPORT_HEVC hevc;
1061  } codec_support;
1062 
1063  support.NodeIndex = 0;
1064  support.Codec = ctx->codec->d3d12_codec;
1065  support.Profile = ctx->profile->d3d12_profile;
1066 
1067  switch (ctx->codec->d3d12_codec) {
1068  case D3D12_VIDEO_ENCODER_CODEC_H264:
1069  support.PictureSupport.DataSize = sizeof(codec_support.h264);
1070  support.PictureSupport.pH264Support = &codec_support.h264;
1071  break;
1072 
1073  case D3D12_VIDEO_ENCODER_CODEC_HEVC:
1074  support.PictureSupport.DataSize = sizeof(codec_support.hevc);
1075  support.PictureSupport.pHEVCSupport = &codec_support.hevc;
1076  break;
1077 
1078  default:
1079  av_assert0(0);
1080  }
1081 
1082  hr = ID3D12VideoDevice3_CheckFeatureSupport(ctx->video_device3, D3D12_FEATURE_VIDEO_ENCODER_CODEC_PICTURE_CONTROL_SUPPORT,
1083  &support, sizeof(support));
1084  if (FAILED(hr))
1085  return AVERROR(EINVAL);
1086 
1087  if (support.IsSupported) {
1088  switch (ctx->codec->d3d12_codec) {
1089  case D3D12_VIDEO_ENCODER_CODEC_H264:
1090  ref_l0 = FFMIN(support.PictureSupport.pH264Support->MaxL0ReferencesForP,
1091  support.PictureSupport.pH264Support->MaxL1ReferencesForB);
1092  ref_l1 = support.PictureSupport.pH264Support->MaxL1ReferencesForB;
1093  break;
1094 
1095  case D3D12_VIDEO_ENCODER_CODEC_HEVC:
1096  ref_l0 = FFMIN(support.PictureSupport.pHEVCSupport->MaxL0ReferencesForP,
1097  support.PictureSupport.pHEVCSupport->MaxL1ReferencesForB);
1098  ref_l1 = support.PictureSupport.pHEVCSupport->MaxL1ReferencesForB;
1099  break;
1100 
1101  default:
1102  av_assert0(0);
1103  }
1104  } else {
1105  ref_l0 = ref_l1 = 0;
1106  }
1107 
1108  if (ref_l0 > 0 && ref_l1 > 0 && ctx->bi_not_empty) {
1109  base_ctx->p_to_gpb = 1;
1110  av_log(avctx, AV_LOG_VERBOSE, "Driver does not support P-frames, "
1111  "replacing them with B-frames.\n");
1112  }
1113 
1114  err = ff_hw_base_init_gop_structure(base_ctx, avctx, ref_l0, ref_l1, ctx->codec->flags, 0);
1115  if (err < 0)
1116  return err;
1117 
1118  return 0;
1119 }
1120 
1122 {
1123  FFHWBaseEncodeContext *base_ctx = avctx->priv_data;
1125  AVD3D12VAFramesContext *frames_hwctx = base_ctx->input_frames->hwctx;
1126  HRESULT hr;
1127 
1128  D3D12_VIDEO_ENCODER_DESC desc = {
1129  .NodeMask = 0,
1130  .Flags = D3D12_VIDEO_ENCODER_FLAG_NONE,
1131  .EncodeCodec = ctx->codec->d3d12_codec,
1132  .EncodeProfile = ctx->profile->d3d12_profile,
1133  .InputFormat = frames_hwctx->format,
1134  .CodecConfiguration = ctx->codec_conf,
1135  .MaxMotionEstimationPrecision = D3D12_VIDEO_ENCODER_MOTION_ESTIMATION_PRECISION_MODE_MAXIMUM,
1136  };
1137 
1138  hr = ID3D12VideoDevice3_CreateVideoEncoder(ctx->video_device3, &desc, &IID_ID3D12VideoEncoder,
1139  (void **)&ctx->encoder);
1140  if (FAILED(hr)) {
1141  av_log(avctx, AV_LOG_ERROR, "Failed to create encoder.\n");
1142  return AVERROR(EINVAL);
1143  }
1144 
1145  return 0;
1146 }
1147 
1149 {
1151  HRESULT hr;
1152 
1153  D3D12_VIDEO_ENCODER_HEAP_DESC desc = {
1154  .NodeMask = 0,
1155  .Flags = D3D12_VIDEO_ENCODER_FLAG_NONE,
1156  .EncodeCodec = ctx->codec->d3d12_codec,
1157  .EncodeProfile = ctx->profile->d3d12_profile,
1158  .EncodeLevel = ctx->level,
1159  .ResolutionsListCount = 1,
1160  .pResolutionList = &ctx->resolution,
1161  };
1162 
1163  hr = ID3D12VideoDevice3_CreateVideoEncoderHeap(ctx->video_device3, &desc,
1164  &IID_ID3D12VideoEncoderHeap, (void **)&ctx->encoder_heap);
1165  if (FAILED(hr)) {
1166  av_log(avctx, AV_LOG_ERROR, "Failed to create encoder heap.\n");
1167  return AVERROR(EINVAL);
1168  }
1169 
1170  return 0;
1171 }
1172 
1173 static void d3d12va_encode_free_buffer(void *opaque, uint8_t *data)
1174 {
1175  ID3D12Resource *pResource;
1176 
1177  pResource = (ID3D12Resource *)data;
1178  D3D12_OBJECT_RELEASE(pResource);
1179 }
1180 
1182 {
1183  AVCodecContext *avctx = opaque;
1184  FFHWBaseEncodeContext *base_ctx = avctx->priv_data;
1186  ID3D12Resource *pResource = NULL;
1187  HRESULT hr;
1188  AVBufferRef *ref;
1189  D3D12_HEAP_PROPERTIES heap_props;
1190  D3D12_HEAP_TYPE heap_type = D3D12_HEAP_TYPE_READBACK;
1191 
1192  D3D12_RESOURCE_DESC desc = {
1193  .Dimension = D3D12_RESOURCE_DIMENSION_BUFFER,
1194  .Alignment = 0,
1195  .Width = FFALIGN(3 * base_ctx->surface_width * base_ctx->surface_height + (1 << 16),
1196  D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT),
1197  .Height = 1,
1198  .DepthOrArraySize = 1,
1199  .MipLevels = 1,
1200  .Format = DXGI_FORMAT_UNKNOWN,
1201  .SampleDesc = { .Count = 1, .Quality = 0 },
1202  .Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR,
1203  .Flags = D3D12_RESOURCE_FLAG_NONE,
1204  };
1205 
1206  ctx->hwctx->device->lpVtbl->GetCustomHeapProperties(ctx->hwctx->device, &heap_props, 0, heap_type);
1207 
1208  hr = ID3D12Device_CreateCommittedResource(ctx->hwctx->device, &heap_props, D3D12_HEAP_FLAG_NONE,
1209  &desc, D3D12_RESOURCE_STATE_COMMON, NULL, &IID_ID3D12Resource,
1210  (void **)&pResource);
1211 
1212  if (FAILED(hr)) {
1213  av_log(avctx, AV_LOG_ERROR, "Failed to create d3d12 buffer.\n");
1214  return NULL;
1215  }
1216 
1217  ref = av_buffer_create((uint8_t *)(uintptr_t)pResource,
1218  sizeof(pResource),
1220  avctx, AV_BUFFER_FLAG_READONLY);
1221  if (!ref) {
1222  D3D12_OBJECT_RELEASE(pResource);
1223  return NULL;
1224  }
1225 
1226  return ref;
1227 }
1228 
1230 {
1231  FFHWBaseEncodeContext *base_ctx = avctx->priv_data;
1233  AVD3D12VAFramesContext *frames_ctx = base_ctx->input_frames->hwctx;
1234  HRESULT hr;
1235 
1236  ctx->req.NodeIndex = 0;
1237  ctx->req.Codec = ctx->codec->d3d12_codec;
1238  ctx->req.Profile = ctx->profile->d3d12_profile;
1239  ctx->req.InputFormat = frames_ctx->format;
1240  ctx->req.PictureTargetResolution = ctx->resolution;
1241 
1242  hr = ID3D12VideoDevice3_CheckFeatureSupport(ctx->video_device3,
1243  D3D12_FEATURE_VIDEO_ENCODER_RESOURCE_REQUIREMENTS,
1244  &ctx->req, sizeof(ctx->req));
1245  if (FAILED(hr)) {
1246  av_log(avctx, AV_LOG_ERROR, "Failed to check encoder resource requirements support.\n");
1247  return AVERROR(EINVAL);
1248  }
1249 
1250  if (!ctx->req.IsSupported) {
1251  av_log(avctx, AV_LOG_ERROR, "Encoder resource requirements unsupported.\n");
1252  return AVERROR(EINVAL);
1253  }
1254 
1255  ctx->output_buffer_pool = av_buffer_pool_init2(sizeof(ID3D12Resource *), avctx,
1257  if (!ctx->output_buffer_pool)
1258  return AVERROR(ENOMEM);
1259 
1260  return 0;
1261 }
1262 
1264 {
1266  ID3D12CommandAllocator *command_allocator = NULL;
1267  int err;
1268  HRESULT hr;
1269 
1270  D3D12_COMMAND_QUEUE_DESC queue_desc = {
1271  .Type = D3D12_COMMAND_LIST_TYPE_VIDEO_ENCODE,
1272  .Priority = 0,
1273  .Flags = D3D12_COMMAND_QUEUE_FLAG_NONE,
1274  .NodeMask = 0,
1275  };
1276 
1279  if (!ctx->allocator_queue)
1280  return AVERROR(ENOMEM);
1281 
1282  hr = ID3D12Device_CreateFence(ctx->hwctx->device, 0, D3D12_FENCE_FLAG_NONE,
1283  &IID_ID3D12Fence, (void **)&ctx->sync_ctx.fence);
1284  if (FAILED(hr)) {
1285  av_log(avctx, AV_LOG_ERROR, "Failed to create fence(%lx)\n", (long)hr);
1286  err = AVERROR_UNKNOWN;
1287  goto fail;
1288  }
1289 
1290  ctx->sync_ctx.event = CreateEvent(NULL, FALSE, FALSE, NULL);
1291  if (!ctx->sync_ctx.event)
1292  goto fail;
1293 
1294  err = d3d12va_get_valid_command_allocator(avctx, &command_allocator);
1295  if (err < 0)
1296  goto fail;
1297 
1298  hr = ID3D12Device_CreateCommandQueue(ctx->hwctx->device, &queue_desc,
1299  &IID_ID3D12CommandQueue, (void **)&ctx->command_queue);
1300  if (FAILED(hr)) {
1301  av_log(avctx, AV_LOG_ERROR, "Failed to create command queue(%lx)\n", (long)hr);
1302  err = AVERROR_UNKNOWN;
1303  goto fail;
1304  }
1305 
1306  hr = ID3D12Device_CreateCommandList(ctx->hwctx->device, 0, queue_desc.Type,
1307  command_allocator, NULL, &IID_ID3D12CommandList,
1308  (void **)&ctx->command_list);
1309  if (FAILED(hr)) {
1310  av_log(avctx, AV_LOG_ERROR, "Failed to create command list(%lx)\n", (long)hr);
1311  err = AVERROR_UNKNOWN;
1312  goto fail;
1313  }
1314 
1315  hr = ID3D12VideoEncodeCommandList2_Close(ctx->command_list);
1316  if (FAILED(hr)) {
1317  av_log(avctx, AV_LOG_ERROR, "Failed to close the command list(%lx)\n", (long)hr);
1318  err = AVERROR_UNKNOWN;
1319  goto fail;
1320  }
1321 
1322  ID3D12CommandQueue_ExecuteCommandLists(ctx->command_queue, 1, (ID3D12CommandList **)&ctx->command_list);
1323 
1324  err = d3d12va_sync_with_gpu(avctx);
1325  if (err < 0)
1326  goto fail;
1327 
1328  err = d3d12va_discard_command_allocator(avctx, command_allocator, ctx->sync_ctx.fence_value);
1329  if (err < 0)
1330  goto fail;
1331 
1332  return 0;
1333 
1334 fail:
1335  D3D12_OBJECT_RELEASE(command_allocator);
1336  return err;
1337 }
1338 
1340 {
1341  FFHWBaseEncodeContext *base_ctx = avctx->priv_data;
1342  AVD3D12VAFramesContext *hwctx;
1343  enum AVPixelFormat recon_format;
1344  int err;
1345 
1346  err = ff_hw_base_get_recon_format(base_ctx, NULL, &recon_format);
1347  if (err < 0)
1348  return err;
1349 
1350  base_ctx->recon_frames_ref = av_hwframe_ctx_alloc(base_ctx->device_ref);
1351  if (!base_ctx->recon_frames_ref)
1352  return AVERROR(ENOMEM);
1353 
1354  base_ctx->recon_frames = (AVHWFramesContext *)base_ctx->recon_frames_ref->data;
1355  hwctx = (AVD3D12VAFramesContext *)base_ctx->recon_frames->hwctx;
1356 
1357  base_ctx->recon_frames->format = AV_PIX_FMT_D3D12;
1358  base_ctx->recon_frames->sw_format = recon_format;
1359  base_ctx->recon_frames->width = base_ctx->surface_width;
1360  base_ctx->recon_frames->height = base_ctx->surface_height;
1361 
1362  hwctx->flags = D3D12_RESOURCE_FLAG_VIDEO_ENCODE_REFERENCE_ONLY |
1363  D3D12_RESOURCE_FLAG_DENY_SHADER_RESOURCE;
1364 
1365  err = av_hwframe_ctx_init(base_ctx->recon_frames_ref);
1366  if (err < 0) {
1367  av_log(avctx, AV_LOG_ERROR, "Failed to initialise reconstructed "
1368  "frame context: %d.\n", err);
1369  return err;
1370  }
1371 
1372  return 0;
1373 }
1374 
1376  .priv_size = sizeof(D3D12VAEncodePicture),
1377 
1379 
1380  .issue = &d3d12va_encode_issue,
1381 
1383 
1384  .free = &d3d12va_encode_free,
1385 };
1386 
1388 {
1389  return ff_hw_base_encode_receive_packet(avctx->priv_data, avctx, pkt);
1390 }
1391 
1393 {
1394  FFHWBaseEncodeContext *base_ctx = avctx->priv_data;
1396  D3D12_FEATURE_DATA_VIDEO_FEATURE_AREA_SUPPORT support = { 0 };
1397  int err;
1398  HRESULT hr;
1399 
1400  err = ff_hw_base_encode_init(avctx, base_ctx);
1401  if (err < 0)
1402  goto fail;
1403 
1404  base_ctx->op = &d3d12va_type;
1405 
1406  ctx->hwctx = base_ctx->device->hwctx;
1407 
1408  ctx->resolution.Width = base_ctx->input_frames->width;
1409  ctx->resolution.Height = base_ctx->input_frames->height;
1410 
1411  hr = ID3D12Device_QueryInterface(ctx->hwctx->device, &IID_ID3D12Device3, (void **)&ctx->device3);
1412  if (FAILED(hr)) {
1413  av_log(avctx, AV_LOG_ERROR, "ID3D12Device3 interface is not supported.\n");
1414  err = AVERROR_UNKNOWN;
1415  goto fail;
1416  }
1417 
1418  hr = ID3D12Device3_QueryInterface(ctx->device3, &IID_ID3D12VideoDevice3, (void **)&ctx->video_device3);
1419  if (FAILED(hr)) {
1420  av_log(avctx, AV_LOG_ERROR, "ID3D12VideoDevice3 interface is not supported.\n");
1421  err = AVERROR_UNKNOWN;
1422  goto fail;
1423  }
1424 
1425  if (FAILED(ID3D12VideoDevice3_CheckFeatureSupport(ctx->video_device3, D3D12_FEATURE_VIDEO_FEATURE_AREA_SUPPORT,
1426  &support, sizeof(support))) && !support.VideoEncodeSupport) {
1427  av_log(avctx, AV_LOG_ERROR, "D3D12 video device has no video encoder support.\n");
1428  err = AVERROR(EINVAL);
1429  goto fail;
1430  }
1431 
1432  err = d3d12va_encode_set_profile(avctx);
1433  if (err < 0)
1434  goto fail;
1435 
1436  err = d3d12va_encode_init_rate_control(avctx);
1437  if (err < 0)
1438  goto fail;
1439 
1440  if (ctx->codec->get_encoder_caps) {
1441  err = ctx->codec->get_encoder_caps(avctx);
1442  if (err < 0)
1443  goto fail;
1444  }
1445 
1446  err = d3d12va_encode_init_gop_structure(avctx);
1447  if (err < 0)
1448  goto fail;
1449 
1450  if (!(ctx->codec->flags & FF_HW_FLAG_SLICE_CONTROL) && avctx->slices > 0) {
1451  av_log(avctx, AV_LOG_WARNING, "Multiple slices were requested "
1452  "but this codec does not support controlling slices.\n");
1453  }
1454 
1456  if (err < 0)
1457  goto fail;
1458 
1460  if (err < 0)
1461  goto fail;
1462 
1464  if (err < 0)
1465  goto fail;
1466 
1467  if (ctx->codec->configure) {
1468  err = ctx->codec->configure(avctx);
1469  if (err < 0)
1470  goto fail;
1471  }
1472 
1473  if (ctx->codec->init_sequence_params) {
1474  err = ctx->codec->init_sequence_params(avctx);
1475  if (err < 0) {
1476  av_log(avctx, AV_LOG_ERROR, "Codec sequence initialisation "
1477  "failed: %d.\n", err);
1478  goto fail;
1479  }
1480  }
1481 
1482  if (ctx->codec->set_level) {
1483  err = ctx->codec->set_level(avctx);
1484  if (err < 0)
1485  goto fail;
1486  }
1487 
1488  base_ctx->output_delay = base_ctx->b_per_p;
1489  base_ctx->decode_delay = base_ctx->max_b_depth;
1490 
1491  err = d3d12va_create_encoder(avctx);
1492  if (err < 0)
1493  goto fail;
1494 
1495  err = d3d12va_create_encoder_heap(avctx);
1496  if (err < 0)
1497  goto fail;
1498 
1499  base_ctx->async_encode = 1;
1500  base_ctx->encode_fifo = av_fifo_alloc2(base_ctx->async_depth,
1501  sizeof(D3D12VAEncodePicture *), 0);
1502  if (!base_ctx->encode_fifo)
1503  return AVERROR(ENOMEM);
1504 
1505  return 0;
1506 
1507 fail:
1508  return err;
1509 }
1510 
1512 {
1513  int num_allocator = 0;
1514  FFHWBaseEncodeContext *base_ctx = avctx->priv_data;
1516  FFHWBaseEncodePicture *pic, *next;
1517  CommandAllocator allocator;
1518 
1519  if (!base_ctx->frame)
1520  return 0;
1521 
1522  for (pic = base_ctx->pic_start; pic; pic = next) {
1523  next = pic->next;
1524  d3d12va_encode_free(avctx, pic);
1525  }
1526 
1528 
1529  av_buffer_pool_uninit(&ctx->output_buffer_pool);
1530 
1531  D3D12_OBJECT_RELEASE(ctx->command_list);
1532  D3D12_OBJECT_RELEASE(ctx->command_queue);
1533 
1534  if (ctx->allocator_queue) {
1535  while (av_fifo_read(ctx->allocator_queue, &allocator, 1) >= 0) {
1536  num_allocator++;
1538  }
1539 
1540  av_log(avctx, AV_LOG_VERBOSE, "Total number of command allocators reused: %d\n", num_allocator);
1541  }
1542 
1543  av_fifo_freep2(&ctx->allocator_queue);
1544 
1545  D3D12_OBJECT_RELEASE(ctx->sync_ctx.fence);
1546  if (ctx->sync_ctx.event)
1547  CloseHandle(ctx->sync_ctx.event);
1548 
1549  D3D12_OBJECT_RELEASE(ctx->encoder_heap);
1550  D3D12_OBJECT_RELEASE(ctx->encoder);
1551  D3D12_OBJECT_RELEASE(ctx->video_device3);
1552  D3D12_OBJECT_RELEASE(ctx->device3);
1553 
1554  ff_hw_base_encode_close(base_ctx);
1555 
1556  return 0;
1557 }
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:85
AV_LOG_WARNING
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition: log.h:215
AVPixelFormat
AVPixelFormat
Pixel format.
Definition: pixfmt.h:71
FFHWBaseEncodeContext::recon_frames_ref
AVBufferRef * recon_frames_ref
Definition: hw_base_encode.h:156
RC_MODE_CBR
@ RC_MODE_CBR
Definition: d3d12va_encode.h:95
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:691
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:3170
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:197
RC_MODE_CQP
@ RC_MODE_CQP
Definition: d3d12va_encode.h:94
AV_CODEC_FLAG_QSCALE
#define AV_CODEC_FLAG_QSCALE
Use fixed qscale.
Definition: avcodec.h:224
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:225
d3d12va_encode_create_recon_frames
static int d3d12va_encode_create_recon_frames(AVCodecContext *avctx)
Definition: d3d12va_encode.c:1339
av_frame_free
void av_frame_free(AVFrame **frame)
Free the frame and any dynamically allocated objects in it, e.g.
Definition: frame.c:162
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:322
AVFrame
This structure describes decoded (raw) audio or video data.
Definition: frame.h:389
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:248
AVPacket::data
uint8_t * data
Definition: packet.h:539
ff_hw_base_encode_init
int ff_hw_base_encode_init(AVCodecContext *avctx, FFHWBaseEncodeContext *ctx)
Definition: hw_base_encode.c:772
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:624
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:225
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:217
AVCodecContext::qmax
int qmax
maximum quantizer
Definition: avcodec.h:1273
AVFrame::data
uint8_t * data[AV_NUM_DATA_POINTERS]
pointer to the picture/channel planes.
Definition: frame.h:410
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:566
d3d12va_encode_output
static int d3d12va_encode_output(AVCodecContext *avctx, FFHWBaseEncodePicture *base_pic, AVPacket *pkt)
Definition: d3d12va_encode.c:666
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:575
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:805
FFHWBaseEncodePicture::is_reference
int is_reference
Definition: hw_base_encode.h:87
fail
#define fail()
Definition: checkasm.h:193
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
FF_HW_FLAG_SLICE_CONTROL
@ FF_HW_FLAG_SLICE_CONTROL
Definition: hw_base_encode.h:47
AVCodecContext::flags
int flags
AV_CODEC_FLAG_*.
Definition: avcodec.h:508
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:661
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:744
check_rate_control_support
static int check_rate_control_support(AVCodecContext *avctx, const D3D12VAEncodeRCMode *rc_mode)
Definition: d3d12va_encode.c:754
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:714
d3d12va_encode_get_buffer_size
static int d3d12va_encode_get_buffer_size(AVCodecContext *avctx, D3D12VAEncodePicture *pic, size_t *size)
Definition: d3d12va_encode.c:589
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:209
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:1330
AVHWFramesContext::height
int height
Definition: hwcontext.h:217
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:1249
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:1451
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:212
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:40
d3d12va_create_encoder_heap
static int d3d12va_create_encoder_heap(AVCodecContext *avctx)
Definition: d3d12va_encode.c:1148
AV_LOG_DEBUG
#define AV_LOG_DEBUG
Stuff which is only useful for libav* developers.
Definition: log.h:230
ctx
AVFormatContext * ctx
Definition: movenc.c:49
FF_HW_PICTURE_TYPE_IDR
@ FF_HW_PICTURE_TYPE_IDR
Definition: hw_base_encode.h:39
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:511
AVCodecContext::rc_max_rate
int64_t rc_max_rate
maximum bitrate
Definition: avcodec.h:1302
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:1287
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:210
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:501
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
RC_MODE_VBR
@ RC_MODE_VBR
Definition: d3d12va_encode.h:96
AVD3D12VAFramesContext
This struct is allocated as AVHWFramesContext.hwctx.
Definition: hwcontext_d3d12va.h:126
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
RC_MODE_QVBR
@ RC_MODE_QVBR
Definition: d3d12va_encode.h:97
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:550
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:518
d3d12va_encode_free_buffer
static void d3d12va_encode_free_buffer(void *opaque, uint8_t *data)
Definition: d3d12va_encode.c:1173
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:207
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:1263
ff_d3d12va_encode_init
int ff_d3d12va_encode_init(AVCodecContext *avctx)
Definition: d3d12va_encode.c:1392
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:1375
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:557
AVCodecHWConfigInternal
Definition: hwconfig.h:25
FFHWBaseEncodeContext::p_to_gpb
int p_to_gpb
Definition: hw_base_encode.h:194
MAX_PARAM_BUFFER_SIZE
@ MAX_PARAM_BUFFER_SIZE
Definition: vaapi_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
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:1181
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:558
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)
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:2233
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:1121
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:115
d3d12va_encode_init_rate_control
static int d3d12va_encode_init_rate_control(AVCodecContext *avctx)
Definition: d3d12va_encode.c:779
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:264
AVHWFramesContext::hwctx
void * hwctx
The format-specific data, allocated and freed automatically along with this context.
Definition: hwcontext.h:150
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:215
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:1229
FFHWBaseEncodeContext::surface_height
int surface_height
Definition: hw_base_encode.h:141
FFHWBaseEncodeContext::async_depth
int async_depth
Definition: hw_base_encode.h:217
AVCodecContext
main external API structure.
Definition: avcodec.h:451
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:1266
AVRational::den
int den
Denominator.
Definition: rational.h:60
FF_HW_FLAG_CONSTANT_QUALITY_ONLY
@ FF_HW_FLAG_CONSTANT_QUALITY_ONLY
Definition: hw_base_encode.h:49
AVCodecContext::profile
int profile
profile
Definition: avcodec.h:1650
d3d12va_encode_free_rc_params
static int d3d12va_encode_free_rc_params(AVCodecContext *avctx)
Definition: d3d12va_encode.c:533
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
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:1511
FFALIGN
#define FFALIGN(x, a)
Definition: macros.h:78
AVCodecContext::slices
int slices
Number of slices.
Definition: avcodec.h:1053
ff_d3d12va_encode_receive_packet
int ff_d3d12va_encode_receive_packet(AVCodecContext *avctx, AVPacket *pkt)
Definition: d3d12va_encode.c:1387
AVPacket
This structure stores compressed data.
Definition: packet.h:516
AVCodecContext::priv_data
void * priv_data
Definition: avcodec.h:478
av_freep
#define av_freep(p)
Definition: tableprint_vlc.h:34
d3d12va_encode_init_gop_structure
static int d3d12va_encode_init_gop_structure(AVCodecContext *avctx)
Definition: d3d12va_encode.c:1050
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:85
FF_QP2LAMBDA
#define FF_QP2LAMBDA
factor to convert from H.263 QP to lambda
Definition: avutil.h:227
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