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