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 22#include "libavutil/avassert.h" 23#include "libavutil/imgutils.h" 24#include "libavutil/hwcontext.h" 25#if CONFIG_D3D11VA 26#include "libavutil/hwcontext_d3d11va.h" 27#endif 28#if CONFIG_DXVA2 29#define COBJMACROS 30#include "libavutil/hwcontext_dxva2.h" 31#endif 32#include "libavutil/mem.h" 33#include "libavutil/pixdesc.h" 34#include "libavutil/time.h" 35 36#include "amfenc.h" 37#include "encode.h" 38#include "internal.h" 39 40#if CONFIG_D3D11VA 41#include <d3d11.h> 42#endif 43 44#ifdef _WIN32 45#include "compat/w32dlfcn.h" 46#else 47#include <dlfcn.h> 48#endif 49 50#define FFMPEG_AMF_WRITER_ID L"ffmpeg_amf" 51 52#define PTS_PROP L"PtsProp" 53 54const enum AVPixelFormat ff_amf_pix_fmts[] = { 55 AV_PIX_FMT_NV12, 56 AV_PIX_FMT_YUV420P, 57#if CONFIG_D3D11VA 58 AV_PIX_FMT_D3D11, 59#endif 60#if CONFIG_DXVA2 61 AV_PIX_FMT_DXVA2_VLD, 62#endif 63 AV_PIX_FMT_NONE 64}; 65 66typedef struct FormatMap { 67 enum AVPixelFormat av_format; 68 enum AMF_SURFACE_FORMAT amf_format; 69} FormatMap; 70 71static const FormatMap format_map[] = 72{ 73 { AV_PIX_FMT_NONE, AMF_SURFACE_UNKNOWN }, 74 { AV_PIX_FMT_NV12, AMF_SURFACE_NV12 }, 75 { AV_PIX_FMT_BGR0, AMF_SURFACE_BGRA }, 76 { AV_PIX_FMT_RGB0, AMF_SURFACE_RGBA }, 77 { AV_PIX_FMT_GRAY8, AMF_SURFACE_GRAY8 }, 78 { AV_PIX_FMT_YUV420P, AMF_SURFACE_YUV420P }, 79 { AV_PIX_FMT_YUYV422, AMF_SURFACE_YUY2 }, 80}; 81 82static enum AMF_SURFACE_FORMAT amf_av_to_amf_format(enum AVPixelFormat fmt) 83{ 84 int i; 85 for (i = 0; i < amf_countof(format_map); i++) { 86 if (format_map[i].av_format == fmt) { 87 return format_map[i].amf_format; 88 } 89 } 90 return AMF_SURFACE_UNKNOWN; 91} 92 93static void AMF_CDECL_CALL AMFTraceWriter_Write(AMFTraceWriter *pThis, 94 const wchar_t *scope, const wchar_t *message) 95{ 96 AmfTraceWriter *tracer = (AmfTraceWriter*)pThis; 97 av_log(tracer->avctx, AV_LOG_DEBUG, "%ls: %ls", scope, message); // \n is provided from AMF 98} 99 100static void AMF_CDECL_CALL AMFTraceWriter_Flush(AMFTraceWriter *pThis) 101{ 102} 103 104static AMFTraceWriterVtbl tracer_vtbl = 105{ 106 .Write = AMFTraceWriter_Write, 107 .Flush = AMFTraceWriter_Flush, 108}; 109 110static int amf_load_library(AVCodecContext *avctx) 111{ 112 AmfContext *ctx = avctx->priv_data; 113 AMFInit_Fn init_fun; 114 AMFQueryVersion_Fn version_fun; 115 AMF_RESULT res; 116 117 ctx->delayed_frame = av_frame_alloc(); 118 if (!ctx->delayed_frame) { 119 return AVERROR(ENOMEM); 120 } 121 // hardcoded to current HW queue size - will auto-realloc if too small 122 ctx->timestamp_list = av_fifo_alloc2(avctx->max_b_frames + 16, sizeof(int64_t), 123 AV_FIFO_FLAG_AUTO_GROW); 124 if (!ctx->timestamp_list) { 125 return AVERROR(ENOMEM); 126 } 127 ctx->dts_delay = 0; 128 129 130 ctx->library = dlopen(AMF_DLL_NAMEA, RTLD_NOW | RTLD_LOCAL); 131 AMF_RETURN_IF_FALSE(ctx, ctx->library != NULL, 132 AVERROR_UNKNOWN, "DLL %s failed to open\n", AMF_DLL_NAMEA); 133 134 init_fun = (AMFInit_Fn)dlsym(ctx->library, AMF_INIT_FUNCTION_NAME); 135 AMF_RETURN_IF_FALSE(ctx, init_fun != NULL, AVERROR_UNKNOWN, "DLL %s failed to find function %s\n", AMF_DLL_NAMEA, AMF_INIT_FUNCTION_NAME); 136 137 version_fun = (AMFQueryVersion_Fn)dlsym(ctx->library, AMF_QUERY_VERSION_FUNCTION_NAME); 138 AMF_RETURN_IF_FALSE(ctx, version_fun != NULL, AVERROR_UNKNOWN, "DLL %s failed to find function %s\n", AMF_DLL_NAMEA, AMF_QUERY_VERSION_FUNCTION_NAME); 139 140 res = version_fun(&ctx->version); 141 AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, "%s failed with error %d\n", AMF_QUERY_VERSION_FUNCTION_NAME, res); 142 res = init_fun(AMF_FULL_VERSION, &ctx->factory); 143 AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, "%s failed with error %d\n", AMF_INIT_FUNCTION_NAME, res); 144 res = ctx->factory->pVtbl->GetTrace(ctx->factory, &ctx->trace); 145 AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, "GetTrace() failed with error %d\n", res); 146 res = ctx->factory->pVtbl->GetDebug(ctx->factory, &ctx->debug); 147 AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, "GetDebug() failed with error %d\n", res); 148 return 0; 149} 150 151#if CONFIG_D3D11VA 152static int amf_init_from_d3d11_device(AVCodecContext *avctx, AVD3D11VADeviceContext *hwctx) 153{ 154 AmfContext *ctx = avctx->priv_data; 155 AMF_RESULT res; 156 157 res = ctx->context->pVtbl->InitDX11(ctx->context, hwctx->device, AMF_DX11_1); 158 if (res != AMF_OK) { 159 if (res == AMF_NOT_SUPPORTED) 160 av_log(avctx, AV_LOG_ERROR, "AMF via D3D11 is not supported on the given device.\n"); 161 else 162 av_log(avctx, AV_LOG_ERROR, "AMF failed to initialise on the given D3D11 device: %d.\n", res); 163 return AVERROR(ENODEV); 164 } 165 166 return 0; 167} 168#endif 169 170#if CONFIG_DXVA2 171static int amf_init_from_dxva2_device(AVCodecContext *avctx, AVDXVA2DeviceContext *hwctx) 172{ 173 AmfContext *ctx = avctx->priv_data; 174 HANDLE device_handle; 175 IDirect3DDevice9 *device; 176 HRESULT hr; 177 AMF_RESULT res; 178 int ret; 179 180 hr = IDirect3DDeviceManager9_OpenDeviceHandle(hwctx->devmgr, &device_handle); 181 if (FAILED(hr)) { 182 av_log(avctx, AV_LOG_ERROR, "Failed to open device handle for Direct3D9 device: %lx.\n", (unsigned long)hr); 183 return AVERROR_EXTERNAL; 184 } 185 186 hr = IDirect3DDeviceManager9_LockDevice(hwctx->devmgr, device_handle, &device, FALSE); 187 if (SUCCEEDED(hr)) { 188 IDirect3DDeviceManager9_UnlockDevice(hwctx->devmgr, device_handle, FALSE); 189 ret = 0; 190 } else { 191 av_log(avctx, AV_LOG_ERROR, "Failed to lock device handle for Direct3D9 device: %lx.\n", (unsigned long)hr); 192 ret = AVERROR_EXTERNAL; 193 } 194 195 IDirect3DDeviceManager9_CloseDeviceHandle(hwctx->devmgr, device_handle); 196 197 if (ret < 0) 198 return ret; 199 200 res = ctx->context->pVtbl->InitDX9(ctx->context, device); 201 202 IDirect3DDevice9_Release(device); 203 204 if (res != AMF_OK) { 205 if (res == AMF_NOT_SUPPORTED) 206 av_log(avctx, AV_LOG_ERROR, "AMF via D3D9 is not supported on the given device.\n"); 207 else 208 av_log(avctx, AV_LOG_ERROR, "AMF failed to initialise on given D3D9 device: %d.\n", res); 209 return AVERROR(ENODEV); 210 } 211 212 return 0; 213} 214#endif 215 216static int amf_init_context(AVCodecContext *avctx) 217{ 218 AmfContext *ctx = avctx->priv_data; 219 AMFContext1 *context1 = NULL; 220 AMF_RESULT res; 221 av_unused int ret; 222 223 ctx->hwsurfaces_in_queue = 0; 224 ctx->hwsurfaces_in_queue_max = 16; 225 226 // configure AMF logger 227 // the return of these functions indicates old state and do not affect behaviour 228 ctx->trace->pVtbl->EnableWriter(ctx->trace, AMF_TRACE_WRITER_DEBUG_OUTPUT, ctx->log_to_dbg != 0 ); 229 if (ctx->log_to_dbg) 230 ctx->trace->pVtbl->SetWriterLevel(ctx->trace, AMF_TRACE_WRITER_DEBUG_OUTPUT, AMF_TRACE_TRACE); 231 ctx->trace->pVtbl->EnableWriter(ctx->trace, AMF_TRACE_WRITER_CONSOLE, 0); 232 ctx->trace->pVtbl->SetGlobalLevel(ctx->trace, AMF_TRACE_TRACE); 233 234 // connect AMF logger to av_log 235 ctx->tracer.vtbl = &tracer_vtbl; 236 ctx->tracer.avctx = avctx; 237 ctx->trace->pVtbl->RegisterWriter(ctx->trace, FFMPEG_AMF_WRITER_ID,(AMFTraceWriter*)&ctx->tracer, 1); 238 ctx->trace->pVtbl->SetWriterLevel(ctx->trace, FFMPEG_AMF_WRITER_ID, AMF_TRACE_TRACE); 239 240 res = ctx->factory->pVtbl->CreateContext(ctx->factory, &ctx->context); 241 AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, "CreateContext() failed with error %d\n", res); 242 243 // If a device was passed to the encoder, try to initialise from that. 244 if (avctx->hw_frames_ctx) { 245 AVHWFramesContext *frames_ctx = (AVHWFramesContext*)avctx->hw_frames_ctx->data; 246 247 if (amf_av_to_amf_format(frames_ctx->sw_format) == AMF_SURFACE_UNKNOWN) { 248 av_log(avctx, AV_LOG_ERROR, "Format of input frames context (%s) is not supported by AMF.\n", 249 av_get_pix_fmt_name(frames_ctx->sw_format)); 250 return AVERROR(EINVAL); 251 } 252 253 switch (frames_ctx->device_ctx->type) { 254#if CONFIG_D3D11VA 255 case AV_HWDEVICE_TYPE_D3D11VA: 256 ret = amf_init_from_d3d11_device(avctx, frames_ctx->device_ctx->hwctx); 257 if (ret < 0) 258 return ret; 259 break; 260#endif 261#if CONFIG_DXVA2 262 case AV_HWDEVICE_TYPE_DXVA2: 263 ret = amf_init_from_dxva2_device(avctx, frames_ctx->device_ctx->hwctx); 264 if (ret < 0) 265 return ret; 266 break; 267#endif 268 default: 269 av_log(avctx, AV_LOG_ERROR, "AMF initialisation from a %s frames context is not supported.\n", 270 av_hwdevice_get_type_name(frames_ctx->device_ctx->type)); 271 return AVERROR(ENOSYS); 272 } 273 274 ctx->hw_frames_ctx = av_buffer_ref(avctx->hw_frames_ctx); 275 if (!ctx->hw_frames_ctx) 276 return AVERROR(ENOMEM); 277 278 if (frames_ctx->initial_pool_size > 0) 279 ctx->hwsurfaces_in_queue_max = frames_ctx->initial_pool_size - 1; 280 281 } else if (avctx->hw_device_ctx) { 282 AVHWDeviceContext *device_ctx = (AVHWDeviceContext*)avctx->hw_device_ctx->data; 283 284 switch (device_ctx->type) { 285#if CONFIG_D3D11VA 286 case AV_HWDEVICE_TYPE_D3D11VA: 287 ret = amf_init_from_d3d11_device(avctx, device_ctx->hwctx); 288 if (ret < 0) 289 return ret; 290 break; 291#endif 292#if CONFIG_DXVA2 293 case AV_HWDEVICE_TYPE_DXVA2: 294 ret = amf_init_from_dxva2_device(avctx, device_ctx->hwctx); 295 if (ret < 0) 296 return ret; 297 break; 298#endif 299 default: 300 av_log(avctx, AV_LOG_ERROR, "AMF initialisation from a %s device is not supported.\n", 301 av_hwdevice_get_type_name(device_ctx->type)); 302 return AVERROR(ENOSYS); 303 } 304 305 ctx->hw_device_ctx = av_buffer_ref(avctx->hw_device_ctx); 306 if (!ctx->hw_device_ctx) 307 return AVERROR(ENOMEM); 308 309 } else { 310 res = ctx->context->pVtbl->InitDX11(ctx->context, NULL, AMF_DX11_1); 311 if (res == AMF_OK) { 312 av_log(avctx, AV_LOG_VERBOSE, "AMF initialisation succeeded via D3D11.\n"); 313 } else { 314 res = ctx->context->pVtbl->InitDX9(ctx->context, NULL); 315 if (res == AMF_OK) { 316 av_log(avctx, AV_LOG_VERBOSE, "AMF initialisation succeeded via D3D9.\n"); 317 } else { 318 AMFGuid guid = IID_AMFContext1(); 319 res = ctx->context->pVtbl->QueryInterface(ctx->context, &guid, (void**)&context1); 320 AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, "CreateContext1() failed with error %d\n", res); 321 322 res = context1->pVtbl->InitVulkan(context1, NULL); 323 context1->pVtbl->Release(context1); 324 if (res != AMF_OK) { 325 if (res == AMF_NOT_SUPPORTED) 326 av_log(avctx, AV_LOG_ERROR, "AMF via Vulkan is not supported on the given device.\n"); 327 else 328 av_log(avctx, AV_LOG_ERROR, "AMF failed to initialise on the given Vulkan device: %d.\n", res); 329 return AVERROR(ENOSYS); 330 } 331 av_log(avctx, AV_LOG_VERBOSE, "AMF initialisation succeeded via Vulkan.\n"); 332 } 333 } 334 } 335 return 0; 336} 337 338static int amf_init_encoder(AVCodecContext *avctx) 339{ 340 AmfContext *ctx = avctx->priv_data; 341 const wchar_t *codec_id = NULL; 342 AMF_RESULT res; 343 enum AVPixelFormat pix_fmt; 344 345 switch (avctx->codec->id) { 346 case AV_CODEC_ID_H264: 347 codec_id = AMFVideoEncoderVCE_AVC; 348 break; 349 case AV_CODEC_ID_HEVC: 350 codec_id = AMFVideoEncoder_HEVC; 351 break; 352 default: 353 break; 354 } 355 AMF_RETURN_IF_FALSE(ctx, codec_id != NULL, AVERROR(EINVAL), "Codec %d is not supported\n", avctx->codec->id); 356 357 if (ctx->hw_frames_ctx) 358 pix_fmt = ((AVHWFramesContext*)ctx->hw_frames_ctx->data)->sw_format; 359 else 360 pix_fmt = avctx->pix_fmt; 361 362 ctx->format = amf_av_to_amf_format(pix_fmt); 363 AMF_RETURN_IF_FALSE(ctx, ctx->format != AMF_SURFACE_UNKNOWN, AVERROR(EINVAL), 364 "Format %s is not supported\n", av_get_pix_fmt_name(pix_fmt)); 365 366 res = ctx->factory->pVtbl->CreateComponent(ctx->factory, ctx->context, codec_id, &ctx->encoder); 367 AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_ENCODER_NOT_FOUND, "CreateComponent(%ls) failed with error %d\n", codec_id, res); 368 369 return 0; 370} 371 372int av_cold ff_amf_encode_close(AVCodecContext *avctx) 373{ 374 AmfContext *ctx = avctx->priv_data; 375 376 if (ctx->delayed_surface) { 377 ctx->delayed_surface->pVtbl->Release(ctx->delayed_surface); 378 ctx->delayed_surface = NULL; 379 } 380 381 if (ctx->encoder) { 382 ctx->encoder->pVtbl->Terminate(ctx->encoder); 383 ctx->encoder->pVtbl->Release(ctx->encoder); 384 ctx->encoder = NULL; 385 } 386 387 if (ctx->context) { 388 ctx->context->pVtbl->Terminate(ctx->context); 389 ctx->context->pVtbl->Release(ctx->context); 390 ctx->context = NULL; 391 } 392 av_buffer_unref(&ctx->hw_device_ctx); 393 av_buffer_unref(&ctx->hw_frames_ctx); 394 395 if (ctx->trace) { 396 ctx->trace->pVtbl->UnregisterWriter(ctx->trace, FFMPEG_AMF_WRITER_ID); 397 } 398 if (ctx->library) { 399 dlclose(ctx->library); 400 ctx->library = NULL; 401 } 402 ctx->trace = NULL; 403 ctx->debug = NULL; 404 ctx->factory = NULL; 405 ctx->version = 0; 406 ctx->delayed_drain = 0; 407 av_frame_free(&ctx->delayed_frame); 408 av_fifo_freep2(&ctx->timestamp_list); 409 410 return 0; 411} 412 413static int amf_copy_surface(AVCodecContext *avctx, const AVFrame *frame, 414 AMFSurface* surface) 415{ 416 AMFPlane *plane; 417 uint8_t *dst_data[4]; 418 int dst_linesize[4]; 419 int planes; 420 int i; 421 422 planes = surface->pVtbl->GetPlanesCount(surface); 423 av_assert0(planes < FF_ARRAY_ELEMS(dst_data)); 424 425 for (i = 0; i < planes; i++) { 426 plane = surface->pVtbl->GetPlaneAt(surface, i); 427 dst_data[i] = plane->pVtbl->GetNative(plane); 428 dst_linesize[i] = plane->pVtbl->GetHPitch(plane); 429 } 430 av_image_copy(dst_data, dst_linesize, 431 (const uint8_t**)frame->data, frame->linesize, frame->format, 432 avctx->width, avctx->height); 433 434 return 0; 435} 436 437static int amf_copy_buffer(AVCodecContext *avctx, AVPacket *pkt, AMFBuffer *buffer) 438{ 439 AmfContext *ctx = avctx->priv_data; 440 int ret; 441 AMFVariantStruct var = {0}; 442 int64_t timestamp = AV_NOPTS_VALUE; 443 int64_t size = buffer->pVtbl->GetSize(buffer); 444 445 if ((ret = ff_get_encode_buffer(avctx, pkt, size, 0)) < 0) { 446 return ret; 447 } 448 memcpy(pkt->data, buffer->pVtbl->GetNative(buffer), size); 449 450 switch (avctx->codec->id) { 451 case AV_CODEC_ID_H264: 452 buffer->pVtbl->GetProperty(buffer, AMF_VIDEO_ENCODER_OUTPUT_DATA_TYPE, &var); 453 if(var.int64Value == AMF_VIDEO_ENCODER_OUTPUT_DATA_TYPE_IDR) { 454 pkt->flags = AV_PKT_FLAG_KEY; 455 } 456 break; 457 case AV_CODEC_ID_HEVC: 458 buffer->pVtbl->GetProperty(buffer, AMF_VIDEO_ENCODER_HEVC_OUTPUT_DATA_TYPE, &var); 459 if (var.int64Value == AMF_VIDEO_ENCODER_HEVC_OUTPUT_DATA_TYPE_IDR) { 460 pkt->flags = AV_PKT_FLAG_KEY; 461 } 462 break; 463 default: 464 break; 465 } 466 467 buffer->pVtbl->GetProperty(buffer, PTS_PROP, &var); 468 469 pkt->pts = var.int64Value; // original pts 470 471 472 AMF_RETURN_IF_FALSE(ctx, av_fifo_read(ctx->timestamp_list, ×tamp, 1) >= 0, 473 AVERROR_UNKNOWN, "timestamp_list is empty\n"); 474 475 // calc dts shift if max_b_frames > 0 476 if (avctx->max_b_frames > 0 && ctx->dts_delay == 0) { 477 int64_t timestamp_last = AV_NOPTS_VALUE; 478 size_t can_read = av_fifo_can_read(ctx->timestamp_list); 479 480 AMF_RETURN_IF_FALSE(ctx, can_read > 0, AVERROR_UNKNOWN, 481 "timestamp_list is empty while max_b_frames = %d\n", avctx->max_b_frames); 482 av_fifo_peek(ctx->timestamp_list, ×tamp_last, 1, can_read - 1); 483 if (timestamp < 0 || timestamp_last < AV_NOPTS_VALUE) { 484 return AVERROR(ERANGE); 485 } 486 ctx->dts_delay = timestamp_last - timestamp; 487 } 488 pkt->dts = timestamp - ctx->dts_delay; 489 return 0; 490} 491 492// amfenc API implementation 493int ff_amf_encode_init(AVCodecContext *avctx) 494{ 495 int ret; 496 497 if ((ret = amf_load_library(avctx)) == 0) { 498 if ((ret = amf_init_context(avctx)) == 0) { 499 if ((ret = amf_init_encoder(avctx)) == 0) { 500 return 0; 501 } 502 } 503 } 504 ff_amf_encode_close(avctx); 505 return ret; 506} 507 508static AMF_RESULT amf_set_property_buffer(AMFSurface *object, const wchar_t *name, AMFBuffer *val) 509{ 510 AMF_RESULT res; 511 AMFVariantStruct var; 512 res = AMFVariantInit(&var); 513 if (res == AMF_OK) { 514 AMFGuid guid_AMFInterface = IID_AMFInterface(); 515 AMFInterface *amf_interface; 516 res = val->pVtbl->QueryInterface(val, &guid_AMFInterface, (void**)&amf_interface); 517 518 if (res == AMF_OK) { 519 res = AMFVariantAssignInterface(&var, amf_interface); 520 amf_interface->pVtbl->Release(amf_interface); 521 } 522 if (res == AMF_OK) { 523 res = object->pVtbl->SetProperty(object, name, var); 524 } 525 AMFVariantClear(&var); 526 } 527 return res; 528} 529 530static AMF_RESULT amf_get_property_buffer(AMFData *object, const wchar_t *name, AMFBuffer **val) 531{ 532 AMF_RESULT res; 533 AMFVariantStruct var; 534 res = AMFVariantInit(&var); 535 if (res == AMF_OK) { 536 res = object->pVtbl->GetProperty(object, name, &var); 537 if (res == AMF_OK) { 538 if (var.type == AMF_VARIANT_INTERFACE) { 539 AMFGuid guid_AMFBuffer = IID_AMFBuffer(); 540 AMFInterface *amf_interface = AMFVariantInterface(&var); 541 res = amf_interface->pVtbl->QueryInterface(amf_interface, &guid_AMFBuffer, (void**)val); 542 } else { 543 res = AMF_INVALID_DATA_TYPE; 544 } 545 } 546 AMFVariantClear(&var); 547 } 548 return res; 549} 550 551static AMFBuffer *amf_create_buffer_with_frame_ref(const AVFrame *frame, AMFContext *context) 552{ 553 AVFrame *frame_ref; 554 AMFBuffer *frame_ref_storage_buffer = NULL; 555 AMF_RESULT res; 556 557 res = context->pVtbl->AllocBuffer(context, AMF_MEMORY_HOST, sizeof(frame_ref), &frame_ref_storage_buffer); 558 if (res == AMF_OK) { 559 frame_ref = av_frame_clone(frame); 560 if (frame_ref) { 561 memcpy(frame_ref_storage_buffer->pVtbl->GetNative(frame_ref_storage_buffer), &frame_ref, sizeof(frame_ref)); 562 } else { 563 frame_ref_storage_buffer->pVtbl->Release(frame_ref_storage_buffer); 564 frame_ref_storage_buffer = NULL; 565 } 566 } 567 return frame_ref_storage_buffer; 568} 569 570static void amf_release_buffer_with_frame_ref(AMFBuffer *frame_ref_storage_buffer) 571{ 572 AVFrame *frame_ref; 573 memcpy(&frame_ref, frame_ref_storage_buffer->pVtbl->GetNative(frame_ref_storage_buffer), sizeof(frame_ref)); 574 av_frame_free(&frame_ref); 575 frame_ref_storage_buffer->pVtbl->Release(frame_ref_storage_buffer); 576} 577 578int ff_amf_receive_packet(AVCodecContext *avctx, AVPacket *avpkt) 579{ 580 AmfContext *ctx = avctx->priv_data; 581 AMFSurface *surface; 582 AMF_RESULT res; 583 int ret; 584 AMF_RESULT res_query; 585 AMFData *data = NULL; 586 AVFrame *frame = ctx->delayed_frame; 587 int block_and_wait; 588 589 if (!ctx->encoder) 590 return AVERROR(EINVAL); 591 592 if (!frame->buf[0]) { 593 ret = ff_encode_get_frame(avctx, frame); 594 if (ret < 0 && ret != AVERROR_EOF) 595 return ret; 596 } 597 598 if (!frame->buf[0]) { // submit drain 599 if (!ctx->eof) { // submit drain one time only 600 if (ctx->delayed_surface != NULL) { 601 ctx->delayed_drain = 1; // input queue is full: resubmit Drain() in ff_amf_receive_packet 602 } else if(!ctx->delayed_drain) { 603 res = ctx->encoder->pVtbl->Drain(ctx->encoder); 604 if (res == AMF_INPUT_FULL) { 605 ctx->delayed_drain = 1; // input queue is full: resubmit Drain() in ff_amf_receive_packet 606 } else { 607 if (res == AMF_OK) { 608 ctx->eof = 1; // drain started 609 } 610 AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, "Drain() failed with error %d\n", res); 611 } 612 } 613 } 614 } else if (!ctx->delayed_surface) { // submit frame 615 int hw_surface = 0; 616 617 // prepare surface from frame 618 switch (frame->format) { 619#if CONFIG_D3D11VA 620 case AV_PIX_FMT_D3D11: 621 { 622 static const GUID AMFTextureArrayIndexGUID = { 0x28115527, 0xe7c3, 0x4b66, { 0x99, 0xd3, 0x4f, 0x2a, 0xe6, 0xb4, 0x7f, 0xaf } }; 623 ID3D11Texture2D *texture = (ID3D11Texture2D*)frame->data[0]; // actual texture 624 int index = (intptr_t)frame->data[1]; // index is a slice in texture array is - set to tell AMF which slice to use 625 626 av_assert0(frame->hw_frames_ctx && ctx->hw_frames_ctx && 627 frame->hw_frames_ctx->data == ctx->hw_frames_ctx->data); 628 629 texture->lpVtbl->SetPrivateData(texture, &AMFTextureArrayIndexGUID, sizeof(index), &index); 630 631 res = ctx->context->pVtbl->CreateSurfaceFromDX11Native(ctx->context, texture, &surface, NULL); // wrap to AMF surface 632 AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR(ENOMEM), "CreateSurfaceFromDX11Native() failed with error %d\n", res); 633 634 hw_surface = 1; 635 } 636 break; 637#endif 638#if CONFIG_DXVA2 639 case AV_PIX_FMT_DXVA2_VLD: 640 { 641 IDirect3DSurface9 *texture = (IDirect3DSurface9 *)frame->data[3]; // actual texture 642 643 res = ctx->context->pVtbl->CreateSurfaceFromDX9Native(ctx->context, texture, &surface, NULL); // wrap to AMF surface 644 AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR(ENOMEM), "CreateSurfaceFromDX9Native() failed with error %d\n", res); 645 646 hw_surface = 1; 647 } 648 break; 649#endif 650 default: 651 { 652 res = ctx->context->pVtbl->AllocSurface(ctx->context, AMF_MEMORY_HOST, ctx->format, avctx->width, avctx->height, &surface); 653 AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR(ENOMEM), "AllocSurface() failed with error %d\n", res); 654 amf_copy_surface(avctx, frame, surface); 655 } 656 break; 657 } 658 659 if (hw_surface) { 660 AMFBuffer *frame_ref_storage_buffer; 661 662 // input HW surfaces can be vertically aligned by 16; tell AMF the real size 663 surface->pVtbl->SetCrop(surface, 0, 0, frame->width, frame->height); 664 665 frame_ref_storage_buffer = amf_create_buffer_with_frame_ref(frame, ctx->context); 666 AMF_RETURN_IF_FALSE(ctx, frame_ref_storage_buffer != NULL, AVERROR(ENOMEM), "create_buffer_with_frame_ref() returned NULL\n"); 667 668 res = amf_set_property_buffer(surface, L"av_frame_ref", frame_ref_storage_buffer); 669 AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, "SetProperty failed for \"av_frame_ref\" with error %d\n", res); 670 ctx->hwsurfaces_in_queue++; 671 frame_ref_storage_buffer->pVtbl->Release(frame_ref_storage_buffer); 672 } 673 674 surface->pVtbl->SetPts(surface, frame->pts); 675 AMF_ASSIGN_PROPERTY_INT64(res, surface, PTS_PROP, frame->pts); 676 677 switch (avctx->codec->id) { 678 case AV_CODEC_ID_H264: 679 AMF_ASSIGN_PROPERTY_INT64(res, surface, AMF_VIDEO_ENCODER_INSERT_AUD, !!ctx->aud); 680 break; 681 case AV_CODEC_ID_HEVC: 682 AMF_ASSIGN_PROPERTY_INT64(res, surface, AMF_VIDEO_ENCODER_HEVC_INSERT_AUD, !!ctx->aud); 683 break; 684 default: 685 break; 686 } 687 688 // submit surface 689 res = ctx->encoder->pVtbl->SubmitInput(ctx->encoder, (AMFData*)surface); 690 if (res == AMF_INPUT_FULL) { // handle full queue 691 //store surface for later submission 692 ctx->delayed_surface = surface; 693 } else { 694 int64_t pts = frame->pts; 695 surface->pVtbl->Release(surface); 696 AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, "SubmitInput() failed with error %d\n", res); 697 698 av_frame_unref(frame); 699 ret = av_fifo_write(ctx->timestamp_list, &pts, 1); 700 if (ret < 0) 701 return ret; 702 } 703 } 704 705 706 do { 707 block_and_wait = 0; 708 // poll data 709 res_query = ctx->encoder->pVtbl->QueryOutput(ctx->encoder, &data); 710 if (data) { 711 // copy data to packet 712 AMFBuffer* buffer; 713 AMFGuid guid = IID_AMFBuffer(); 714 data->pVtbl->QueryInterface(data, &guid, (void**)&buffer); // query for buffer interface 715 ret = amf_copy_buffer(avctx, avpkt, buffer); 716 717 buffer->pVtbl->Release(buffer); 718 719 if (data->pVtbl->HasProperty(data, L"av_frame_ref")) { 720 AMFBuffer *frame_ref_storage_buffer; 721 res = amf_get_property_buffer(data, L"av_frame_ref", &frame_ref_storage_buffer); 722 AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, "GetProperty failed for \"av_frame_ref\" with error %d\n", res); 723 amf_release_buffer_with_frame_ref(frame_ref_storage_buffer); 724 ctx->hwsurfaces_in_queue--; 725 } 726 727 data->pVtbl->Release(data); 728 729 AMF_RETURN_IF_FALSE(ctx, ret >= 0, ret, "amf_copy_buffer() failed with error %d\n", ret); 730 731 if (ctx->delayed_surface != NULL) { // try to resubmit frame 732 res = ctx->encoder->pVtbl->SubmitInput(ctx->encoder, (AMFData*)ctx->delayed_surface); 733 if (res != AMF_INPUT_FULL) { 734 int64_t pts = ctx->delayed_surface->pVtbl->GetPts(ctx->delayed_surface); 735 ctx->delayed_surface->pVtbl->Release(ctx->delayed_surface); 736 ctx->delayed_surface = NULL; 737 av_frame_unref(ctx->delayed_frame); 738 AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, "Repeated SubmitInput() failed with error %d\n", res); 739 740 ret = av_fifo_write(ctx->timestamp_list, &pts, 1); 741 if (ret < 0) 742 return ret; 743 } else { 744 av_log(avctx, AV_LOG_WARNING, "Data acquired but delayed frame submission got AMF_INPUT_FULL- should not happen\n"); 745 } 746 } else if (ctx->delayed_drain) { // try to resubmit drain 747 res = ctx->encoder->pVtbl->Drain(ctx->encoder); 748 if (res != AMF_INPUT_FULL) { 749 ctx->delayed_drain = 0; 750 ctx->eof = 1; // drain started 751 AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, "Repeated Drain() failed with error %d\n", res); 752 } else { 753 av_log(avctx, AV_LOG_WARNING, "Data acquired but delayed drain submission got AMF_INPUT_FULL- should not happen\n"); 754 } 755 } 756 } else if (ctx->delayed_surface != NULL || ctx->delayed_drain || (ctx->eof && res_query != AMF_EOF) || (ctx->hwsurfaces_in_queue >= ctx->hwsurfaces_in_queue_max)) { 757 block_and_wait = 1; 758 av_usleep(1000); // wait and poll again 759 } 760 } while (block_and_wait); 761 762 if (res_query == AMF_EOF) { 763 ret = AVERROR_EOF; 764 } else if (data == NULL) { 765 ret = AVERROR(EAGAIN); 766 } else { 767 ret = 0; 768 } 769 return ret; 770} 771 772const AVCodecHWConfigInternal *const ff_amfenc_hw_configs[] = { 773#if CONFIG_D3D11VA 774 HW_CONFIG_ENCODER_FRAMES(D3D11, D3D11VA), 775 HW_CONFIG_ENCODER_DEVICE(NONE, D3D11VA), 776#endif 777#if CONFIG_DXVA2 778 HW_CONFIG_ENCODER_FRAMES(DXVA2_VLD, DXVA2), 779 HW_CONFIG_ENCODER_DEVICE(NONE, DXVA2), 780#endif 781 NULL, 782}; 783