1 /*
2 * This file is part of FFmpeg.
3 *
4 * FFmpeg is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * FFmpeg is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with FFmpeg; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18
19 #include "config.h"
20 #include "config_components.h"
21
27 #if CONFIG_D3D11VA
29 #endif
30 #if CONFIG_DXVA2
31 #define COBJMACROS
33 #endif
37
42
43 #define AMF_AV_FRAME_REF L"av_frame_ref"
44 #define PTS_PROP L"PtsProp"
45
47 {
52
54 if (sd_display) {
57 const unsigned int luma_den = 10000;
58 hdrmeta->maxMasteringLuminance =
60 hdrmeta->minMasteringLuminance =
62 }
64 const unsigned int chroma_den = 50000;
65 hdrmeta->redPrimary[0] =
67 hdrmeta->redPrimary[1] =
69 hdrmeta->greenPrimary[0] =
71 hdrmeta->greenPrimary[1] =
73 hdrmeta->bluePrimary[0] =
75 hdrmeta->bluePrimary[1] =
77 hdrmeta->whitePoint[0] =
79 hdrmeta->whitePoint[1] =
81 }
82
84 if (sd_light) {
87 hdrmeta->maxContentLightLevel = (amf_uint16)light_meta->
MaxCLL;
88 hdrmeta->maxFrameAverageLightLevel = (amf_uint16)light_meta->
MaxFALL;
89 }
90 }
91 return 0;
92 }
93 return 1;
94 }
95
96 #if CONFIG_D3D11VA
97 #include <d3d11.h>
98 #endif
99
100 #ifdef _WIN32
102 #else
103 #include <dlfcn.h>
104 #endif
105
106 #define FFMPEG_AMF_WRITER_ID L"ffmpeg_amf"
107
108
112 #if CONFIG_D3D11VA
114 #endif
115 #if CONFIG_DXVA2
117 #endif
128 };
129
131
133 {
136 AMF_RESULT res;
140 int alloc_size;
142
143
146 if(!
ctx->pts_property_name)
148
150 ctx->av_frame_property_name =
av_memdup(
name, alloc_size *
sizeof(
wchar_t));
151 if(!
ctx->av_frame_property_name)
153
155
159 break;
162 break;
165 break;
166 default:
167 break;
168 }
170
173 else
175
177 AMF_RETURN_IF_FALSE(
ctx, amf_device_ctx->version >= AMF_MAKE_FULL_VERSION(1, 4, 32, 0),
AVERROR_UNKNOWN,
"10-bit encoder is not supported by AMD GPU drivers versions lower than 23.30.\n");
178 }
179
183
184 res = amf_device_ctx->factory->pVtbl->CreateComponent(amf_device_ctx->factory, amf_device_ctx->context,
codec_id, &
ctx->encoder);
186
187 ctx->submitted_frame = 0;
188 ctx->encoded_frame = 0;
190
191 return 0;
192 }
193
195 {
197
199 ctx->encoder->pVtbl->Terminate(
ctx->encoder);
200 ctx->encoder->pVtbl->Release(
ctx->encoder);
202 }
203
206
207 if (
ctx->output_list) {
208 // release remaining AMF output buffers
214 }
216 }
219
220 return 0;
221 }
222
224 AMFSurface* surface)
225 {
226 AMFPlane *plane;
227 uint8_t *dst_data[4] = {0};
228 int dst_linesize[4] = {0};
231
232 planes = (int)surface->pVtbl->GetPlanesCount(surface);
234
236 plane = surface->pVtbl->GetPlaneAt(surface,
i);
237 dst_data[
i] = plane->pVtbl->GetNative(plane);
238 dst_linesize[
i] = plane->pVtbl->GetHPitch(plane);
239 }
243
244 return 0;
245 }
246
248 {
251 AMFVariantStruct var = {0};
254
257 }
259
262 buffer->pVtbl->GetProperty(
buffer, AMF_VIDEO_ENCODER_OUTPUT_DATA_TYPE, &var);
263 if(var.int64Value == AMF_VIDEO_ENCODER_OUTPUT_DATA_TYPE_IDR) {
265 }
266 break;
268 buffer->pVtbl->GetProperty(
buffer, AMF_VIDEO_ENCODER_HEVC_OUTPUT_DATA_TYPE, &var);
269 if (var.int64Value == AMF_VIDEO_ENCODER_HEVC_OUTPUT_DATA_TYPE_IDR) {
271 }
272 break;
274 buffer->pVtbl->GetProperty(
buffer, AMF_VIDEO_ENCODER_AV1_OUTPUT_FRAME_TYPE, &var);
275 if (var.int64Value == AMF_VIDEO_ENCODER_AV1_OUTPUT_FRAME_TYPE_KEY) {
277 }
278 default:
279 break;
280 }
281
283
284 pkt->
pts = var.int64Value;
// original pts
285
288
289 // calc dts shift if max_b_frames > 0
290 if ((
ctx->max_b_frames > 0 || ((
ctx->pa_adaptive_mini_gop == 1) ?
true :
false)) &&
ctx->dts_delay == 0) {
293
295 "timestamp_list is empty while max_b_frames = %d\n", avctx->
max_b_frames);
299 }
300 ctx->dts_delay = timestamp_last - timestamp;
301 }
303 return 0;
304 }
305
306 // amfenc API implementation
308 {
312
313 // hardcoded to current HW queue size - will auto-realloc if too small
316 if (!
ctx->timestamp_list) {
318 }
320 if (!
ctx->output_list)
322
324
325 ctx->hwsurfaces_in_queue = 0;
326
330 {
332 }
333 else {
336 }
342 }
343 else {
346 }
347 }
348 }
349 else {
352 }
353
355 return 0;
356 }
357
360 }
361
363 {
364 AMF_RESULT res;
365 AMFVariantStruct var;
366 res = AMFVariantInit(&var);
367 if (res == AMF_OK) {
368 AMFGuid guid_AMFInterface = IID_AMFInterface();
369 AMFInterface *amf_interface;
370 res =
val->pVtbl->QueryInterface(
val, &guid_AMFInterface, (
void**)&amf_interface);
371
372 if (res == AMF_OK) {
373 res = AMFVariantAssignInterface(&var, amf_interface);
374 amf_interface->pVtbl->Release(amf_interface);
375 }
376 if (res == AMF_OK) {
377 res =
object->pVtbl->SetProperty(
object,
name, var);
378 }
379 AMFVariantClear(&var);
380 }
381 return res;
382 }
383
385 {
389 AMF_RESULT res;
390
391 switch(amf_device_ctx->memory_type) {
392 case AMF_MEMORY_DX11:
393 res = amf_device_ctx->context->pVtbl->LockDX11(amf_device_ctx->context);
395 break;
396 case AMF_MEMORY_DX12:
397 {
398 AMFContext2 *context2 =
NULL;
399 AMFGuid guid = IID_AMFContext2();
400 res = amf_device_ctx->context->pVtbl->QueryInterface(amf_device_ctx->context, &guid, (void**)&context2);
402 res = context2->pVtbl->LockDX12(context2);
404 context2->pVtbl->Release(context2);
405 }
406 break;
407 case AMF_MEMORY_DX9:
408 res = amf_device_ctx->context->pVtbl->LockDX9(amf_device_ctx->context);
410
411 case AMF_MEMORY_VULKAN:
412 {
413 AMFContext2 *context2 =
NULL;
414 AMFGuid guid = IID_AMFContext2();
415 res = amf_device_ctx->context->pVtbl->QueryInterface(amf_device_ctx->context, &guid, (void**)&context2);
417 res = context2->pVtbl->LockVulkan(context2);
419 context2->pVtbl->Release(context2);
420 }
421 break;
422 }
423 return AMF_OK;
424 }
426 {
430 AMF_RESULT res;
431
432 switch(amf_device_ctx->memory_type) {
433 case AMF_MEMORY_DX11:
434 res = amf_device_ctx->context->pVtbl->UnlockDX11(amf_device_ctx->context);
436 break;
437 case AMF_MEMORY_DX12:
438 {
439 AMFContext2 *context2 =
NULL;
440 AMFGuid guid = IID_AMFContext2();
441 res = amf_device_ctx->context->pVtbl->QueryInterface(amf_device_ctx->context, &guid, (void**)&context2);
443 res = context2->pVtbl->UnlockDX12(context2);
445 context2->pVtbl->Release(context2);
446 }
447 break;
448 case AMF_MEMORY_DX9:
449 res = amf_device_ctx->context->pVtbl->UnlockDX9(amf_device_ctx->context);
451
452 case AMF_MEMORY_VULKAN:
453 {
454 AMFContext2 *context2 =
NULL;
455 AMFGuid guid = IID_AMFContext2();
456 res = amf_device_ctx->context->pVtbl->QueryInterface(amf_device_ctx->context, &guid, (void**)&context2);
458 res = context2->pVtbl->UnlockVulkan(context2);
460 context2->pVtbl->Release(context2);
461 }
462 break;
463 }
464 return AMF_OK;
465 }
466
468 {
469 AMF_RESULT res = AMF_FAIL;
474 AMF_ASSIGN_PROPERTY_INT64(res, surface,
ctx->av_frame_property_name,
data);
475 }
476 return res;
477 }
478
480 {
481 AMFVariantStruct var = {0};
482 AMF_RESULT res =
buffer->pVtbl->GetProperty(
buffer,
ctx->av_frame_property_name, &var);
483 if(res == AMF_OK && var.int64Value){
487 }
488 return res;
489 }
490
492 {
496 AMFSurface *surface;
497 AMF_RESULT res;
499 int hw_surface = 0;
501
502 // prepare surface from frame
503 switch (
frame->format) {
504 #if CONFIG_D3D11VA
506 {
507 static const GUID AMFTextureArrayIndexGUID = { 0x28115527, 0xe7c3, 0x4b66, { 0x99, 0xd3, 0x4f, 0x2a, 0xe6, 0xb4, 0x7f, 0xaf } };
508 ID3D11Texture2D *texture = (ID3D11Texture2D*)
frame->data[0];
// actual texture
509 int index = (intptr_t)
frame->data[1];
// index is a slice in texture array is - set to tell AMF which slice to use
512 texture->lpVtbl->SetPrivateData(texture, &AMFTextureArrayIndexGUID,
sizeof(
index), &
index);
513 res = amf_device_ctx->context->pVtbl->CreateSurfaceFromDX11Native(amf_device_ctx->context, texture, &surface,
NULL);
// wrap to AMF surface
515 hw_surface = 1;
516 }
517 break;
518 #endif
519 #if CONFIG_DXVA2
521 {
522 IDirect3DSurface9 *texture = (IDirect3DSurface9 *)
frame->data[3];
// actual texture
523 res = amf_device_ctx->context->pVtbl->CreateSurfaceFromDX9Native(amf_device_ctx->context, texture, &surface,
NULL);
// wrap to AMF surface
525 hw_surface = 1;
526 }
527 break;
528 #endif
530 {
531 surface = (AMFSurface*)
frame->data[0];
532 surface->pVtbl->Acquire(surface);
533 hw_surface = 1;
534 }
535 break;
536 default:
537 {
538 res = amf_device_ctx->context->pVtbl->AllocSurface(amf_device_ctx->context, AMF_MEMORY_HOST,
ctx->format, avctx->
width, avctx->
height, &surface);
541 }
542 break;
543 }
544 if (hw_surface) {
546 ctx->hwsurfaces_in_queue++;
547 // input HW surfaces can be vertically aligned by 16; tell AMF the real size
548 surface->pVtbl->SetCrop(surface, 0, 0,
frame->width,
frame->height);
549 }
550 // HDR10 metadata
552 AMFBuffer * hdrmeta_buffer =
NULL;
553 res = amf_device_ctx->context->pVtbl->AllocBuffer(amf_device_ctx->context, AMF_MEMORY_HOST, sizeof(AMFHDRMetadata), &hdrmeta_buffer);
554 if (res == AMF_OK) {
555 AMFHDRMetadata * hdrmeta = (AMFHDRMetadata*)hdrmeta_buffer->pVtbl->GetNative(hdrmeta_buffer);
559 AMF_ASSIGN_PROPERTY_INTERFACE(res,
ctx->encoder, AMF_VIDEO_ENCODER_INPUT_HDR_METADATA, hdrmeta_buffer);
break;
561 AMF_ASSIGN_PROPERTY_INTERFACE(res,
ctx->encoder, AMF_VIDEO_ENCODER_HEVC_INPUT_HDR_METADATA, hdrmeta_buffer);
break;
563 AMF_ASSIGN_PROPERTY_INTERFACE(res,
ctx->encoder, AMF_VIDEO_ENCODER_AV1_INPUT_HDR_METADATA, hdrmeta_buffer);
break;
564 }
567 }
568 hdrmeta_buffer->pVtbl->Release(hdrmeta_buffer);
569 }
570 }
571 surface->pVtbl->SetPts(surface,
frame->pts);
572
573 AMF_ASSIGN_PROPERTY_INT64(res, surface,
ctx->pts_property_name,
frame->pts);
574
577 AMF_ASSIGN_PROPERTY_INT64(res, surface, AMF_VIDEO_ENCODER_INSERT_AUD, !!
ctx->aud);
578 switch (
frame->pict_type) {
580 if (
ctx->forced_idr) {
581 AMF_ASSIGN_PROPERTY_INT64(res, surface, AMF_VIDEO_ENCODER_INSERT_SPS, 1);
582 AMF_ASSIGN_PROPERTY_INT64(res, surface, AMF_VIDEO_ENCODER_INSERT_PPS, 1);
583 AMF_ASSIGN_PROPERTY_INT64(res, surface, AMF_VIDEO_ENCODER_FORCE_PICTURE_TYPE, AMF_VIDEO_ENCODER_PICTURE_TYPE_IDR);
584 } else {
585 AMF_ASSIGN_PROPERTY_INT64(res, surface, AMF_VIDEO_ENCODER_FORCE_PICTURE_TYPE, AMF_VIDEO_ENCODER_PICTURE_TYPE_I);
586 }
587 break;
589 AMF_ASSIGN_PROPERTY_INT64(res, surface, AMF_VIDEO_ENCODER_FORCE_PICTURE_TYPE, AMF_VIDEO_ENCODER_PICTURE_TYPE_P);
590 break;
592 AMF_ASSIGN_PROPERTY_INT64(res, surface, AMF_VIDEO_ENCODER_FORCE_PICTURE_TYPE, AMF_VIDEO_ENCODER_PICTURE_TYPE_B);
593 break;
594 }
595 break;
597 AMF_ASSIGN_PROPERTY_INT64(res, surface, AMF_VIDEO_ENCODER_HEVC_INSERT_AUD, !!
ctx->aud);
598 switch (
frame->pict_type) {
600 if (
ctx->forced_idr) {
601 AMF_ASSIGN_PROPERTY_INT64(res, surface, AMF_VIDEO_ENCODER_HEVC_INSERT_HEADER, 1);
602 AMF_ASSIGN_PROPERTY_INT64(res, surface, AMF_VIDEO_ENCODER_HEVC_FORCE_PICTURE_TYPE, AMF_VIDEO_ENCODER_HEVC_PICTURE_TYPE_IDR);
603 } else {
604 AMF_ASSIGN_PROPERTY_INT64(res, surface, AMF_VIDEO_ENCODER_HEVC_FORCE_PICTURE_TYPE, AMF_VIDEO_ENCODER_HEVC_PICTURE_TYPE_I);
605 }
606 break;
608 AMF_ASSIGN_PROPERTY_INT64(res, surface, AMF_VIDEO_ENCODER_HEVC_FORCE_PICTURE_TYPE, AMF_VIDEO_ENCODER_HEVC_PICTURE_TYPE_P);
609 break;
610 }
611 break;
614 if (
ctx->forced_idr) {
615 AMF_ASSIGN_PROPERTY_INT64(res, surface, AMF_VIDEO_ENCODER_AV1_FORCE_INSERT_SEQUENCE_HEADER, 1);
616 AMF_ASSIGN_PROPERTY_INT64(res, surface, AMF_VIDEO_ENCODER_AV1_FORCE_FRAME_TYPE, AMF_VIDEO_ENCODER_AV1_FORCE_FRAME_TYPE_KEY);
617 } else {
618 AMF_ASSIGN_PROPERTY_INT64(res, surface, AMF_VIDEO_ENCODER_AV1_FORCE_FRAME_TYPE, AMF_VIDEO_ENCODER_AV1_FORCE_FRAME_TYPE_INTRA_ONLY);
619 }
620 }
621 break;
622 default:
623 break;
624 }
625 // submit surface
626 res =
ctx->encoder->pVtbl->SubmitInput(
ctx->encoder, (AMFData*)surface);
627 if (res == AMF_INPUT_FULL) { // handle full queue
628 //store surface for later submission
629 *surface_resubmit = surface;
630 } else {
631 surface->pVtbl->Release(surface);
633 ctx->submitted_frame++;
637 if(
ctx->submitted_frame <=
ctx->encoded_frame + output_delay)
638 return AVERROR(EAGAIN);
// too soon to poll or wait
639 }
640 return 0;
641 }
642
644 {
649
651
655 }
657 {
660 AMF_RESULT
ret =
ctx->encoder->pVtbl->QueryOutput(
ctx->encoder, &
data);
663 AMFGuid guid = IID_AMFBuffer();
664 data->pVtbl->QueryInterface(
data, &guid, (
void**)
buffer);
// query for buffer interface
667 ctx->hwsurfaces_in_queue--;
668 ctx->encoded_frame++;
669 }
671 }
672
674 {
676 AMFSurface *surface =
NULL;
677 AMF_RESULT res;
679 AMF_RESULT res_query;
682 int block_and_wait;
685
689 }
690 // check if some outputs are available
692 if (
buffer !=
NULL) {
// return already retrieved output
696 }
697
703 if(
ctx->submitted_frame <=
ctx->encoded_frame + output_delay)
// too soon to poll
705 }
706 }
707 }
709 if (!
frame->buf[0]) {
// submit drain
710 if (!
ctx->eof) {
// submit drain one time only
711 if(!
ctx->delayed_drain) {
712 res =
ctx->encoder->pVtbl->Drain(
ctx->encoder);
713 if (res == AMF_INPUT_FULL) {
714 ctx->delayed_drain = 1;
// input queue is full: resubmit Drain() in receive loop
715 } else {
716 if (res == AMF_OK) {
717 ctx->eof = 1;
// drain started
718 }
720 }
721 }
722 }
723 } else { // submit frame
728 }
730 }
731 }
733
734 do {
735 block_and_wait = 0;
736 // poll data
741
743
744 if (
ctx->delayed_drain) {
// try to resubmit drain
745 res =
ctx->encoder->pVtbl->Drain(
ctx->encoder);
746 if (res != AMF_INPUT_FULL) {
747 ctx->delayed_drain = 0;
748 ctx->eof = 1;
// drain started
750 } else {
751 av_log(avctx,
AV_LOG_WARNING,
"Data acquired but delayed drain submission got AMF_INPUT_FULL- should not happen\n");
752 }
753 }
754 }
else if (
ctx->delayed_drain || (
ctx->eof && res_query != AMF_EOF) || (
ctx->hwsurfaces_in_queue >=
ctx->hwsurfaces_in_queue_max) || surface) {
755 block_and_wait = 1;
756 // Only sleep if the driver doesn't support waiting in QueryOutput()
757 // or if we already have output data so we will skip calling it.
758 if (!
ctx->query_timeout_supported || avpkt->
data || avpkt->
buf) {
760 }
761 }
762 } while (block_and_wait);
763
764 if (res_query == AMF_EOF) {
768 } else {
769 if(surface) {
770 // resubmit surface
771 do {
772 res =
ctx->encoder->pVtbl->SubmitInput(
ctx->encoder, (AMFData*)surface);
773 if (res != AMF_INPUT_FULL)
774 break;
775
776 if (!
ctx->query_timeout_supported)
778
779 // Need to free up space in the encoder queue.
780 // The number of retrieved outputs is limited currently to 21
786 }
787 } while(res == AMF_INPUT_FULL);
788
789 surface->pVtbl->Release(surface);
790 if (res == AMF_INPUT_FULL) {
791 av_log(avctx,
AV_LOG_WARNING,
"Data acquired but delayed SubmitInput returned AMF_INPUT_FULL- should not happen\n");
792 } else {
794
796
797 ctx->submitted_frame++;
798
801 }
802 }
804 }
806 }
807
809 {
810 amf_int64 color_profile = AMF_VIDEO_CONVERTER_COLOR_PROFILE_UNKNOWN;
812 /// Color Space for Full (JPEG) Range
815 color_profile = AMF_VIDEO_CONVERTER_COLOR_PROFILE_FULL_601;
816 break;
818 color_profile = AMF_VIDEO_CONVERTER_COLOR_PROFILE_FULL_709;
819 break;
822 color_profile = AMF_VIDEO_CONVERTER_COLOR_PROFILE_FULL_2020;
823 break;
824 }
825 } else {
826 /// Color Space for Limited (MPEG) range
829 color_profile = AMF_VIDEO_CONVERTER_COLOR_PROFILE_601;
830 break;
832 color_profile = AMF_VIDEO_CONVERTER_COLOR_PROFILE_709;
833 break;
836 color_profile = AMF_VIDEO_CONVERTER_COLOR_PROFILE_2020;
837 break;
838 }
839 }
840 return color_profile;
841 }
842
844 #if CONFIG_D3D11VA
847 #endif
848 #if CONFIG_DXVA2
851 #endif
855 };