blob: 63b83a625b47107dd1ae33149b61569698c57bce [file] [log] [blame]
Mikhail Mironov9ea66072017-11-27 02:36:061/*
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
James Almera198c132017-11-29 17:24:0819#include "config.h"
Martin Storsjöa78f1362022-02-23 12:56:4920#include "config_components.h"
James Almera198c132017-11-29 17:24:0821
Mikhail Mironov9ea66072017-11-27 02:36:0622#include "libavutil/avassert.h"
23#include "libavutil/imgutils.h"
24#include "libavutil/hwcontext.h"
Dmitrii Ovchinnikov88a8ba52024-10-15 17:52:1225#include "libavutil/hwcontext_amf.h"
26#include "libavutil/hwcontext_amf_internal.h"
Mikhail Mironov9ea66072017-11-27 02:36:0627#if CONFIG_D3D11VA
28#include "libavutil/hwcontext_d3d11va.h"
29#endif
Alexander Kravchenko2c6ca2b2018-04-14 14:46:1030#if CONFIG_DXVA2
31#define COBJMACROS
32#include "libavutil/hwcontext_dxva2.h"
33#endif
Mikhail Mironov9ea66072017-11-27 02:36:0634#include "libavutil/mem.h"
35#include "libavutil/pixdesc.h"
36#include "libavutil/time.h"
37
38#include "amfenc.h"
James Almer827d6fe2020-06-09 21:31:3239#include "encode.h"
Mikhail Mironov9ea66072017-11-27 02:36:0640#include "internal.h"
nyanmisaka62876202024-07-31 16:01:4141#include "libavutil/mastering_display_metadata.h"
42
Dmitrii Ovchinnikov88a8ba52024-10-15 17:52:1243#define AMF_AV_FRAME_REF L"av_frame_ref"
44
nyanmisaka62876202024-07-31 16:01:4145static int amf_save_hdr_metadata(AVCodecContext *avctx, const AVFrame *frame, AMFHDRMetadata *hdrmeta)
46{
47 AVFrameSideData *sd_display;
48 AVFrameSideData *sd_light;
49 AVMasteringDisplayMetadata *display_meta;
50 AVContentLightMetadata *light_meta;
51
52 sd_display = av_frame_get_side_data(frame, AV_FRAME_DATA_MASTERING_DISPLAY_METADATA);
53 if (sd_display) {
54 display_meta = (AVMasteringDisplayMetadata *)sd_display->data;
55 if (display_meta->has_luminance) {
56 const unsigned int luma_den = 10000;
57 hdrmeta->maxMasteringLuminance =
58 (amf_uint32)(luma_den * av_q2d(display_meta->max_luminance));
59 hdrmeta->minMasteringLuminance =
60 FFMIN((amf_uint32)(luma_den * av_q2d(display_meta->min_luminance)), hdrmeta->maxMasteringLuminance);
61 }
62 if (display_meta->has_primaries) {
63 const unsigned int chroma_den = 50000;
64 hdrmeta->redPrimary[0] =
65 FFMIN((amf_uint16)(chroma_den * av_q2d(display_meta->display_primaries[0][0])), chroma_den);
66 hdrmeta->redPrimary[1] =
67 FFMIN((amf_uint16)(chroma_den * av_q2d(display_meta->display_primaries[0][1])), chroma_den);
68 hdrmeta->greenPrimary[0] =
69 FFMIN((amf_uint16)(chroma_den * av_q2d(display_meta->display_primaries[1][0])), chroma_den);
70 hdrmeta->greenPrimary[1] =
71 FFMIN((amf_uint16)(chroma_den * av_q2d(display_meta->display_primaries[1][1])), chroma_den);
72 hdrmeta->bluePrimary[0] =
73 FFMIN((amf_uint16)(chroma_den * av_q2d(display_meta->display_primaries[2][0])), chroma_den);
74 hdrmeta->bluePrimary[1] =
75 FFMIN((amf_uint16)(chroma_den * av_q2d(display_meta->display_primaries[2][1])), chroma_den);
76 hdrmeta->whitePoint[0] =
77 FFMIN((amf_uint16)(chroma_den * av_q2d(display_meta->white_point[0])), chroma_den);
78 hdrmeta->whitePoint[1] =
79 FFMIN((amf_uint16)(chroma_den * av_q2d(display_meta->white_point[1])), chroma_den);
80 }
81
82 sd_light = av_frame_get_side_data(frame, AV_FRAME_DATA_CONTENT_LIGHT_LEVEL);
83 if (sd_light) {
84 light_meta = (AVContentLightMetadata *)sd_light->data;
85 if (light_meta) {
86 hdrmeta->maxContentLightLevel = (amf_uint16)light_meta->MaxCLL;
87 hdrmeta->maxFrameAverageLightLevel = (amf_uint16)light_meta->MaxFALL;
88 }
89 }
90 return 0;
91 }
92 return 1;
93}
Mikhail Mironov9ea66072017-11-27 02:36:0694
95#if CONFIG_D3D11VA
96#include <d3d11.h>
97#endif
98
99#ifdef _WIN32
100#include "compat/w32dlfcn.h"
101#else
102#include <dlfcn.h>
103#endif
104
105#define FFMPEG_AMF_WRITER_ID L"ffmpeg_amf"
106
107#define PTS_PROP L"PtsProp"
108
109const enum AVPixelFormat ff_amf_pix_fmts[] = {
110 AV_PIX_FMT_NV12,
111 AV_PIX_FMT_YUV420P,
112#if CONFIG_D3D11VA
113 AV_PIX_FMT_D3D11,
114#endif
Alexander Kravchenko2c6ca2b2018-04-14 14:46:10115#if CONFIG_DXVA2
116 AV_PIX_FMT_DXVA2_VLD,
117#endif
Michael Fabian 'Xaymar' Dirksfb4dd4b2024-07-31 16:00:57118 AV_PIX_FMT_P010,
Dmitrii Ovchinnikov88a8ba52024-10-15 17:52:12119 AV_PIX_FMT_AMF_SURFACE,
Dmitrii Ovchinnikov7225e302025-02-14 13:52:33120 AV_PIX_FMT_BGR0,
121 AV_PIX_FMT_RGB0,
122 AV_PIX_FMT_BGRA,
123 AV_PIX_FMT_ARGB,
124 AV_PIX_FMT_RGBA,
125 AV_PIX_FMT_X2BGR10,
126 AV_PIX_FMT_RGBAF16,
Mikhail Mironov9ea66072017-11-27 02:36:06127 AV_PIX_FMT_NONE
128};
129
Mikhail Mironov9ea66072017-11-27 02:36:06130static int amf_init_encoder(AVCodecContext *avctx)
131{
Dmitrii Ovchinnikov88a8ba52024-10-15 17:52:12132 AMFEncoderContext *ctx = avctx->priv_data;
133 const wchar_t *codec_id = NULL;
134 AMF_RESULT res;
135 enum AVPixelFormat pix_fmt;
136 AVHWDeviceContext *hw_device_ctx = (AVHWDeviceContext*)ctx->device_ctx_ref->data;
137 AVAMFDeviceContext *amf_device_ctx = (AVAMFDeviceContext *)hw_device_ctx->hwctx;
Mikhail Mironov9ea66072017-11-27 02:36:06138
139 switch (avctx->codec->id) {
140 case AV_CODEC_ID_H264:
141 codec_id = AMFVideoEncoderVCE_AVC;
142 break;
143 case AV_CODEC_ID_HEVC:
144 codec_id = AMFVideoEncoder_HEVC;
145 break;
Dmitrii Ovchinnikov5f0a7a92022-12-20 15:20:38146 case AV_CODEC_ID_AV1 :
147 codec_id = AMFVideoEncoder_AV1;
148 break;
Mikhail Mironov9ea66072017-11-27 02:36:06149 default:
150 break;
151 }
152 AMF_RETURN_IF_FALSE(ctx, codec_id != NULL, AVERROR(EINVAL), "Codec %d is not supported\n", avctx->codec->id);
153
Dmitrii Ovchinnikov88a8ba52024-10-15 17:52:12154 if (avctx->hw_frames_ctx)
155 pix_fmt = ((AVHWFramesContext*)avctx->hw_frames_ctx->data)->sw_format;
Alexander Kravchenkoab7eed12018-04-14 14:46:05156 else
157 pix_fmt = avctx->pix_fmt;
158
Araz Iusuboveda3fc62024-07-31 22:00:33159 if (pix_fmt == AV_PIX_FMT_P010) {
Dmitrii Ovchinnikov88a8ba52024-10-15 17:52:12160 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");
Araz Iusuboveda3fc62024-07-31 22:00:33161 }
162
Dmitrii Ovchinnikov88a8ba52024-10-15 17:52:12163 ctx->format = av_av_to_amf_format(pix_fmt);
Alexander Kravchenkoab7eed12018-04-14 14:46:05164 AMF_RETURN_IF_FALSE(ctx, ctx->format != AMF_SURFACE_UNKNOWN, AVERROR(EINVAL),
165 "Format %s is not supported\n", av_get_pix_fmt_name(pix_fmt));
Mikhail Mironov9ea66072017-11-27 02:36:06166
Dmitrii Ovchinnikov88a8ba52024-10-15 17:52:12167 res = amf_device_ctx->factory->pVtbl->CreateComponent(amf_device_ctx->factory, amf_device_ctx->context, codec_id, &ctx->encoder);
Mikhail Mironov9ea66072017-11-27 02:36:06168 AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_ENCODER_NOT_FOUND, "CreateComponent(%ls) failed with error %d\n", codec_id, res);
169
Cameron Gutman8503c642024-10-11 22:28:00170 ctx->submitted_frame = 0;
Dmitrii Ovchinnikov88a8ba52024-10-15 17:52:12171 ctx->encoded_frame = 0;
172 ctx->eof = 0;
Cameron Gutman8503c642024-10-11 22:28:00173
Mikhail Mironov9ea66072017-11-27 02:36:06174 return 0;
175}
176
177int av_cold ff_amf_encode_close(AVCodecContext *avctx)
178{
Dmitrii Ovchinnikov88a8ba52024-10-15 17:52:12179 AMFEncoderContext *ctx = avctx->priv_data;
Mikhail Mironov9ea66072017-11-27 02:36:06180
181 if (ctx->encoder) {
182 ctx->encoder->pVtbl->Terminate(ctx->encoder);
183 ctx->encoder->pVtbl->Release(ctx->encoder);
184 ctx->encoder = NULL;
185 }
186
Dmitrii Ovchinnikov88a8ba52024-10-15 17:52:12187 av_buffer_unref(&ctx->device_ctx_ref);
Anton Khirnov70611d72022-01-10 10:04:36188 av_fifo_freep2(&ctx->timestamp_list);
Mikhail Mironov9ea66072017-11-27 02:36:06189
190 return 0;
191}
192
193static int amf_copy_surface(AVCodecContext *avctx, const AVFrame *frame,
194 AMFSurface* surface)
195{
Mark Thompsonedecd722018-04-14 14:46:15196 AMFPlane *plane;
Dmitrii Ovchinnikov88a8ba52024-10-15 17:52:12197 uint8_t *dst_data[4] = {0};
198 int dst_linesize[4] = {0};
Mark Thompsonedecd722018-04-14 14:46:15199 int planes;
200 int i;
Mikhail Mironov9ea66072017-11-27 02:36:06201
Dmitrii Ovchinnikov88a8ba52024-10-15 17:52:12202 planes = (int)surface->pVtbl->GetPlanesCount(surface);
Mark Thompson73ed6fa2018-04-14 14:46:00203 av_assert0(planes < FF_ARRAY_ELEMS(dst_data));
Mikhail Mironov9ea66072017-11-27 02:36:06204
205 for (i = 0; i < planes; i++) {
206 plane = surface->pVtbl->GetPlaneAt(surface, i);
207 dst_data[i] = plane->pVtbl->GetNative(plane);
208 dst_linesize[i] = plane->pVtbl->GetHPitch(plane);
209 }
Andreas Rheinhardt423b6a72023-09-06 22:09:10210 av_image_copy2(dst_data, dst_linesize,
211 frame->data, frame->linesize, frame->format,
212 avctx->width, avctx->height);
Mikhail Mironov9ea66072017-11-27 02:36:06213
Mark Thompson73ed6fa2018-04-14 14:46:00214 return 0;
Mikhail Mironov9ea66072017-11-27 02:36:06215}
216
Mikhail Mironov9ea66072017-11-27 02:36:06217static int amf_copy_buffer(AVCodecContext *avctx, AVPacket *pkt, AMFBuffer *buffer)
218{
Dmitrii Ovchinnikov88a8ba52024-10-15 17:52:12219 AMFEncoderContext *ctx = avctx->priv_data;
Mark Thompsonedecd722018-04-14 14:46:15220 int ret;
221 AMFVariantStruct var = {0};
222 int64_t timestamp = AV_NOPTS_VALUE;
223 int64_t size = buffer->pVtbl->GetSize(buffer);
Mikhail Mironov9ea66072017-11-27 02:36:06224
James Almerb615e8a2021-03-12 23:49:44225 if ((ret = ff_get_encode_buffer(avctx, pkt, size, 0)) < 0) {
Mikhail Mironov9ea66072017-11-27 02:36:06226 return ret;
227 }
228 memcpy(pkt->data, buffer->pVtbl->GetNative(buffer), size);
229
230 switch (avctx->codec->id) {
231 case AV_CODEC_ID_H264:
232 buffer->pVtbl->GetProperty(buffer, AMF_VIDEO_ENCODER_OUTPUT_DATA_TYPE, &var);
233 if(var.int64Value == AMF_VIDEO_ENCODER_OUTPUT_DATA_TYPE_IDR) {
234 pkt->flags = AV_PKT_FLAG_KEY;
235 }
236 break;
237 case AV_CODEC_ID_HEVC:
238 buffer->pVtbl->GetProperty(buffer, AMF_VIDEO_ENCODER_HEVC_OUTPUT_DATA_TYPE, &var);
239 if (var.int64Value == AMF_VIDEO_ENCODER_HEVC_OUTPUT_DATA_TYPE_IDR) {
240 pkt->flags = AV_PKT_FLAG_KEY;
241 }
242 break;
Dmitrii Ovchinnikov5f0a7a92022-12-20 15:20:38243 case AV_CODEC_ID_AV1:
244 buffer->pVtbl->GetProperty(buffer, AMF_VIDEO_ENCODER_AV1_OUTPUT_FRAME_TYPE, &var);
245 if (var.int64Value == AMF_VIDEO_ENCODER_AV1_OUTPUT_FRAME_TYPE_KEY) {
246 pkt->flags = AV_PKT_FLAG_KEY;
247 }
Mikhail Mironov9ea66072017-11-27 02:36:06248 default:
249 break;
250 }
251
252 buffer->pVtbl->GetProperty(buffer, PTS_PROP, &var);
253
254 pkt->pts = var.int64Value; // original pts
255
Anton Khirnov70611d72022-01-10 10:04:36256 AMF_RETURN_IF_FALSE(ctx, av_fifo_read(ctx->timestamp_list, &timestamp, 1) >= 0,
257 AVERROR_UNKNOWN, "timestamp_list is empty\n");
Mikhail Mironov9ea66072017-11-27 02:36:06258
259 // calc dts shift if max_b_frames > 0
Dmitrii Ovchinnikovf593dc92023-05-17 12:59:40260 if ((ctx->max_b_frames > 0 || ((ctx->pa_adaptive_mini_gop == 1) ? true : false)) && ctx->dts_delay == 0) {
Mikhail Mironov9ea66072017-11-27 02:36:06261 int64_t timestamp_last = AV_NOPTS_VALUE;
Anton Khirnov70611d72022-01-10 10:04:36262 size_t can_read = av_fifo_can_read(ctx->timestamp_list);
Dmitrii Ovchinnikov88a8ba52024-10-15 17:52:12263
Anton Khirnov70611d72022-01-10 10:04:36264 AMF_RETURN_IF_FALSE(ctx, can_read > 0, AVERROR_UNKNOWN,
Mikhail Mironov9ea66072017-11-27 02:36:06265 "timestamp_list is empty while max_b_frames = %d\n", avctx->max_b_frames);
Anton Khirnov70611d72022-01-10 10:04:36266 av_fifo_peek(ctx->timestamp_list, &timestamp_last, 1, can_read - 1);
Mikhail Mironov9ea66072017-11-27 02:36:06267 if (timestamp < 0 || timestamp_last < AV_NOPTS_VALUE) {
268 return AVERROR(ERANGE);
269 }
270 ctx->dts_delay = timestamp_last - timestamp;
271 }
272 pkt->dts = timestamp - ctx->dts_delay;
273 return 0;
274}
275
Michael Wootton34c11332018-01-03 17:55:53276// amfenc API implementation
Mikhail Mironov9ea66072017-11-27 02:36:06277int ff_amf_encode_init(AVCodecContext *avctx)
278{
Mark Thompsonedecd722018-04-14 14:46:15279 int ret;
Dmitrii Ovchinnikov88a8ba52024-10-15 17:52:12280 AMFEncoderContext *ctx = avctx->priv_data;
281 AVHWDeviceContext *hwdev_ctx = NULL;
Mikhail Mironov9ea66072017-11-27 02:36:06282
Dmitrii Ovchinnikov88a8ba52024-10-15 17:52:12283 // hardcoded to current HW queue size - will auto-realloc if too small
284 ctx->timestamp_list = av_fifo_alloc2(avctx->max_b_frames + 16, sizeof(int64_t),
285 AV_FIFO_FLAG_AUTO_GROW);
286 if (!ctx->timestamp_list) {
287 return AVERROR(ENOMEM);
288 }
289 ctx->dts_delay = 0;
290
291 ctx->hwsurfaces_in_queue = 0;
292
293 if (avctx->hw_device_ctx) {
294 hwdev_ctx = (AVHWDeviceContext*)avctx->hw_device_ctx->data;
295 if (hwdev_ctx->type == AV_HWDEVICE_TYPE_AMF)
296 {
297 ctx->device_ctx_ref = av_buffer_ref(avctx->hw_device_ctx);
298 }
299 else {
300 ret = av_hwdevice_ctx_create_derived(&ctx->device_ctx_ref, AV_HWDEVICE_TYPE_AMF, avctx->hw_device_ctx, 0);
301 AMF_RETURN_IF_FALSE(avctx, ret == 0, ret, "Failed to create derived AMF device context: %s\n", av_err2str(ret));
302 }
303 } else if (avctx->hw_frames_ctx) {
304 AVHWFramesContext *frames_ctx = (AVHWFramesContext*)avctx->hw_frames_ctx->data;
305 if (frames_ctx->device_ref ) {
306 if (frames_ctx->format == AV_PIX_FMT_AMF_SURFACE) {
307 ctx->device_ctx_ref = av_buffer_ref(frames_ctx->device_ref);
308 }
309 else {
310 ret = av_hwdevice_ctx_create_derived(&ctx->device_ctx_ref, AV_HWDEVICE_TYPE_AMF, frames_ctx->device_ref, 0);
311 AMF_RETURN_IF_FALSE(avctx, ret == 0, ret, "Failed to create derived AMF device context: %s\n", av_err2str(ret));
Mikhail Mironov9ea66072017-11-27 02:36:06312 }
313 }
314 }
Dmitrii Ovchinnikov88a8ba52024-10-15 17:52:12315 else {
316 ret = av_hwdevice_ctx_create(&ctx->device_ctx_ref, AV_HWDEVICE_TYPE_AMF, NULL, NULL, 0);
317 AMF_RETURN_IF_FALSE(avctx, ret == 0, ret, "Failed to create hardware device context (AMF) : %s\n", av_err2str(ret));
318 }
319
320 if ((ret = amf_init_encoder(avctx)) == 0) {
321 return 0;
322 }
323
Mikhail Mironov9ea66072017-11-27 02:36:06324 ff_amf_encode_close(avctx);
325 return ret;
326}
327
Alexander Kravchenko05f1a3f2018-04-09 16:48:33328static AMF_RESULT amf_set_property_buffer(AMFSurface *object, const wchar_t *name, AMFBuffer *val)
329{
330 AMF_RESULT res;
331 AMFVariantStruct var;
332 res = AMFVariantInit(&var);
333 if (res == AMF_OK) {
334 AMFGuid guid_AMFInterface = IID_AMFInterface();
335 AMFInterface *amf_interface;
336 res = val->pVtbl->QueryInterface(val, &guid_AMFInterface, (void**)&amf_interface);
337
338 if (res == AMF_OK) {
339 res = AMFVariantAssignInterface(&var, amf_interface);
340 amf_interface->pVtbl->Release(amf_interface);
341 }
342 if (res == AMF_OK) {
343 res = object->pVtbl->SetProperty(object, name, var);
344 }
345 AMFVariantClear(&var);
346 }
347 return res;
348}
349
Dmitrii Ovchinnikov88a8ba52024-10-15 17:52:12350static AMF_RESULT amf_store_attached_frame_ref(const AVFrame *frame, AMFSurface *surface)
Alexander Kravchenko05f1a3f2018-04-09 16:48:33351{
Dmitrii Ovchinnikov88a8ba52024-10-15 17:52:12352 AMF_RESULT res = AMF_FAIL;
353 int64_t data;
354 AVFrame *frame_ref = av_frame_clone(frame);
355 if (frame_ref) {
356 memcpy(&data, &frame_ref, sizeof(frame_ref)); // store pointer in 8 bytes
357 AMF_ASSIGN_PROPERTY_INT64(res, surface, AMF_AV_FRAME_REF, data);
Alexander Kravchenko05f1a3f2018-04-09 16:48:33358 }
359 return res;
360}
361
Dmitrii Ovchinnikov88a8ba52024-10-15 17:52:12362static AMF_RESULT amf_release_attached_frame_ref(AMFBuffer *buffer)
Alexander Kravchenko05f1a3f2018-04-09 16:48:33363{
Dmitrii Ovchinnikov88a8ba52024-10-15 17:52:12364 AMFVariantStruct var = {0};
365 AMF_RESULT res = buffer->pVtbl->GetProperty(buffer, AMF_AV_FRAME_REF, &var);
366 if(res == AMF_OK && var.int64Value){
367 AVFrame *frame_ref;
368 memcpy(&frame_ref, &var.int64Value, sizeof(frame_ref));
369 av_frame_free(&frame_ref);
Alexander Kravchenko05f1a3f2018-04-09 16:48:33370 }
Dmitrii Ovchinnikov88a8ba52024-10-15 17:52:12371 return res;
Alexander Kravchenko05f1a3f2018-04-09 16:48:33372}
Mikhail Mironov9ea66072017-11-27 02:36:06373
James Almer827d6fe2020-06-09 21:31:32374int ff_amf_receive_packet(AVCodecContext *avctx, AVPacket *avpkt)
Mikhail Mironov9ea66072017-11-27 02:36:06375{
Dmitrii Ovchinnikov88a8ba52024-10-15 17:52:12376 AMFEncoderContext *ctx = avctx->priv_data;
377 AVHWDeviceContext *hw_device_ctx = (AVHWDeviceContext*)ctx->device_ctx_ref->data;
378 AVAMFDeviceContext *amf_device_ctx = (AVAMFDeviceContext *)hw_device_ctx->hwctx;
Mark Thompsonedecd722018-04-14 14:46:15379 AMFSurface *surface;
380 AMF_RESULT res;
381 int ret;
James Almer827d6fe2020-06-09 21:31:32382 AMF_RESULT res_query;
383 AMFData *data = NULL;
Dmitrii Ovchinnikov88a8ba52024-10-15 17:52:12384 AVFrame *frame = av_frame_alloc();
James Almer827d6fe2020-06-09 21:31:32385 int block_and_wait;
Dmitrii Ovchinnikov88a8ba52024-10-15 17:52:12386 int input_full = 0;
387 int hw_surface = 0;
388 int64_t pts = 0;
389 int max_b_frames = ctx->max_b_frames < 0 ? 0 : ctx->max_b_frames;
Mikhail Mironov9ea66072017-11-27 02:36:06390
Dmitrii Ovchinnikov88a8ba52024-10-15 17:52:12391 if (!ctx->encoder){
392 av_frame_free(&frame);
Mikhail Mironov9ea66072017-11-27 02:36:06393 return AVERROR(EINVAL);
James Almer827d6fe2020-06-09 21:31:32394 }
Dmitrii Ovchinnikov88a8ba52024-10-15 17:52:12395 ret = ff_encode_get_frame(avctx, frame);
396 if(ret < 0){
397 if(ret != AVERROR_EOF){
398 av_frame_free(&frame);
399 if(ret == AVERROR(EAGAIN)){
400 if(ctx->submitted_frame <= ctx->encoded_frame + max_b_frames + 1) // too soon to poll
401 return ret;
Mikhail Mironov9ea66072017-11-27 02:36:06402 }
Mikhail Mironov9ea66072017-11-27 02:36:06403 }
Mikhail Mironov9ea66072017-11-27 02:36:06404 }
Dmitrii Ovchinnikov88a8ba52024-10-15 17:52:12405 if(ret != AVERROR(EAGAIN)){
406 if (!frame->buf[0]) { // submit drain
407 if (!ctx->eof) { // submit drain one time only
408 if(!ctx->delayed_drain) {
409 res = ctx->encoder->pVtbl->Drain(ctx->encoder);
410 if (res == AMF_INPUT_FULL) {
411 ctx->delayed_drain = 1; // input queue is full: resubmit Drain() in receive loop
412 } else {
413 if (res == AMF_OK) {
414 ctx->eof = 1; // drain started
415 }
416 AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, "Drain() failed with error %d\n", res);
417 }
418 }
419 }
420 } else { // submit frame
Mikhail Mironov9ea66072017-11-27 02:36:06421
Dmitrii Ovchinnikov88a8ba52024-10-15 17:52:12422 // prepare surface from frame
423 switch (frame->format) {
424 #if CONFIG_D3D11VA
425 case AV_PIX_FMT_D3D11:
426 {
427 static const GUID AMFTextureArrayIndexGUID = { 0x28115527, 0xe7c3, 0x4b66, { 0x99, 0xd3, 0x4f, 0x2a, 0xe6, 0xb4, 0x7f, 0xaf } };
428 ID3D11Texture2D *texture = (ID3D11Texture2D*)frame->data[0]; // actual texture
429 int index = (intptr_t)frame->data[1]; // index is a slice in texture array is - set to tell AMF which slice to use
430
431 av_assert0(frame->hw_frames_ctx && avctx->hw_frames_ctx &&
432 frame->hw_frames_ctx->data == avctx->hw_frames_ctx->data);
433
434 texture->lpVtbl->SetPrivateData(texture, &AMFTextureArrayIndexGUID, sizeof(index), &index);
435
436 res = amf_device_ctx->context->pVtbl->CreateSurfaceFromDX11Native(amf_device_ctx->context, texture, &surface, NULL); // wrap to AMF surface
437 AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR(ENOMEM), "CreateSurfaceFromDX11Native() failed with error %d\n", res);
438
439 hw_surface = 1;
440 }
441 break;
442 #endif
443 #if CONFIG_DXVA2
444 case AV_PIX_FMT_DXVA2_VLD:
445 {
446 IDirect3DSurface9 *texture = (IDirect3DSurface9 *)frame->data[3]; // actual texture
447
448 res = amf_device_ctx->context->pVtbl->CreateSurfaceFromDX9Native(amf_device_ctx->context, texture, &surface, NULL); // wrap to AMF surface
449 AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR(ENOMEM), "CreateSurfaceFromDX9Native() failed with error %d\n", res);
450
451 hw_surface = 1;
452 }
453 break;
454 #endif
455 case AV_PIX_FMT_AMF_SURFACE:
456 {
457 surface = (AMFSurface*)frame->data[0];
458 surface->pVtbl->Acquire(surface);
459 hw_surface = 1;
460 }
461 break;
462 default:
463 {
464 res = amf_device_ctx->context->pVtbl->AllocSurface(amf_device_ctx->context, AMF_MEMORY_HOST, ctx->format, avctx->width, avctx->height, &surface);
465 AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR(ENOMEM), "AllocSurface() failed with error %d\n", res);
466 amf_copy_surface(avctx, frame, surface);
467 }
468 break;
469 }
470
471 if (hw_surface) {
472 amf_store_attached_frame_ref(frame, surface);
473 ctx->hwsurfaces_in_queue++;
474 // input HW surfaces can be vertically aligned by 16; tell AMF the real size
475 surface->pVtbl->SetCrop(surface, 0, 0, frame->width, frame->height);
476 }
477
478 // HDR10 metadata
479 if (frame->color_trc == AVCOL_TRC_SMPTE2084) {
480 AMFBuffer * hdrmeta_buffer = NULL;
481 res = amf_device_ctx->context->pVtbl->AllocBuffer(amf_device_ctx->context, AMF_MEMORY_HOST, sizeof(AMFHDRMetadata), &hdrmeta_buffer);
482 if (res == AMF_OK) {
483 AMFHDRMetadata * hdrmeta = (AMFHDRMetadata*)hdrmeta_buffer->pVtbl->GetNative(hdrmeta_buffer);
484 if (amf_save_hdr_metadata(avctx, frame, hdrmeta) == 0) {
485 switch (avctx->codec->id) {
486 case AV_CODEC_ID_H264:
487 AMF_ASSIGN_PROPERTY_INTERFACE(res, ctx->encoder, AMF_VIDEO_ENCODER_INPUT_HDR_METADATA, hdrmeta_buffer); break;
488 case AV_CODEC_ID_HEVC:
489 AMF_ASSIGN_PROPERTY_INTERFACE(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_INPUT_HDR_METADATA, hdrmeta_buffer); break;
490 case AV_CODEC_ID_AV1:
491 AMF_ASSIGN_PROPERTY_INTERFACE(res, ctx->encoder, AMF_VIDEO_ENCODER_AV1_INPUT_HDR_METADATA, hdrmeta_buffer); break;
492 }
493 res = amf_set_property_buffer(surface, L"av_frame_hdrmeta", hdrmeta_buffer);
494 AMF_RETURN_IF_FALSE(avctx, res == AMF_OK, AVERROR_UNKNOWN, "SetProperty failed for \"av_frame_hdrmeta\" with error %d\n", res);
495 }
496 hdrmeta_buffer->pVtbl->Release(hdrmeta_buffer);
497 }
498 }
499
500 surface->pVtbl->SetPts(surface, frame->pts);
501 AMF_ASSIGN_PROPERTY_INT64(res, surface, PTS_PROP, frame->pts);
502
503 switch (avctx->codec->id) {
504 case AV_CODEC_ID_H264:
505 AMF_ASSIGN_PROPERTY_INT64(res, surface, AMF_VIDEO_ENCODER_INSERT_AUD, !!ctx->aud);
506 switch (frame->pict_type) {
507 case AV_PICTURE_TYPE_I:
508 if (ctx->forced_idr) {
509 AMF_ASSIGN_PROPERTY_INT64(res, surface, AMF_VIDEO_ENCODER_INSERT_SPS, 1);
510 AMF_ASSIGN_PROPERTY_INT64(res, surface, AMF_VIDEO_ENCODER_INSERT_PPS, 1);
511 AMF_ASSIGN_PROPERTY_INT64(res, surface, AMF_VIDEO_ENCODER_FORCE_PICTURE_TYPE, AMF_VIDEO_ENCODER_PICTURE_TYPE_IDR);
512 } else {
513 AMF_ASSIGN_PROPERTY_INT64(res, surface, AMF_VIDEO_ENCODER_FORCE_PICTURE_TYPE, AMF_VIDEO_ENCODER_PICTURE_TYPE_I);
514 }
515 break;
516 case AV_PICTURE_TYPE_P:
517 AMF_ASSIGN_PROPERTY_INT64(res, surface, AMF_VIDEO_ENCODER_FORCE_PICTURE_TYPE, AMF_VIDEO_ENCODER_PICTURE_TYPE_P);
518 break;
519 case AV_PICTURE_TYPE_B:
520 AMF_ASSIGN_PROPERTY_INT64(res, surface, AMF_VIDEO_ENCODER_FORCE_PICTURE_TYPE, AMF_VIDEO_ENCODER_PICTURE_TYPE_B);
521 break;
522 }
523 break;
524 case AV_CODEC_ID_HEVC:
525 AMF_ASSIGN_PROPERTY_INT64(res, surface, AMF_VIDEO_ENCODER_HEVC_INSERT_AUD, !!ctx->aud);
526 switch (frame->pict_type) {
527 case AV_PICTURE_TYPE_I:
528 if (ctx->forced_idr) {
529 AMF_ASSIGN_PROPERTY_INT64(res, surface, AMF_VIDEO_ENCODER_HEVC_INSERT_HEADER, 1);
530 AMF_ASSIGN_PROPERTY_INT64(res, surface, AMF_VIDEO_ENCODER_HEVC_FORCE_PICTURE_TYPE, AMF_VIDEO_ENCODER_HEVC_PICTURE_TYPE_IDR);
531 } else {
532 AMF_ASSIGN_PROPERTY_INT64(res, surface, AMF_VIDEO_ENCODER_HEVC_FORCE_PICTURE_TYPE, AMF_VIDEO_ENCODER_HEVC_PICTURE_TYPE_I);
533 }
534 break;
535 case AV_PICTURE_TYPE_P:
536 AMF_ASSIGN_PROPERTY_INT64(res, surface, AMF_VIDEO_ENCODER_HEVC_FORCE_PICTURE_TYPE, AMF_VIDEO_ENCODER_HEVC_PICTURE_TYPE_P);
537 break;
538 }
539 break;
540 case AV_CODEC_ID_AV1:
541 if (frame->pict_type == AV_PICTURE_TYPE_I) {
542 if (ctx->forced_idr) {
543 AMF_ASSIGN_PROPERTY_INT64(res, surface, AMF_VIDEO_ENCODER_AV1_FORCE_INSERT_SEQUENCE_HEADER, 1);
544 AMF_ASSIGN_PROPERTY_INT64(res, surface, AMF_VIDEO_ENCODER_AV1_FORCE_FRAME_TYPE, AMF_VIDEO_ENCODER_AV1_FORCE_FRAME_TYPE_KEY);
545 } else {
546 AMF_ASSIGN_PROPERTY_INT64(res, surface, AMF_VIDEO_ENCODER_AV1_FORCE_FRAME_TYPE, AMF_VIDEO_ENCODER_AV1_FORCE_FRAME_TYPE_INTRA_ONLY);
547 }
548 }
549 break;
550 default:
551 break;
552 }
553 pts = frame->pts;
554 // submit surface
555 res = ctx->encoder->pVtbl->SubmitInput(ctx->encoder, (AMFData*)surface);
556 av_frame_free(&frame);
557
558 if (res == AMF_INPUT_FULL) { // handle full queue
559 //store surface for later submission
560 input_full = 1;
561 } else {
562 surface->pVtbl->Release(surface);
563 AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, "SubmitInput() failed with error %d\n", res);
564
565 ctx->submitted_frame++;
566 ret = av_fifo_write(ctx->timestamp_list, &pts, 1);
567
568 if (ret < 0)
569 return ret;
570 if(ctx->submitted_frame <= ctx->encoded_frame + max_b_frames + 1)
571 return AVERROR(EAGAIN); // if frame just submiited - don't poll or wait
572 }
573 }
574 }
575 av_frame_free(&frame);
Mikhail Mironov9ea66072017-11-27 02:36:06576
577 do {
578 block_and_wait = 0;
579 // poll data
Mikhail Mironov9ea66072017-11-27 02:36:06580
Dmitrii Ovchinnikov88a8ba52024-10-15 17:52:12581 res_query = ctx->encoder->pVtbl->QueryOutput(ctx->encoder, &data);
582 if (data) {
583 // copy data to packet
584 AMFBuffer *buffer;
585 AMFGuid guid = IID_AMFBuffer();
586 data->pVtbl->QueryInterface(data, &guid, (void**)&buffer); // query for buffer interface
587 ret = amf_copy_buffer(avctx, avpkt, buffer);
588 if (amf_release_attached_frame_ref(buffer) == AMF_OK) {
589 ctx->hwsurfaces_in_queue--;
590 }
591 ctx->encoded_frame++;
592 buffer->pVtbl->Release(buffer);
593 data->pVtbl->Release(data);
Alexander Kravchenko05f1a3f2018-04-09 16:48:33594
Dmitrii Ovchinnikov88a8ba52024-10-15 17:52:12595 AMF_RETURN_IF_FALSE(ctx, ret >= 0, ret, "amf_copy_buffer() failed with error %d\n", ret);
596
597 if (ctx->delayed_drain) { // try to resubmit drain
598 res = ctx->encoder->pVtbl->Drain(ctx->encoder);
599 if (res != AMF_INPUT_FULL) {
600 ctx->delayed_drain = 0;
601 ctx->eof = 1; // drain started
602 AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, "Repeated Drain() failed with error %d\n", res);
603 } else {
604 av_log(avctx, AV_LOG_WARNING, "Data acquired but delayed drain submission got AMF_INPUT_FULL- should not happen\n");
Mikhail Mironov9ea66072017-11-27 02:36:06605 }
Mikhail Mironov9ea66072017-11-27 02:36:06606 }
Dmitrii Ovchinnikov88a8ba52024-10-15 17:52:12607 } else if (ctx->delayed_drain || (ctx->eof && res_query != AMF_EOF) || (ctx->hwsurfaces_in_queue >= ctx->hwsurfaces_in_queue_max) || input_full) {
608 block_and_wait = 1;
609 // Only sleep if the driver doesn't support waiting in QueryOutput()
610 // or if we already have output data so we will skip calling it.
611 if (!ctx->query_timeout_supported || avpkt->data || avpkt->buf) {
612 av_usleep(1000);
Dmitrii Ovchinnikovf593dc92023-05-17 12:59:40613 }
Mikhail Mironov9ea66072017-11-27 02:36:06614 }
615 } while (block_and_wait);
616
617 if (res_query == AMF_EOF) {
618 ret = AVERROR_EOF;
619 } else if (data == NULL) {
620 ret = AVERROR(EAGAIN);
621 } else {
Dmitrii Ovchinnikov88a8ba52024-10-15 17:52:12622 if(input_full) {
623 // resubmit surface
624 res = ctx->encoder->pVtbl->SubmitInput(ctx->encoder, (AMFData*)surface);
625 surface->pVtbl->Release(surface);
626 if (res == AMF_INPUT_FULL) {
627 av_log(avctx, AV_LOG_WARNING, "Data acquired but delayed SubmitInput returned AMF_INPUT_FULL- should not happen\n");
628 } else {
629 AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, "SubmitInput() failed with error %d\n", res);
630
631 ret = av_fifo_write(ctx->timestamp_list, &pts, 1);
632
633 ctx->submitted_frame++;
634
635 if (ret < 0)
636 return ret;
637 }
638 }
Mikhail Mironov9ea66072017-11-27 02:36:06639 ret = 0;
640 }
641 return ret;
642}
OvchinnikovDmitrii2fb764e2020-10-15 00:16:21643
Michael Fabian 'Xaymar' Dirksfb4dd4b2024-07-31 16:00:57644int ff_amf_get_color_profile(AVCodecContext *avctx)
645{
646 amf_int64 color_profile = AMF_VIDEO_CONVERTER_COLOR_PROFILE_UNKNOWN;
647 if (avctx->color_range == AVCOL_RANGE_JPEG) {
648 /// Color Space for Full (JPEG) Range
649 switch (avctx->colorspace) {
650 case AVCOL_SPC_SMPTE170M:
651 color_profile = AMF_VIDEO_CONVERTER_COLOR_PROFILE_FULL_601;
652 break;
653 case AVCOL_SPC_BT709:
654 color_profile = AMF_VIDEO_CONVERTER_COLOR_PROFILE_FULL_709;
655 break;
656 case AVCOL_SPC_BT2020_NCL:
657 case AVCOL_SPC_BT2020_CL:
658 color_profile = AMF_VIDEO_CONVERTER_COLOR_PROFILE_FULL_2020;
659 break;
660 }
661 } else {
662 /// Color Space for Limited (MPEG) range
663 switch (avctx->colorspace) {
664 case AVCOL_SPC_SMPTE170M:
665 color_profile = AMF_VIDEO_CONVERTER_COLOR_PROFILE_601;
666 break;
667 case AVCOL_SPC_BT709:
668 color_profile = AMF_VIDEO_CONVERTER_COLOR_PROFILE_709;
669 break;
670 case AVCOL_SPC_BT2020_NCL:
671 case AVCOL_SPC_BT2020_CL:
672 color_profile = AMF_VIDEO_CONVERTER_COLOR_PROFILE_2020;
673 break;
674 }
675 }
676 return color_profile;
677}
678
OvchinnikovDmitrii2fb764e2020-10-15 00:16:21679const AVCodecHWConfigInternal *const ff_amfenc_hw_configs[] = {
680#if CONFIG_D3D11VA
681 HW_CONFIG_ENCODER_FRAMES(D3D11, D3D11VA),
682 HW_CONFIG_ENCODER_DEVICE(NONE, D3D11VA),
683#endif
684#if CONFIG_DXVA2
685 HW_CONFIG_ENCODER_FRAMES(DXVA2_VLD, DXVA2),
686 HW_CONFIG_ENCODER_DEVICE(NONE, DXVA2),
687#endif
Dmitrii Ovchinnikov88a8ba52024-10-15 17:52:12688 HW_CONFIG_ENCODER_FRAMES(AMF_SURFACE, AMF),
689 HW_CONFIG_ENCODER_DEVICE(NONE, AMF),
OvchinnikovDmitrii2fb764e2020-10-15 00:16:21690 NULL,
691};