FFmpeg
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
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 
977  case RC_MODE_CBR:
978  D3D12_VIDEO_ENCODER_RATE_CONTROL_CBR *cbr_ctl;
979 
980  ctx->rc.ConfigParams.DataSize = sizeof(D3D12_VIDEO_ENCODER_RATE_CONTROL_CBR);
981  cbr_ctl = av_mallocz(ctx->rc.ConfigParams.DataSize);
982  if (!cbr_ctl)
983  return AVERROR(ENOMEM);
984 
985  cbr_ctl->TargetBitRate = rc_target_bitrate;
986  cbr_ctl->VBVCapacity = hrd_buffer_size;
987  cbr_ctl->InitialVBVFullness = hrd_initial_buffer_fullness;
988  ctx->rc.Flags |= D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_VBV_SIZES;
989 
990  if (avctx->qmin > 0 || avctx->qmax > 0) {
991  cbr_ctl->MinQP = avctx->qmin;
992  cbr_ctl->MaxQP = avctx->qmax;
993  ctx->rc.Flags |= D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_QP_RANGE;
994  }
995 
996  ctx->rc.ConfigParams.pConfiguration_CBR = cbr_ctl;
997  break;
998 
999  case RC_MODE_VBR:
1000  D3D12_VIDEO_ENCODER_RATE_CONTROL_VBR *vbr_ctl;
1001 
1002  ctx->rc.ConfigParams.DataSize = sizeof(D3D12_VIDEO_ENCODER_RATE_CONTROL_VBR);
1003  vbr_ctl = av_mallocz(ctx->rc.ConfigParams.DataSize);
1004  if (!vbr_ctl)
1005  return AVERROR(ENOMEM);
1006 
1007  vbr_ctl->TargetAvgBitRate = rc_target_bitrate;
1008  vbr_ctl->PeakBitRate = rc_peak_bitrate;
1009  vbr_ctl->VBVCapacity = hrd_buffer_size;
1010  vbr_ctl->InitialVBVFullness = hrd_initial_buffer_fullness;
1011  ctx->rc.Flags |= D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_VBV_SIZES;
1012 
1013  if (avctx->qmin > 0 || avctx->qmax > 0) {
1014  vbr_ctl->MinQP = avctx->qmin;
1015  vbr_ctl->MaxQP = avctx->qmax;
1016  ctx->rc.Flags |= D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_QP_RANGE;
1017  }
1018 
1019  ctx->rc.ConfigParams.pConfiguration_VBR = vbr_ctl;
1020  break;
1021 
1022  case RC_MODE_QVBR:
1023  D3D12_VIDEO_ENCODER_RATE_CONTROL_QVBR *qvbr_ctl;
1024 
1025  ctx->rc.ConfigParams.DataSize = sizeof(D3D12_VIDEO_ENCODER_RATE_CONTROL_QVBR);
1026  qvbr_ctl = av_mallocz(ctx->rc.ConfigParams.DataSize);
1027  if (!qvbr_ctl)
1028  return AVERROR(ENOMEM);
1029 
1030  qvbr_ctl->TargetAvgBitRate = rc_target_bitrate;
1031  qvbr_ctl->PeakBitRate = rc_peak_bitrate;
1032  qvbr_ctl->ConstantQualityTarget = rc_quality;
1033 
1034  if (avctx->qmin > 0 || avctx->qmax > 0) {
1035  qvbr_ctl->MinQP = avctx->qmin;
1036  qvbr_ctl->MaxQP = avctx->qmax;
1037  ctx->rc.Flags |= D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_QP_RANGE;
1038  }
1039 
1040  ctx->rc.ConfigParams.pConfiguration_QVBR = qvbr_ctl;
1041  break;
1042 
1043  default:
1044  break;
1045  }
1046  return 0;
1047 }
1048 
1050 {
1051  FFHWBaseEncodeContext *base_ctx = avctx->priv_data;
1053  uint32_t ref_l0, ref_l1;
1054  int err;
1055  HRESULT hr;
1056  D3D12_FEATURE_DATA_VIDEO_ENCODER_CODEC_PICTURE_CONTROL_SUPPORT support;
1057  union {
1058  D3D12_VIDEO_ENCODER_CODEC_PICTURE_CONTROL_SUPPORT_H264 h264;
1059  D3D12_VIDEO_ENCODER_CODEC_PICTURE_CONTROL_SUPPORT_HEVC hevc;
1060  } codec_support;
1061 
1062  support.NodeIndex = 0;
1063  support.Codec = ctx->codec->d3d12_codec;
1064  support.Profile = ctx->profile->d3d12_profile;
1065 
1066  switch (ctx->codec->d3d12_codec) {
1067  case D3D12_VIDEO_ENCODER_CODEC_H264:
1068  support.PictureSupport.DataSize = sizeof(codec_support.h264);
1069  support.PictureSupport.pH264Support = &codec_support.h264;
1070  break;
1071 
1072  case D3D12_VIDEO_ENCODER_CODEC_HEVC:
1073  support.PictureSupport.DataSize = sizeof(codec_support.hevc);
1074  support.PictureSupport.pHEVCSupport = &codec_support.hevc;
1075  break;
1076 
1077  default:
1078  av_assert0(0);
1079  }
1080 
1081  hr = ID3D12VideoDevice3_CheckFeatureSupport(ctx->video_device3, D3D12_FEATURE_VIDEO_ENCODER_CODEC_PICTURE_CONTROL_SUPPORT,
1082  &support, sizeof(support));
1083  if (FAILED(hr))
1084  return AVERROR(EINVAL);
1085 
1086  if (support.IsSupported) {
1087  switch (ctx->codec->d3d12_codec) {
1088  case D3D12_VIDEO_ENCODER_CODEC_H264:
1089  ref_l0 = FFMIN(support.PictureSupport.pH264Support->MaxL0ReferencesForP,
1090  support.PictureSupport.pH264Support->MaxL1ReferencesForB ?
1091  support.PictureSupport.pH264Support->MaxL1ReferencesForB : UINT_MAX);
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  support.PictureSupport.pHEVCSupport->MaxL1ReferencesForB : UINT_MAX);
1099  ref_l1 = support.PictureSupport.pHEVCSupport->MaxL1ReferencesForB;
1100  break;
1101 
1102  default:
1103  av_assert0(0);
1104  }
1105  } else {
1106  ref_l0 = ref_l1 = 0;
1107  }
1108 
1109  if (ref_l0 > 0 && ref_l1 > 0 && ctx->bi_not_empty) {
1110  base_ctx->p_to_gpb = 1;
1111  av_log(avctx, AV_LOG_VERBOSE, "Driver does not support P-frames, "
1112  "replacing them with B-frames.\n");
1113  }
1114 
1115  err = ff_hw_base_init_gop_structure(base_ctx, avctx, ref_l0, ref_l1, ctx->codec->flags, 0);
1116  if (err < 0)
1117  return err;
1118 
1119  return 0;
1120 }
1121 
1123 {
1124  FFHWBaseEncodeContext *base_ctx = avctx->priv_data;
1126  AVD3D12VAFramesContext *frames_hwctx = base_ctx->input_frames->hwctx;
1127  HRESULT hr;
1128 
1129  D3D12_VIDEO_ENCODER_DESC desc = {
1130  .NodeMask = 0,
1131  .Flags = D3D12_VIDEO_ENCODER_FLAG_NONE,
1132  .EncodeCodec = ctx->codec->d3d12_codec,
1133  .EncodeProfile = ctx->profile->d3d12_profile,
1134  .InputFormat = frames_hwctx->format,
1135  .CodecConfiguration = ctx->codec_conf,
1136  .MaxMotionEstimationPrecision = D3D12_VIDEO_ENCODER_MOTION_ESTIMATION_PRECISION_MODE_MAXIMUM,
1137  };
1138 
1139  hr = ID3D12VideoDevice3_CreateVideoEncoder(ctx->video_device3, &desc, &IID_ID3D12VideoEncoder,
1140  (void **)&ctx->encoder);
1141  if (FAILED(hr)) {
1142  av_log(avctx, AV_LOG_ERROR, "Failed to create encoder.\n");
1143  return AVERROR(EINVAL);
1144  }
1145 
1146  return 0;
1147 }
1148 
1150 {
1152  HRESULT hr;
1153 
1154  D3D12_VIDEO_ENCODER_HEAP_DESC desc = {
1155  .NodeMask = 0,
1156  .Flags = D3D12_VIDEO_ENCODER_HEAP_FLAG_NONE,
1157  .EncodeCodec = ctx->codec->d3d12_codec,
1158  .EncodeProfile = ctx->profile->d3d12_profile,
1159  .EncodeLevel = ctx->level,
1160  .ResolutionsListCount = 1,
1161  .pResolutionList = &ctx->resolution,
1162  };
1163 
1164  hr = ID3D12VideoDevice3_CreateVideoEncoderHeap(ctx->video_device3, &desc,
1165  &IID_ID3D12VideoEncoderHeap, (void **)&ctx->encoder_heap);
1166  if (FAILED(hr)) {
1167  av_log(avctx, AV_LOG_ERROR, "Failed to create encoder heap.\n");
1168  return AVERROR(EINVAL);
1169  }
1170 
1171  return 0;
1172 }
1173 
1174 static void d3d12va_encode_free_buffer(void *opaque, uint8_t *data)
1175 {
1176  ID3D12Resource *pResource;
1177 
1178  pResource = (ID3D12Resource *)data;
1179  D3D12_OBJECT_RELEASE(pResource);
1180 }
1181 
1183 {
1184  AVCodecContext *avctx = opaque;
1185  FFHWBaseEncodeContext *base_ctx = avctx->priv_data;
1187  ID3D12Resource *pResource = NULL;
1188  HRESULT hr;
1189  AVBufferRef *ref;
1190  D3D12_HEAP_PROPERTIES heap_props;
1191  D3D12_HEAP_TYPE heap_type = D3D12_HEAP_TYPE_READBACK;
1192 
1193  D3D12_RESOURCE_DESC desc = {
1194  .Dimension = D3D12_RESOURCE_DIMENSION_BUFFER,
1195  .Alignment = 0,
1196  .Width = FFALIGN(3 * base_ctx->surface_width * base_ctx->surface_height + (1 << 16),
1197  D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT),
1198  .Height = 1,
1199  .DepthOrArraySize = 1,
1200  .MipLevels = 1,
1201  .Format = DXGI_FORMAT_UNKNOWN,
1202  .SampleDesc = { .Count = 1, .Quality = 0 },
1203  .Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR,
1204  .Flags = D3D12_RESOURCE_FLAG_NONE,
1205  };
1206 
1207  ctx->hwctx->device->lpVtbl->GetCustomHeapProperties(ctx->hwctx->device, &heap_props, 0, heap_type);
1208 
1209  hr = ID3D12Device_CreateCommittedResource(ctx->hwctx->device, &heap_props, D3D12_HEAP_FLAG_NONE,
1210  &desc, D3D12_RESOURCE_STATE_COMMON, NULL, &IID_ID3D12Resource,
1211  (void **)&pResource);
1212 
1213  if (FAILED(hr)) {
1214  av_log(avctx, AV_LOG_ERROR, "Failed to create d3d12 buffer.\n");
1215  return NULL;
1216  }
1217 
1218  ref = av_buffer_create((uint8_t *)(uintptr_t)pResource,
1219  sizeof(pResource),
1221  avctx, AV_BUFFER_FLAG_READONLY);
1222  if (!ref) {
1223  D3D12_OBJECT_RELEASE(pResource);
1224  return NULL;
1225  }
1226 
1227  return ref;
1228 }
1229 
1231 {
1232  FFHWBaseEncodeContext *base_ctx = avctx->priv_data;
1234  AVD3D12VAFramesContext *frames_ctx = base_ctx->input_frames->hwctx;
1235  HRESULT hr;
1236 
1237  ctx->req.NodeIndex = 0;
1238  ctx->req.Codec = ctx->codec->d3d12_codec;
1239  ctx->req.Profile = ctx->profile->d3d12_profile;
1240  ctx->req.InputFormat = frames_ctx->format;
1241  ctx->req.PictureTargetResolution = ctx->resolution;
1242 
1243  hr = ID3D12VideoDevice3_CheckFeatureSupport(ctx->video_device3,
1244  D3D12_FEATURE_VIDEO_ENCODER_RESOURCE_REQUIREMENTS,
1245  &ctx->req, sizeof(ctx->req));
1246  if (FAILED(hr)) {
1247  av_log(avctx, AV_LOG_ERROR, "Failed to check encoder resource requirements support.\n");
1248  return AVERROR(EINVAL);
1249  }
1250 
1251  if (!ctx->req.IsSupported) {
1252  av_log(avctx, AV_LOG_ERROR, "Encoder resource requirements unsupported.\n");
1253  return AVERROR(EINVAL);
1254  }
1255 
1256  ctx->output_buffer_pool = av_buffer_pool_init2(sizeof(ID3D12Resource *), avctx,
1258  if (!ctx->output_buffer_pool)
1259  return AVERROR(ENOMEM);
1260 
1261  return 0;
1262 }
1263 
1265 {
1267  ID3D12CommandAllocator *command_allocator = NULL;
1268  int err = AVERROR_UNKNOWN;
1269  HRESULT hr;
1270 
1271  D3D12_COMMAND_QUEUE_DESC queue_desc = {
1272  .Type = D3D12_COMMAND_LIST_TYPE_VIDEO_ENCODE,
1273  .Priority = 0,
1274  .Flags = D3D12_COMMAND_QUEUE_FLAG_NONE,
1275  .NodeMask = 0,
1276  };
1277 
1280  if (!ctx->allocator_queue)
1281  return AVERROR(ENOMEM);
1282 
1283  hr = ID3D12Device_CreateFence(ctx->hwctx->device, 0, D3D12_FENCE_FLAG_NONE,
1284  &IID_ID3D12Fence, (void **)&ctx->sync_ctx.fence);
1285  if (FAILED(hr)) {
1286  av_log(avctx, AV_LOG_ERROR, "Failed to create fence(%lx)\n", (long)hr);
1287  err = AVERROR_UNKNOWN;
1288  goto fail;
1289  }
1290 
1291  ctx->sync_ctx.event = CreateEvent(NULL, FALSE, FALSE, NULL);
1292  if (!ctx->sync_ctx.event)
1293  goto fail;
1294 
1295  err = d3d12va_get_valid_command_allocator(avctx, &command_allocator);
1296  if (err < 0)
1297  goto fail;
1298 
1299  hr = ID3D12Device_CreateCommandQueue(ctx->hwctx->device, &queue_desc,
1300  &IID_ID3D12CommandQueue, (void **)&ctx->command_queue);
1301  if (FAILED(hr)) {
1302  av_log(avctx, AV_LOG_ERROR, "Failed to create command queue(%lx)\n", (long)hr);
1303  err = AVERROR_UNKNOWN;
1304  goto fail;
1305  }
1306 
1307  hr = ID3D12Device_CreateCommandList(ctx->hwctx->device, 0, queue_desc.Type,
1308  command_allocator, NULL, &IID_ID3D12CommandList,
1309  (void **)&ctx->command_list);
1310  if (FAILED(hr)) {
1311  av_log(avctx, AV_LOG_ERROR, "Failed to create command list(%lx)\n", (long)hr);
1312  err = AVERROR_UNKNOWN;
1313  goto fail;
1314  }
1315 
1316  hr = ID3D12VideoEncodeCommandList2_Close(ctx->command_list);
1317  if (FAILED(hr)) {
1318  av_log(avctx, AV_LOG_ERROR, "Failed to close the command list(%lx)\n", (long)hr);
1319  err = AVERROR_UNKNOWN;
1320  goto fail;
1321  }
1322 
1323  ID3D12CommandQueue_ExecuteCommandLists(ctx->command_queue, 1, (ID3D12CommandList **)&ctx->command_list);
1324 
1325  err = d3d12va_sync_with_gpu(avctx);
1326  if (err < 0)
1327  goto fail;
1328 
1329  err = d3d12va_discard_command_allocator(avctx, command_allocator, ctx->sync_ctx.fence_value);
1330  if (err < 0)
1331  goto fail;
1332 
1333  return 0;
1334 
1335 fail:
1336  D3D12_OBJECT_RELEASE(command_allocator);
1337  return err;
1338 }
1339 
1341 {
1342  FFHWBaseEncodeContext *base_ctx = avctx->priv_data;
1343  AVD3D12VAFramesContext *hwctx;
1344  enum AVPixelFormat recon_format;
1345  int err;
1346 
1347  err = ff_hw_base_get_recon_format(base_ctx, NULL, &recon_format);
1348  if (err < 0)
1349  return err;
1350 
1351  base_ctx->recon_frames_ref = av_hwframe_ctx_alloc(base_ctx->device_ref);
1352  if (!base_ctx->recon_frames_ref)
1353  return AVERROR(ENOMEM);
1354 
1355  base_ctx->recon_frames = (AVHWFramesContext *)base_ctx->recon_frames_ref->data;
1356  hwctx = (AVD3D12VAFramesContext *)base_ctx->recon_frames->hwctx;
1357 
1358  base_ctx->recon_frames->format = AV_PIX_FMT_D3D12;
1359  base_ctx->recon_frames->sw_format = recon_format;
1360  base_ctx->recon_frames->width = base_ctx->surface_width;
1361  base_ctx->recon_frames->height = base_ctx->surface_height;
1362 
1363  hwctx->flags = D3D12_RESOURCE_FLAG_VIDEO_ENCODE_REFERENCE_ONLY |
1364  D3D12_RESOURCE_FLAG_DENY_SHADER_RESOURCE;
1365 
1366  err = av_hwframe_ctx_init(base_ctx->recon_frames_ref);
1367  if (err < 0) {
1368  av_log(avctx, AV_LOG_ERROR, "Failed to initialise reconstructed "
1369  "frame context: %d.\n", err);
1370  return err;
1371  }
1372 
1373  return 0;
1374 }
1375 
1377  .priv_size = sizeof(D3D12VAEncodePicture),
1378 
1380 
1381  .issue = &d3d12va_encode_issue,
1382 
1384 
1385  .free = &d3d12va_encode_free,
1386 };
1387 
1389 {
1390  return ff_hw_base_encode_receive_packet(avctx->priv_data, avctx, pkt);
1391 }
1392 
1394 {
1395  FFHWBaseEncodeContext *base_ctx = avctx->priv_data;
1397  D3D12_FEATURE_DATA_VIDEO_FEATURE_AREA_SUPPORT support = { 0 };
1398  int err;
1399  HRESULT hr;
1400 
1401  err = ff_hw_base_encode_init(avctx, base_ctx);
1402  if (err < 0)
1403  goto fail;
1404 
1405  base_ctx->op = &d3d12va_type;
1406 
1407  ctx->hwctx = base_ctx->device->hwctx;
1408 
1409  ctx->resolution.Width = base_ctx->input_frames->width;
1410  ctx->resolution.Height = base_ctx->input_frames->height;
1411 
1412  hr = ID3D12Device_QueryInterface(ctx->hwctx->device, &IID_ID3D12Device3, (void **)&ctx->device3);
1413  if (FAILED(hr)) {
1414  av_log(avctx, AV_LOG_ERROR, "ID3D12Device3 interface is not supported.\n");
1415  err = AVERROR_UNKNOWN;
1416  goto fail;
1417  }
1418 
1419  hr = ID3D12Device3_QueryInterface(ctx->device3, &IID_ID3D12VideoDevice3, (void **)&ctx->video_device3);
1420  if (FAILED(hr)) {
1421  av_log(avctx, AV_LOG_ERROR, "ID3D12VideoDevice3 interface is not supported.\n");
1422  err = AVERROR_UNKNOWN;
1423  goto fail;
1424  }
1425 
1426  if (FAILED(ID3D12VideoDevice3_CheckFeatureSupport(ctx->video_device3, D3D12_FEATURE_VIDEO_FEATURE_AREA_SUPPORT,
1427  &support, sizeof(support))) && !support.VideoEncodeSupport) {
1428  av_log(avctx, AV_LOG_ERROR, "D3D12 video device has no video encoder support.\n");
1429  err = AVERROR(EINVAL);
1430  goto fail;
1431  }
1432 
1433  err = d3d12va_encode_set_profile(avctx);
1434  if (err < 0)
1435  goto fail;
1436 
1437  err = d3d12va_encode_init_rate_control(avctx);
1438  if (err < 0)
1439  goto fail;
1440 
1441  if (ctx->codec->get_encoder_caps) {
1442  err = ctx->codec->get_encoder_caps(avctx);
1443  if (err < 0)
1444  goto fail;
1445  }
1446 
1447  err = d3d12va_encode_init_gop_structure(avctx);
1448  if (err < 0)
1449  goto fail;
1450 
1451  if (!(ctx->codec->flags & FF_HW_FLAG_SLICE_CONTROL) && avctx->slices > 0) {
1452  av_log(avctx, AV_LOG_WARNING, "Multiple slices were requested "
1453  "but this codec does not support controlling slices.\n");
1454  }
1455 
1457  if (err < 0)
1458  goto fail;
1459 
1461  if (err < 0)
1462  goto fail;
1463 
1465  if (err < 0)
1466  goto fail;
1467 
1468  if (ctx->codec->configure) {
1469  err = ctx->codec->configure(avctx);
1470  if (err < 0)
1471  goto fail;
1472  }
1473 
1474  if (ctx->codec->init_sequence_params) {
1475  err = ctx->codec->init_sequence_params(avctx);
1476  if (err < 0) {
1477  av_log(avctx, AV_LOG_ERROR, "Codec sequence initialisation "
1478  "failed: %d.\n", err);
1479  goto fail;
1480  }
1481  }
1482 
1483  if (ctx->codec->set_level) {
1484  err = ctx->codec->set_level(avctx);
1485  if (err < 0)
1486  goto fail;
1487  }
1488 
1489  base_ctx->output_delay = base_ctx->b_per_p;
1490  base_ctx->decode_delay = base_ctx->max_b_depth;
1491 
1492  err = d3d12va_create_encoder(avctx);
1493  if (err < 0)
1494  goto fail;
1495 
1496  err = d3d12va_create_encoder_heap(avctx);
1497  if (err < 0)
1498  goto fail;
1499 
1500  base_ctx->async_encode = 1;
1501  base_ctx->encode_fifo = av_fifo_alloc2(base_ctx->async_depth,
1502  sizeof(D3D12VAEncodePicture *), 0);
1503  if (!base_ctx->encode_fifo)
1504  return AVERROR(ENOMEM);
1505 
1506  return 0;
1507 
1508 fail:
1509  return err;
1510 }
1511 
1513 {
1514  int num_allocator = 0;
1515  FFHWBaseEncodeContext *base_ctx = avctx->priv_data;
1517  FFHWBaseEncodePicture *pic, *next;
1518  CommandAllocator allocator;
1519 
1520  if (!base_ctx->frame)
1521  return 0;
1522 
1523  for (pic = base_ctx->pic_start; pic; pic = next) {
1524  next = pic->next;
1525  d3d12va_encode_free(avctx, pic);
1526  }
1527 
1529 
1530  av_buffer_pool_uninit(&ctx->output_buffer_pool);
1531 
1532  D3D12_OBJECT_RELEASE(ctx->command_list);
1533  D3D12_OBJECT_RELEASE(ctx->command_queue);
1534 
1535  if (ctx->allocator_queue) {
1536  while (av_fifo_read(ctx->allocator_queue, &allocator, 1) >= 0) {
1537  num_allocator++;
1539  }
1540 
1541  av_log(avctx, AV_LOG_VERBOSE, "Total number of command allocators reused: %d\n", num_allocator);
1542  }
1543 
1544  av_fifo_freep2(&ctx->allocator_queue);
1545 
1546  D3D12_OBJECT_RELEASE(ctx->sync_ctx.fence);
1547  if (ctx->sync_ctx.event)
1548  CloseHandle(ctx->sync_ctx.event);
1549 
1550  D3D12_OBJECT_RELEASE(ctx->encoder_heap);
1551  D3D12_OBJECT_RELEASE(ctx->encoder);
1552  D3D12_OBJECT_RELEASE(ctx->video_device3);
1553  D3D12_OBJECT_RELEASE(ctx->device3);
1554 
1555  ff_hw_base_encode_close(base_ctx);
1556 
1557  return 0;
1558 }
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
FF_HW_PICTURE_TYPE_IDR
@ FF_HW_PICTURE_TYPE_IDR
Definition: hw_base_encode.h:39
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:3441
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:1340
av_frame_free
void av_frame_free(AVFrame **frame)
Free the frame and any dynamically allocated objects in it, e.g.
Definition: frame.c:63
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:421
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:552
ff_hw_base_encode_init
int ff_hw_base_encode_init(AVCodecContext *avctx, FFHWBaseEncodeContext *ctx)
Definition: hw_base_encode.c:776
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:442
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:809
FFHWBaseEncodePicture::is_reference
int is_reference
Definition: hw_base_encode.h:87
fail
#define fail()
Definition: checkasm.h:199
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:718
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:1149
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
FF_HW_FLAG_SLICE_CONTROL
@ FF_HW_FLAG_SLICE_CONTROL
Definition: hw_base_encode.h:47
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
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
MAX_PARAM_BUFFER_SIZE
@ MAX_PARAM_BUFFER_SIZE
Definition: vaapi_encode.h:47
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
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:1174
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:1264
ff_d3d12va_encode_init
int ff_d3d12va_encode_init(AVCodecContext *avctx)
Definition: d3d12va_encode.c:1393
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:1376
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
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:1182
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
FF_HW_FLAG_CONSTANT_QUALITY_ONLY
@ FF_HW_FLAG_CONSTANT_QUALITY_ONLY
Definition: hw_base_encode.h:49
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:2276
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:1122
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:1230
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
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:1512
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:1388
AVPacket
This structure stores compressed data.
Definition: packet.h:529
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:1049
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