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
31
35
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)))
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));
60
63 }
64
69
71 {
72 HRESULT hr;
75
77 uint64_t completion = ID3D12Fence_GetCompletedValue(
ctx->sync_ctx.fence);
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)) {
90 }
91
92 return 0;
93 }
94
96 {
98
101 .fence_value = fence_value,
102 };
103
105
106 return 0;
107 }
108
111 {
114 uint64_t completion;
115
117
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)))
128
129 WaitForSingleObjectEx(
ctx->sync_ctx.event, INFINITE, FALSE);
130 }
131
135
137
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,
167 if (FAILED(hr)) {
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,
179
180 if (FAILED(hr)) {
183 }
184
185 return 0;
186 }
187
190 {
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 int barriers_ref_index = 0;
205 D3D12_RESOURCE_BARRIER *barriers_ref =
NULL;
206
207 D3D12_VIDEO_ENCODER_ENCODEFRAME_INPUT_ARGUMENTS input_args = {
208 .SequenceControlDesc = {
209 .Flags = D3D12_VIDEO_ENCODER_SEQUENCE_CONTROL_FLAG_NONE,
210 .IntraRefreshConfig = { 0 },
211 .RateControl =
ctx->rc,
212 .PictureTargetResolution =
ctx->resolution,
213 .SelectedLayoutMode = D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_FULL_FRAME,
214 .FrameSubregionsLayoutData = { 0 },
215 .CodecGopSequence =
ctx->gop,
216 },
218 .InputFrameSubresource = 0,
219 };
220
221 D3D12_VIDEO_ENCODER_ENCODEFRAME_OUTPUT_ARGUMENTS output_args = { 0 };
222
223 D3D12_VIDEO_ENCODER_RESOLVE_METADATA_INPUT_ARGUMENTS input_metadata = {
224 .EncoderCodec =
ctx->codec->d3d12_codec,
225 .EncoderProfile =
ctx->profile->d3d12_profile,
226 .EncoderInputFormat = frames_hwctx->
format,
227 .EncodedPictureEffectiveResolution =
ctx->resolution,
228 };
229
230 D3D12_VIDEO_ENCODER_RESOLVE_METADATA_OUTPUT_ARGUMENTS output_metadata = { 0 };
231
233
239 } else {
244 }
246
252 }
254 }
255 }
256
261 }
265 }
266
268
272
274
279 }
283
285 if (err < 0)
287
288 if (
ctx->codec->init_picture_params) {
289 err =
ctx->codec->init_picture_params(avctx, base_pic);
290 if (err < 0) {
292 "parameters: %d.\n", err);
294 }
295 }
296
298 if (
ctx->codec->write_sequence_header) {
299 bit_len = 8 *
sizeof(
data);
300 err =
ctx->codec->write_sequence_header(avctx,
data, &bit_len);
301 if (err < 0) {
303 "header: %d.\n", err);
305 }
310
312 if (FAILED(hr)) {
315 }
316
319 }
320 }
321
322 d3d12_refs.NumTexture2Ds = base_pic->
nb_refs[0] + base_pic->
nb_refs[1];
323 if (d3d12_refs.NumTexture2Ds) {
324 d3d12_refs.ppTexture2Ds =
av_calloc(d3d12_refs.NumTexture2Ds,
325 sizeof(*d3d12_refs.ppTexture2Ds));
326 if (!d3d12_refs.ppTexture2Ds) {
329 }
330
331 if (
ctx->is_texture_array) {
332 d3d12_refs.pSubresources =
av_calloc(d3d12_refs.NumTexture2Ds,
333 sizeof(*d3d12_refs.pSubresources));
334 if (!d3d12_refs.pSubresources) {
337 }
338 }
339
341 for (j = 0; j < base_pic->
nb_refs[0]; j++) {
343 if (
ctx->is_texture_array)
346 }
347 for (j = 0; j < base_pic->
nb_refs[1]; j++) {
349 if (
ctx->is_texture_array)
352 }
353 }
354
355 input_args.PictureControlDesc.IntraRefreshFrameIndex = 0;
357 input_args.PictureControlDesc.Flags |= D3D12_VIDEO_ENCODER_PICTURE_CONTROL_FLAG_USED_AS_REFERENCE_PICTURE;
358
359 input_args.PictureControlDesc.PictureControlCodecData = pic->
pic_ctl;
360 input_args.PictureControlDesc.ReferenceFrames = d3d12_refs;
362
366 output_args.ReconstructedPicture.ReconstructedPictureSubresource =
ctx->is_texture_array ? pic->
subresource_index : 0;
368 output_args.EncoderOutputMetadata.Offset = 0;
369
371 input_metadata.HWLayoutMetadata.Offset = 0;
372
374 output_metadata.ResolvedLayoutMetadata.Offset = 0;
375
377 if (err < 0)
379
380 hr = ID3D12CommandAllocator_Reset(command_allocator);
381 if (FAILED(hr)) {
384 }
385
386 hr = ID3D12VideoEncodeCommandList2_Reset(cmd_list, command_allocator);
387 if (FAILED(hr)) {
390 }
391
392 #define TRANSITION_BARRIER(res, subres, before, after) \
393 (D3D12_RESOURCE_BARRIER) { \
394 .Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION, \
395 .Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE, \
396 .Transition = { \
397 .pResource = res, \
398 .Subresource = subres, \
399 .StateBefore = before, \
400 .StateAfter = after, \
401 }, \
402 }
403
405 D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES,
406 D3D12_RESOURCE_STATE_COMMON,
407 D3D12_RESOURCE_STATE_VIDEO_ENCODE_READ);
409 D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES,
410 D3D12_RESOURCE_STATE_COMMON,
411 D3D12_RESOURCE_STATE_VIDEO_ENCODE_WRITE);
413 D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES,
414 D3D12_RESOURCE_STATE_COMMON,
415 D3D12_RESOURCE_STATE_VIDEO_ENCODE_WRITE);
417 D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES,
418 D3D12_RESOURCE_STATE_COMMON,
419 D3D12_RESOURCE_STATE_VIDEO_ENCODE_WRITE);
420
421 ID3D12VideoEncodeCommandList2_ResourceBarrier(cmd_list, 4, barriers);
422
423 if (
ctx->is_texture_array)
425 sizeof(D3D12_RESOURCE_BARRIER));
426 else
428
429 if (
ctx->is_texture_array) {
430 D3D12_RESOURCE_DESC references_tex_array_desc = { 0 };
432
433 for (uint32_t reference_subresource = 0; reference_subresource < references_tex_array_desc.DepthOrArraySize;
434 reference_subresource++) {
435
436 uint32_t array_size = references_tex_array_desc.DepthOrArraySize;
437 uint32_t mip_slice = reference_subresource % references_tex_array_desc.MipLevels;
438 uint32_t array_slice = (reference_subresource / references_tex_array_desc.MipLevels) % array_size;
439
440 for (uint32_t plane_slice = 0; plane_slice <
ctx->plane_count; plane_slice++) {
441 uint32_t outputSubresource = mip_slice + array_slice * references_tex_array_desc.MipLevels +
442 plane_slice * references_tex_array_desc.MipLevels * array_size;
445 D3D12_RESOURCE_STATE_COMMON,
446 D3D12_RESOURCE_STATE_VIDEO_ENCODE_WRITE);
447 } else {
449 D3D12_RESOURCE_STATE_COMMON,
450 D3D12_RESOURCE_STATE_VIDEO_ENCODE_READ);
451 }
452 }
453 }
454 } else {
456 D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES,
457 D3D12_RESOURCE_STATE_COMMON,
458 D3D12_RESOURCE_STATE_VIDEO_ENCODE_WRITE);
459
460 if (d3d12_refs.NumTexture2Ds) {
461 for (
i = 0;
i < d3d12_refs.NumTexture2Ds;
i++)
463 D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES,
464 D3D12_RESOURCE_STATE_COMMON,
465 D3D12_RESOURCE_STATE_VIDEO_ENCODE_READ);
466 }
467 }
468 ID3D12VideoEncodeCommandList2_ResourceBarrier(cmd_list, barriers_ref_index, barriers_ref);
469
470 ID3D12VideoEncodeCommandList2_EncodeFrame(cmd_list,
ctx->encoder,
ctx->encoder_heap,
471 &input_args, &output_args);
472
474 D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES,
475 D3D12_RESOURCE_STATE_VIDEO_ENCODE_WRITE,
476 D3D12_RESOURCE_STATE_VIDEO_ENCODE_READ);
477
478 ID3D12VideoEncodeCommandList2_ResourceBarrier(cmd_list, 1, &barriers[3]);
479
480 ID3D12VideoEncodeCommandList2_ResolveEncoderOutputMetadata(cmd_list, &input_metadata, &output_metadata);
481
482 if (barriers_ref_index > 0) {
483 for (
i = 0;
i < barriers_ref_index;
i++)
484 FFSWAP(D3D12_RESOURCE_STATES, barriers_ref[
i].Transition.StateBefore, barriers_ref[
i].Transition.StateAfter);
485
486 ID3D12VideoEncodeCommandList2_ResourceBarrier(cmd_list, barriers_ref_index,
487 barriers_ref);
488 }
489
491 D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES,
492 D3D12_RESOURCE_STATE_VIDEO_ENCODE_READ,
493 D3D12_RESOURCE_STATE_COMMON);
495 D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES,
496 D3D12_RESOURCE_STATE_VIDEO_ENCODE_WRITE,
497 D3D12_RESOURCE_STATE_COMMON);
499 D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES,
500 D3D12_RESOURCE_STATE_VIDEO_ENCODE_READ,
501 D3D12_RESOURCE_STATE_COMMON);
503 D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES,
504 D3D12_RESOURCE_STATE_VIDEO_ENCODE_WRITE,
505 D3D12_RESOURCE_STATE_COMMON);
506
507 ID3D12VideoEncodeCommandList2_ResourceBarrier(cmd_list, 4, barriers);
508
509 hr = ID3D12VideoEncodeCommandList2_Close(cmd_list);
510 if (FAILED(hr)) {
513 }
514
517 if (FAILED(hr)) {
520 }
521
522 ID3D12CommandQueue_ExecuteCommandLists(
ctx->command_queue, 1, (ID3D12CommandList **)&
ctx->command_list);
523
526 if (FAILED(hr)) {
529 }
530
531 hr = ID3D12CommandQueue_Signal(
ctx->command_queue,
ctx->sync_ctx.fence, ++
ctx->sync_ctx.fence_value);
532 if (FAILED(hr)) {
535 }
536
538 if (err < 0)
540
542
543 if (d3d12_refs.ppTexture2Ds)
545
546 if (
ctx->is_texture_array && d3d12_refs.pSubresources)
547 av_freep(&d3d12_refs.pSubresources);
548
549 if (barriers_ref)
551
552 return 0;
553
555 if (command_allocator)
557
558 if (d3d12_refs.ppTexture2Ds)
560
561 if (
ctx->is_texture_array && d3d12_refs.pSubresources)
562 av_freep(&d3d12_refs.pSubresources);
563
564 if (barriers_ref)
566
567 if (
ctx->codec->free_picture_params)
568 ctx->codec->free_picture_params(pic);
569
574 return err;
575 }
576
579 {
581
583
586 "%"PRId64"/%"PRId64".\n",
588
591 }
592
595
596 return 0;
597 }
598
600 {
602
603 switch (
ctx->rc.Mode)
604 {
605 case D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE_CQP:
606 av_freep(&
ctx->rc.ConfigParams.pConfiguration_CQP);
607 break;
608 case D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE_CBR:
609 av_freep(&
ctx->rc.ConfigParams.pConfiguration_CBR);
610 break;
611 case D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE_VBR:
612 av_freep(&
ctx->rc.ConfigParams.pConfiguration_VBR);
613 break;
614 case D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE_QVBR:
615 av_freep(&
ctx->rc.ConfigParams.pConfiguration_QVBR);
616 break;
617 default:
618 break;
619 }
620
621 return 0;
622 }
623
625 {
629
630 if (
ctx->codec->picture_priv_data_size > 0) {
634 }
635
637
638 return 0;
639 }
640
642 {
645
648
649 if (
ctx->codec->free_picture_params)
650 ctx->codec->free_picture_params(priv);
651
652 return 0;
653 }
654
657 {
658 D3D12_VIDEO_ENCODER_OUTPUT_METADATA *meta =
NULL;
660 HRESULT hr;
661 int err;
662
664 if (FAILED(hr)) {
666 return err;
667 }
668
669 meta = (D3D12_VIDEO_ENCODER_OUTPUT_METADATA *)
data;
670
671 if (meta->EncodeErrorFlags != D3D12_VIDEO_ENCODER_ENCODE_ERROR_FLAG_NO_ERROR) {
674 return err;
675 }
676
677 if (meta->EncodedBitstreamWrittenBytesCount == 0) {
680 return err;
681 }
682
683 *
size = meta->EncodedBitstreamWrittenBytesCount;
684
686
687 return 0;
688 }
689
692 {
693 int err;
694 uint8_t *ptr, *mapped_data;
695 size_t total_size = 0;
696 HRESULT hr;
697
699 if (err < 0)
700 goto end;
701
704
706 if (FAILED(hr)) {
708 goto end;
709 }
710
712 if (err < 0)
713 goto end;
715
717
721
722 memcpy(ptr, mapped_data, total_size);
723
725
726 end:
729 return err;
730 }
731
734 {
738 int err;
739
741 if (err < 0)
742 return err;
743
745 if (err < 0)
746 return err;
747
750
752 pkt_ptr, 0);
753
754 return 0;
755 }
756
758 {
764
770 }
771
772 depth =
desc->comp[0].depth;
773 for (
i = 1;
i <
desc->nb_components;
i++) {
774 if (
desc->comp[
i].depth != depth) {
778 }
779 }
782
784 for (
i = 0; (
ctx->codec->profiles[
i].av_profile !=
789 continue;
790 if (
desc->nb_components > 1 &&
793 continue;
796 continue;
797
799 break;
800 }
804 }
805
807 return 0;
808 }
809
811 // Bitrate Quality
812 // | Maxrate | HRD/VBV
813 { 0 }, // | | | |
814 {
RC_MODE_CQP,
"CQP", 0, 0, 1, 0, D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE_CQP },
815 {
RC_MODE_CBR,
"CBR", 1, 0, 0, 1, D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE_CBR },
816 {
RC_MODE_VBR,
"VBR", 1, 1, 0, 1, D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE_VBR },
817 {
RC_MODE_QVBR,
"QVBR", 1, 1, 1, 1, D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE_QVBR },
818 };
819
821 {
822 HRESULT hr;
824 D3D12_FEATURE_DATA_VIDEO_ENCODER_RATE_CONTROL_MODE d3d12_rc_mode = {
825 .Codec =
ctx->codec->d3d12_codec,
826 };
827
829 return 0;
830
831 d3d12_rc_mode.IsSupported = 0;
832 d3d12_rc_mode.RateControlMode =
rc_mode->d3d12_mode;
833
834 hr = ID3D12VideoDevice3_CheckFeatureSupport(
ctx->video_device3,
835 D3D12_FEATURE_VIDEO_ENCODER_RATE_CONTROL_MODE,
836 &d3d12_rc_mode, sizeof(d3d12_rc_mode));
837 if (FAILED(hr)) {
839 return 0;
840 }
841
842 return d3d12_rc_mode.IsSupported;
843 }
844
846 {
850 int rc_quality;
852 int64_t hrd_initial_buffer_fullness;
853 int fr_num, fr_den;
855
856 #define SET_QP_RANGE(ctl) do { \
857 if (avctx->qmin > 0 || avctx->qmax > 0) { \
858 ctl->MinQP = avctx->qmin; \
859 ctl->MaxQP = avctx->qmax; \
860 ctx->rc.Flags |= D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_QP_RANGE; \
861 } \
862 } while(0)
863
864 #define SET_MAX_FRAME_SIZE(ctl) do { \
865 if (ctx->max_frame_size > 0) { \
866 ctl->MaxFrameBitSize = ctx->max_frame_size * 8; \
867 ctx->rc.Flags |= D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_MAX_FRAME_SIZE; \
868 } \
869 } while(0)
870
871 // Rate control mode selection:
872 // * If the user has set a mode explicitly with the rc_mode option,
873 // use it and fail if it is not available.
874 // * If an explicit QP option has been set, use CQP.
875 // * If the codec is CQ-only, use CQP.
876 // * If the QSCALE avcodec option is set, use CQP.
877 // * If bitrate and quality are both set, try QVBR.
878 // * If quality is set, try CQP.
879 // * If bitrate and maxrate are set and have the same value, try CBR.
880 // * If a bitrate is set, try VBR, then CBR.
881 // * If no bitrate is set, try CQP.
882
883 #define TRY_RC_MODE(mode, fail) do { \
884 rc_mode = &d3d12va_encode_rc_modes[mode]; \
885 if (!(rc_mode->d3d12_mode && check_rate_control_support(avctx, rc_mode))) { \
886 if (fail) { \
887 av_log(avctx, AV_LOG_ERROR, "Driver does not support %s " \
888 "RC mode.\n", rc_mode->name); \
889 return AVERROR(EINVAL); \
890 } \
891 av_log(avctx, AV_LOG_DEBUG, "Driver does not support %s " \
892 "RC mode.\n", rc_mode->name); \
893 rc_mode = NULL; \
894 } else { \
895 goto rc_mode_found; \
896 } \
897 } while (0)
898
899 if (
ctx->explicit_rc_mode)
901
902 if (
ctx->explicit_qp)
904
907
910
913
916 }
917
920
924 } else {
926 }
927
929 "RC mode compatible with selected options.\n");
931
932 rc_mode_found:
938 }
939
944 "bitrate (%"PRId64") must not be greater than "
945 "maxrate (%"PRId64
").\n", avctx->
bit_rate,
948 }
949 rc_target_bitrate = avctx->
bit_rate;
951 } else {
952 // We only have a target bitrate, but this mode requires
953 // that a maximum rate be supplied as well. Since the
954 // user does not want this to be a constraint, arbitrarily
955 // pick a maximum rate of double the target rate.
956 rc_target_bitrate = avctx->
bit_rate;
957 rc_peak_bitrate = 2 * avctx->
bit_rate;
958 }
959 } else {
962 "in %s RC mode.\n",
rc_mode->name);
963 }
964 rc_target_bitrate = avctx->
bit_rate;
965 rc_peak_bitrate = 0;
966 }
967 } else {
968 rc_target_bitrate = 0;
969 rc_peak_bitrate = 0;
970 }
971
973 if (
ctx->explicit_qp) {
974 rc_quality =
ctx->explicit_qp;
978 else
980 } else {
981 rc_quality =
ctx->codec->default_quality;
983 "using default (%d).\n", rc_quality);
984 }
985 } else {
986 rc_quality = 0;
987 }
988
994 else
999 "must have initial buffer size (%d) <= "
1000 "buffer size (%"PRId64").\n",
1003 }
1005 } else {
1006 hrd_initial_buffer_fullness = hrd_buffer_size * 3 / 4;
1007 }
1008 } else {
1011 "in %s RC mode.\n",
rc_mode->name);
1012 }
1013
1014 hrd_buffer_size = 0;
1015 hrd_initial_buffer_fullness = 0;
1016 }
1017
1018 if (rc_target_bitrate > UINT32_MAX ||
1019 hrd_buffer_size > UINT32_MAX ||
1020 hrd_initial_buffer_fullness > UINT32_MAX) {
1022 "greater are not supported by D3D12.\n");
1024 }
1025
1026 ctx->rc_quality = rc_quality;
1027
1029
1032
1035 "initial fullness %"PRId64" bits.\n",
1036 hrd_buffer_size, hrd_initial_buffer_fullness);
1037 }
1038
1042 else
1045
1047 fr_num, fr_den, (double)fr_num / fr_den);
1048
1049 ctx->rc.Flags = D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_NONE;
1050 ctx->rc.TargetFrameRate.Numerator = fr_num;
1051 ctx->rc.TargetFrameRate.Denominator = fr_den;
1053
1056 // cqp ConfigParams will be updated in ctx->codec->configure.
1057 break;
1059 D3D12_VIDEO_ENCODER_RATE_CONTROL_CBR *cbr_ctl;
1060
1061 ctx->rc.ConfigParams.DataSize =
sizeof(D3D12_VIDEO_ENCODER_RATE_CONTROL_CBR);
1063 if (!cbr_ctl)
1065
1066 cbr_ctl->TargetBitRate = rc_target_bitrate;
1067 cbr_ctl->VBVCapacity = hrd_buffer_size;
1068 cbr_ctl->InitialVBVFullness = hrd_initial_buffer_fullness;
1069 ctx->rc.Flags |= D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_VBV_SIZES;
1070
1073
1074 ctx->rc.ConfigParams.pConfiguration_CBR = cbr_ctl;
1075 break;
1076 }
1078 D3D12_VIDEO_ENCODER_RATE_CONTROL_VBR *vbr_ctl;
1079
1080 ctx->rc.ConfigParams.DataSize =
sizeof(D3D12_VIDEO_ENCODER_RATE_CONTROL_VBR);
1082 if (!vbr_ctl)
1084
1085 vbr_ctl->TargetAvgBitRate = rc_target_bitrate;
1086 vbr_ctl->PeakBitRate = rc_peak_bitrate;
1087 vbr_ctl->VBVCapacity = hrd_buffer_size;
1088 vbr_ctl->InitialVBVFullness = hrd_initial_buffer_fullness;
1089 ctx->rc.Flags |= D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_VBV_SIZES;
1090
1093
1094 ctx->rc.ConfigParams.pConfiguration_VBR = vbr_ctl;
1095 break;
1096 }
1098 D3D12_VIDEO_ENCODER_RATE_CONTROL_QVBR *qvbr_ctl;
1099
1100 ctx->rc.ConfigParams.DataSize =
sizeof(D3D12_VIDEO_ENCODER_RATE_CONTROL_QVBR);
1102 if (!qvbr_ctl)
1104
1105 qvbr_ctl->TargetAvgBitRate = rc_target_bitrate;
1106 qvbr_ctl->PeakBitRate = rc_peak_bitrate;
1107 qvbr_ctl->ConstantQualityTarget = rc_quality;
1108
1111
1112 ctx->rc.ConfigParams.pConfiguration_QVBR = qvbr_ctl;
1113 break;
1114 }
1115 default:
1116 break;
1117 }
1118 return 0;
1119 }
1120
1122 {
1125 uint32_t ref_l0, ref_l1;
1126 int err;
1127 HRESULT hr;
1128 D3D12_FEATURE_DATA_VIDEO_ENCODER_CODEC_PICTURE_CONTROL_SUPPORT support;
1129 union {
1130 D3D12_VIDEO_ENCODER_CODEC_PICTURE_CONTROL_SUPPORT_H264 h264;
1131 D3D12_VIDEO_ENCODER_CODEC_PICTURE_CONTROL_SUPPORT_HEVC hevc;
1132 } codec_support;
1133
1134 support.NodeIndex = 0;
1135 support.Codec =
ctx->codec->d3d12_codec;
1136 support.Profile =
ctx->profile->d3d12_profile;
1137
1138 switch (
ctx->codec->d3d12_codec) {
1139 case D3D12_VIDEO_ENCODER_CODEC_H264:
1140 support.PictureSupport.DataSize = sizeof(codec_support.h264);
1141 support.PictureSupport.pH264Support = &codec_support.h264;
1142 break;
1143
1144 case D3D12_VIDEO_ENCODER_CODEC_HEVC:
1145 support.PictureSupport.DataSize = sizeof(codec_support.hevc);
1146 support.PictureSupport.pHEVCSupport = &codec_support.hevc;
1147 break;
1148
1149 default:
1151 }
1152
1153 hr = ID3D12VideoDevice3_CheckFeatureSupport(
ctx->video_device3, D3D12_FEATURE_VIDEO_ENCODER_CODEC_PICTURE_CONTROL_SUPPORT,
1154 &support, sizeof(support));
1155 if (FAILED(hr))
1157
1158 if (support.IsSupported) {
1159 switch (
ctx->codec->d3d12_codec) {
1160 case D3D12_VIDEO_ENCODER_CODEC_H264:
1161 ref_l0 =
FFMIN(support.PictureSupport.pH264Support->MaxL0ReferencesForP,
1162 support.PictureSupport.pH264Support->MaxL1ReferencesForB ?
1163 support.PictureSupport.pH264Support->MaxL1ReferencesForB : UINT_MAX);
1164 ref_l1 = support.PictureSupport.pH264Support->MaxL1ReferencesForB;
1165 break;
1166
1167 case D3D12_VIDEO_ENCODER_CODEC_HEVC:
1168 ref_l0 =
FFMIN(support.PictureSupport.pHEVCSupport->MaxL0ReferencesForP,
1169 support.PictureSupport.pHEVCSupport->MaxL1ReferencesForB ?
1170 support.PictureSupport.pHEVCSupport->MaxL1ReferencesForB : UINT_MAX);
1171 ref_l1 = support.PictureSupport.pHEVCSupport->MaxL1ReferencesForB;
1172 break;
1173
1174 default:
1176 }
1177 } else {
1178 ref_l0 = ref_l1 = 0;
1179 }
1180
1181 if (ref_l0 > 0 && ref_l1 > 0 &&
ctx->bi_not_empty) {
1184 "replacing them with B-frames.\n");
1185 }
1186
1188 if (err < 0)
1189 return err;
1190
1191 return 0;
1192 }
1193
1195 {
1199 HRESULT hr;
1200
1201 D3D12_VIDEO_ENCODER_DESC
desc = {
1202 .NodeMask = 0,
1203 .Flags = D3D12_VIDEO_ENCODER_FLAG_NONE,
1204 .EncodeCodec =
ctx->codec->d3d12_codec,
1205 .EncodeProfile =
ctx->profile->d3d12_profile,
1206 .InputFormat = frames_hwctx->
format,
1207 .CodecConfiguration =
ctx->codec_conf,
1208 .MaxMotionEstimationPrecision = D3D12_VIDEO_ENCODER_MOTION_ESTIMATION_PRECISION_MODE_MAXIMUM,
1209 };
1210
1211 hr = ID3D12VideoDevice3_CreateVideoEncoder(
ctx->video_device3, &
desc, &IID_ID3D12VideoEncoder,
1212 (
void **)&
ctx->encoder);
1213 if (FAILED(hr)) {
1216 }
1217
1218 return 0;
1219 }
1220
1222 {
1224 HRESULT hr;
1225
1226 D3D12_VIDEO_ENCODER_HEAP_DESC
desc = {
1227 .NodeMask = 0,
1228 .Flags = D3D12_VIDEO_ENCODER_HEAP_FLAG_NONE,
1229 .EncodeCodec =
ctx->codec->d3d12_codec,
1230 .EncodeProfile =
ctx->profile->d3d12_profile,
1231 .EncodeLevel =
ctx->level,
1232 .ResolutionsListCount = 1,
1233 .pResolutionList = &
ctx->resolution,
1234 };
1235
1236 hr = ID3D12VideoDevice3_CreateVideoEncoderHeap(
ctx->video_device3, &
desc,
1237 &IID_ID3D12VideoEncoderHeap, (
void **)&
ctx->encoder_heap);
1238 if (FAILED(hr)) {
1241 }
1242
1243 return 0;
1244 }
1245
1247 {
1248 ID3D12Resource *pResource;
1249
1250 pResource = (ID3D12Resource *)
data;
1252 }
1253
1255 {
1259 ID3D12Resource *pResource =
NULL;
1260 HRESULT hr;
1262 D3D12_HEAP_PROPERTIES heap_props;
1263 D3D12_HEAP_TYPE heap_type = D3D12_HEAP_TYPE_READBACK;
1264
1265 D3D12_RESOURCE_DESC
desc = {
1266 .Dimension = D3D12_RESOURCE_DIMENSION_BUFFER,
1267 .Alignment = 0,
1269 D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT),
1270 .Height = 1,
1271 .DepthOrArraySize = 1,
1272 .MipLevels = 1,
1273 .Format = DXGI_FORMAT_UNKNOWN,
1274 .SampleDesc = { .Count = 1, .Quality = 0 },
1275 .Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR,
1276 .Flags = D3D12_RESOURCE_FLAG_NONE,
1277 };
1278
1279 ctx->hwctx->device->lpVtbl->GetCustomHeapProperties(
ctx->hwctx->device, &heap_props, 0, heap_type);
1280
1281 hr = ID3D12Device_CreateCommittedResource(
ctx->hwctx->device, &heap_props, D3D12_HEAP_FLAG_NONE,
1282 &
desc, D3D12_RESOURCE_STATE_COMMON,
NULL, &IID_ID3D12Resource,
1283 (void **)&pResource);
1284
1285 if (FAILED(hr)) {
1288 }
1289
1291 sizeof(pResource),
1297 }
1298
1300 }
1301
1303 {
1307 HRESULT hr;
1308
1309 ctx->req.NodeIndex = 0;
1310 ctx->req.Codec =
ctx->codec->d3d12_codec;
1311 ctx->req.Profile =
ctx->profile->d3d12_profile;
1312 ctx->req.InputFormat = frames_ctx->
format;
1313 ctx->req.PictureTargetResolution =
ctx->resolution;
1314
1315 hr = ID3D12VideoDevice3_CheckFeatureSupport(
ctx->video_device3,
1316 D3D12_FEATURE_VIDEO_ENCODER_RESOURCE_REQUIREMENTS,
1317 &
ctx->req,
sizeof(
ctx->req));
1318 if (FAILED(hr)) {
1319 av_log(avctx,
AV_LOG_ERROR,
"Failed to check encoder resource requirements support.\n");
1321 }
1322
1323 if (!
ctx->req.IsSupported) {
1326 }
1327
1330 if (!
ctx->output_buffer_pool)
1332
1333 return 0;
1334 }
1335
1337 {
1339 ID3D12CommandAllocator *command_allocator =
NULL;
1341 HRESULT hr;
1342
1343 D3D12_COMMAND_QUEUE_DESC queue_desc = {
1344 .Type = D3D12_COMMAND_LIST_TYPE_VIDEO_ENCODE,
1345 .Priority = 0,
1346 .Flags = D3D12_COMMAND_QUEUE_FLAG_NONE,
1347 .NodeMask = 0,
1348 };
1349
1352 if (!
ctx->allocator_queue)
1354
1355 hr = ID3D12Device_CreateFence(
ctx->hwctx->device, 0, D3D12_FENCE_FLAG_NONE,
1356 &IID_ID3D12Fence, (
void **)&
ctx->sync_ctx.fence);
1357 if (FAILED(hr)) {
1361 }
1362
1363 ctx->sync_ctx.event = CreateEvent(
NULL, FALSE, FALSE,
NULL);
1364 if (!
ctx->sync_ctx.event)
1366
1368 if (err < 0)
1370
1371 hr = ID3D12Device_CreateCommandQueue(
ctx->hwctx->device, &queue_desc,
1372 &IID_ID3D12CommandQueue, (
void **)&
ctx->command_queue);
1373 if (FAILED(hr)) {
1377 }
1378
1379 hr = ID3D12Device_CreateCommandList(
ctx->hwctx->device, 0, queue_desc.Type,
1380 command_allocator,
NULL, &IID_ID3D12CommandList,
1381 (
void **)&
ctx->command_list);
1382 if (FAILED(hr)) {
1386 }
1387
1388 hr = ID3D12VideoEncodeCommandList2_Close(
ctx->command_list);
1389 if (FAILED(hr)) {
1393 }
1394
1395 ID3D12CommandQueue_ExecuteCommandLists(
ctx->command_queue, 1, (ID3D12CommandList **)&
ctx->command_list);
1396
1398 if (err < 0)
1400
1402 if (err < 0)
1404
1405 return 0;
1406
1409 return err;
1410 }
1411
1413 {
1418 int err;
1419
1421 if (err < 0)
1422 return err;
1423
1427
1430
1435
1436 hwctx->
resource_flags = D3D12_RESOURCE_FLAG_VIDEO_ENCODE_REFERENCE_ONLY |
1437 D3D12_RESOURCE_FLAG_DENY_SHADER_RESOURCE;
1438 if (
ctx->is_texture_array) {
1441 }
1442
1444 if (err < 0) {
1446 "frame context: %d.\n", err);
1447 return err;
1448 }
1449
1450 return 0;
1451 }
1452
1455
1457
1459
1461
1463 };
1464
1466 {
1468 }
1469
1471 {
1474 D3D12_FEATURE_DATA_VIDEO_FEATURE_AREA_SUPPORT support = { 0 };
1475 D3D12_FEATURE_DATA_FORMAT_INFO format_info = { 0 };
1476 int err;
1477 HRESULT hr;
1478
1480 if (err < 0)
1482
1484
1486
1489
1490 hr = ID3D12Device_QueryInterface(
ctx->hwctx->device, &IID_ID3D12Device3, (
void **)&
ctx->device3);
1491 if (FAILED(hr)) {
1495 }
1496
1497 hr = ID3D12Device3_QueryInterface(
ctx->device3, &IID_ID3D12VideoDevice3, (
void **)&
ctx->video_device3);
1498 if (FAILED(hr)) {
1502 }
1503
1504 if (FAILED(ID3D12VideoDevice3_CheckFeatureSupport(
ctx->video_device3, D3D12_FEATURE_VIDEO_FEATURE_AREA_SUPPORT,
1505 &support, sizeof(support))) && !support.VideoEncodeSupport) {
1509 }
1510
1512 if (FAILED(ID3D12VideoDevice_CheckFeatureSupport(
ctx->hwctx->device, D3D12_FEATURE_FORMAT_INFO,
1513 &format_info, sizeof(format_info)))) {
1517 }
1518 ctx->plane_count = format_info.PlaneCount;
1519
1521 if (err < 0)
1523
1525 if (err < 0)
1527
1528 if (
ctx->codec->get_encoder_caps) {
1529 err =
ctx->codec->get_encoder_caps(avctx);
1530 if (err < 0)
1532 }
1533
1535 if (err < 0)
1537
1540 "but this codec does not support controlling slices.\n");
1541 }
1542
1544 if (err < 0)
1546
1548 if (err < 0)
1550
1551 if (
ctx->codec->configure) {
1552 err =
ctx->codec->configure(avctx);
1553 if (err < 0)
1555 }
1556
1557 if (
ctx->codec->init_sequence_params) {
1558 err =
ctx->codec->init_sequence_params(avctx);
1559 if (err < 0) {
1561 "failed: %d.\n", err);
1563 }
1564 }
1565
1566 if (
ctx->codec->set_level) {
1567 err =
ctx->codec->set_level(avctx);
1568 if (err < 0)
1570 }
1571
1573 if (err < 0)
1575
1578
1580 if (err < 0)
1582
1584 if (err < 0)
1586
1592
1593 return 0;
1594
1596 return err;
1597 }
1598
1600 {
1601 int num_allocator = 0;
1606
1607 if (!base_ctx->
frame)
1608 return 0;
1609
1610 for (pic = base_ctx->
pic_start; pic; pic = next) {
1613 }
1614
1616
1618
1621
1622 if (
ctx->allocator_queue) {
1624 num_allocator++;
1626 }
1627
1628 av_log(avctx,
AV_LOG_VERBOSE,
"Total number of command allocators reused: %d\n", num_allocator);
1629 }
1630
1632
1634 if (
ctx->sync_ctx.event)
1635 CloseHandle(
ctx->sync_ctx.event);
1636
1641
1643
1644 return 0;
1645 }