[FFmpeg-cvslog] amfenc: Retain a reference to D3D frames used as input during the encoding process
ffmpeg | branch: master | Alexander Kravchenko | Thu Apr 12 18:41:35 2018 +0300| [78149d6657302b58d5e46e8bc0a521ed009f86f7] | committer: Luca Barbato amfenc: Retain a reference to D3D frames used as input during the encoding process This fixes frame corruption issue when decoder started reusing frames while they are still in use of encoding process Issue with frame corruption was reproduced using: avconv.exe -y -hwaccel d3d11va -hwaccel_output_format d3d11 -i input.h264 -an -c:v h264_amf output.mkv It is recommended to use -extra_hw_frames 16 option in case if hw frames number in pool is not enough Signed-off-by: Luca Barbato > http://git.videolan.org/gitweb.cgi/ffmpeg.git/?a=commit;h=78149d6657302b58d5e46e8bc0a521ed009f86f7 --- libavcodec/amfenc.c | 95 - libavcodec/amfenc.h | 3 ++ 2 files changed, 97 insertions(+), 1 deletion(-) diff --git a/libavcodec/amfenc.c b/libavcodec/amfenc.c index 74b020b4d8..9a60050bc7 100644 --- a/libavcodec/amfenc.c +++ b/libavcodec/amfenc.c @@ -162,6 +162,9 @@ static int amf_init_context(AVCodecContext *avctx) AmfContext *ctx = avctx->priv_data; AMF_RESULT res = AMF_OK; +ctx->hwsurfaces_in_queue = 0; +ctx->hwsurfaces_in_queue_max = 16; + // configure AMF logger // the return of these functions indicates old state and do not affect behaviour ctx->trace->pVtbl->EnableWriter(ctx->trace, AMF_TRACE_WRITER_DEBUG_OUTPUT, ctx->log_to_dbg != 0 ); @@ -192,6 +195,8 @@ static int amf_init_context(AVCodecContext *avctx) if (!ctx->hw_frames_ctx) { return AVERROR(ENOMEM); } +if (device_ctx->initial_pool_size > 0) +ctx->hwsurfaces_in_queue_max = device_ctx->initial_pool_size - 1; } else { if(res == AMF_NOT_SUPPORTED) av_log(avctx, AV_LOG_INFO, "avctx->hw_frames_ctx has D3D11 device which doesn't have D3D11VA interface, switching to default\n"); @@ -447,6 +452,75 @@ int ff_amf_encode_init(AVCodecContext *avctx) return ret; } +static AMF_RESULT amf_set_property_buffer(AMFSurface *object, const wchar_t *name, AMFBuffer *val) +{ +AMF_RESULT res; +AMFVariantStruct var; +res = AMFVariantInit(); +if (res == AMF_OK) { +AMFGuid guid_AMFInterface = IID_AMFInterface(); +AMFInterface *amf_interface; +res = val->pVtbl->QueryInterface(val, _AMFInterface, (void**)_interface); + +if (res == AMF_OK) { +res = AMFVariantAssignInterface(, amf_interface); +amf_interface->pVtbl->Release(amf_interface); +} +if (res == AMF_OK) { +res = object->pVtbl->SetProperty(object, name, var); +} +AMFVariantClear(); +} +return res; +} + +static AMF_RESULT amf_get_property_buffer(AMFData *object, const wchar_t *name, AMFBuffer **val) +{ +AMF_RESULT res; +AMFVariantStruct var; +res = AMFVariantInit(); +if (res == AMF_OK) { +res = object->pVtbl->GetProperty(object, name, ); +if (res == AMF_OK) { +if (var.type == AMF_VARIANT_INTERFACE) { +AMFGuid guid_AMFBuffer = IID_AMFBuffer(); +AMFInterface *amf_interface = AMFVariantInterface(); +res = amf_interface->pVtbl->QueryInterface(amf_interface, _AMFBuffer, (void**)val); +} else { +res = AMF_INVALID_DATA_TYPE; +} +} +AMFVariantClear(); +} +return res; +} + +static AMFBuffer *amf_create_buffer_with_frame_ref(const AVFrame *frame, AMFContext *context) +{ +AVFrame *frame_ref; +AMFBuffer *frame_ref_storage_buffer = NULL; +AMF_RESULT res; + +res = context->pVtbl->AllocBuffer(context, AMF_MEMORY_HOST, sizeof(frame_ref), _ref_storage_buffer); +if (res == AMF_OK) { +frame_ref = av_frame_clone(frame); +if (frame_ref) { + memcpy(frame_ref_storage_buffer->pVtbl->GetNative(frame_ref_storage_buffer), _ref, sizeof(frame_ref)); +} else { +frame_ref_storage_buffer->pVtbl->Release(frame_ref_storage_buffer); +frame_ref_storage_buffer = NULL; +} +} +return frame_ref_storage_buffer; +} + +static void amf_release_buffer_with_frame_ref(AMFBuffer *frame_ref_storage_buffer) +{ +AVFrame *av_frame_ref; +memcpy(_frame_ref, frame_ref_storage_buffer->pVtbl->GetNative(frame_ref_storage_buffer), sizeof(av_frame_ref)); +av_frame_free(_frame_ref); +frame_ref_storage_buffer->pVtbl->Release(frame_ref_storage_buffer); +} int ff_amf_send_frame(AVCodecContext *avctx, const AVFrame *frame) { @@ -488,6 +562,8 @@ int ff_amf_send_frame(AVCodecContext *avctx, const
[FFmpeg-cvslog] amfenc: Add DXVA2 hardware frame input support
ffmpeg | branch: master | Alexander Kravchenko <akravchenko...@gmail.com> | Sat Apr 14 15:46:10 2018 +0100| [2c6ca2b54968ad3d2c947cdc16f92b6867f29f3a] | committer: Mark Thompson amfenc: Add DXVA2 hardware frame input support Adds support for AMF initialisation from a DXVA2 (Direct3D9) device, and then allows passing DXVA2 surfaces into an AMF encoder. Signed-off-by: Mark Thompson <s...@jkqxz.net> > http://git.videolan.org/gitweb.cgi/ffmpeg.git/?a=commit;h=2c6ca2b54968ad3d2c947cdc16f92b6867f29f3a --- libavcodec/amfenc.c | 79 + 1 file changed, 79 insertions(+) diff --git a/libavcodec/amfenc.c b/libavcodec/amfenc.c index 1ac4ebf456..2a8c76069b 100644 --- a/libavcodec/amfenc.c +++ b/libavcodec/amfenc.c @@ -24,6 +24,10 @@ #if CONFIG_D3D11VA #include "libavutil/hwcontext_d3d11va.h" #endif +#if CONFIG_DXVA2 +#define COBJMACROS +#include "libavutil/hwcontext_dxva2.h" +#endif #include "libavutil/mem.h" #include "libavutil/pixdesc.h" #include "libavutil/time.h" @@ -51,6 +55,9 @@ const enum AVPixelFormat ff_amf_pix_fmts[] = { #if CONFIG_D3D11VA AV_PIX_FMT_D3D11, #endif +#if CONFIG_DXVA2 +AV_PIX_FMT_DXVA2_VLD, +#endif AV_PIX_FMT_NONE }; @@ -162,6 +169,52 @@ static int amf_init_from_d3d11_device(AVCodecContext *avctx, AVD3D11VADeviceCont } #endif +#if CONFIG_DXVA2 +static int amf_init_from_dxva2_device(AVCodecContext *avctx, AVDXVA2DeviceContext *hwctx) +{ +AmfContext *ctx = avctx->priv_data; +HANDLE device_handle; +IDirect3DDevice9 *device; +HRESULT hr; +AMF_RESULT res; +int ret; + +hr = IDirect3DDeviceManager9_OpenDeviceHandle(hwctx->devmgr, _handle); +if (FAILED(hr)) { +av_log(avctx, AV_LOG_ERROR, "Failed to open device handle for Direct3D9 device: %lx.\n", (unsigned long)hr); +return AVERROR_EXTERNAL; +} + +hr = IDirect3DDeviceManager9_LockDevice(hwctx->devmgr, device_handle, , FALSE); +if (SUCCEEDED(hr)) { +IDirect3DDeviceManager9_UnlockDevice(hwctx->devmgr, device_handle, FALSE); +ret = 0; +} else { +av_log(avctx, AV_LOG_ERROR, "Failed to lock device handle for Direct3D9 device: %lx.\n", (unsigned long)hr); +ret = AVERROR_EXTERNAL; +} + +IDirect3DDeviceManager9_CloseDeviceHandle(hwctx->devmgr, device_handle); + +if (ret < 0) +return ret; + +res = ctx->context->pVtbl->InitDX9(ctx->context, device); + +IDirect3DDevice9_Release(device); + +if (res != AMF_OK) { +if (res == AMF_NOT_SUPPORTED) +av_log(avctx, AV_LOG_ERROR, "AMF via D3D9 is not supported on the given device.\n"); +else +av_log(avctx, AV_LOG_ERROR, "AMF failed to initialise on given D3D9 device: %d.\n", res); +return AVERROR(ENODEV); +} + +return 0; +} +#endif + static int amf_init_context(AVCodecContext *avctx) { AmfContext *ctx = avctx->priv_data; @@ -206,6 +259,13 @@ static int amf_init_context(AVCodecContext *avctx) return ret; break; #endif +#if CONFIG_DXVA2 +case AV_HWDEVICE_TYPE_DXVA2: +ret = amf_init_from_dxva2_device(avctx, frames_ctx->device_ctx->hwctx); +if (ret < 0) +return ret; +break; +#endif default: av_log(avctx, AV_LOG_ERROR, "AMF initialisation from a %s frames context is not supported.\n", av_hwdevice_get_type_name(frames_ctx->device_ctx->type)); @@ -230,6 +290,13 @@ static int amf_init_context(AVCodecContext *avctx) return ret; break; #endif +#if CONFIG_DXVA2 +case AV_HWDEVICE_TYPE_DXVA2: +ret = amf_init_from_dxva2_device(avctx, device_ctx->hwctx); +if (ret < 0) +return ret; +break; +#endif default: av_log(avctx, AV_LOG_ERROR, "AMF initialisation from a %s device is not supported.\n", av_hwdevice_get_type_name(device_ctx->type)); @@ -581,6 +648,18 @@ int ff_amf_send_frame(AVCodecContext *avctx, const AVFrame *frame) } break; #endif +#if CONFIG_DXVA2 +case AV_PIX_FMT_DXVA2_VLD: +{ +IDirect3DSurface9 *texture = (IDirect3DSurface9 *)frame->data[3]; // actual texture + +res = ctx->context->pVtbl->CreateSurfaceFromDX9Native(ctx->context, texture, , NULL); // wrap to AMF surface +AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR(ENOMEM), "CreateSurfaceFromDX9Native() failed with error %d\n", res); + +hw_surface = 1; +} +break; +#endif default: { res = ctx->context->pVtbl->AllocSurface(ctx->context, AMF_MEMORY_HOST, ctx->format, avctx->width, avctx->height, ); ___ ffmpeg-cvslog mailing list ffmpeg-cvslog@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-cvslog
[FFmpeg-cvslog] amfenc: Ensure that the software format of hardware frames is valid
ffmpeg | branch: master | Alexander Kravchenko <akravchenko...@gmail.com> | Sat Apr 14 15:46:05 2018 +0100| [ab7eed13a789b3f709a8964b0337bc69f152a9d7] | committer: Mark Thompson amfenc: Ensure that the software format of hardware frames is valid Signed-off-by: Mark Thompson <s...@jkqxz.net> > http://git.videolan.org/gitweb.cgi/ffmpeg.git/?a=commit;h=ab7eed13a789b3f709a8964b0337bc69f152a9d7 --- libavcodec/amfenc.c | 12 +--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/libavcodec/amfenc.c b/libavcodec/amfenc.c index 65a8e0a853..1ac4ebf456 100644 --- a/libavcodec/amfenc.c +++ b/libavcodec/amfenc.c @@ -68,7 +68,6 @@ static const FormatMap format_map[] = { AV_PIX_FMT_GRAY8, AMF_SURFACE_GRAY8 }, { AV_PIX_FMT_YUV420P,AMF_SURFACE_YUV420P }, { AV_PIX_FMT_YUYV422,AMF_SURFACE_YUY2 }, -{ AV_PIX_FMT_D3D11, AMF_SURFACE_NV12 }, }; static enum AMF_SURFACE_FORMAT amf_av_to_amf_format(enum AVPixelFormat fmt) @@ -263,6 +262,7 @@ static int amf_init_encoder(AVCodecContext *avctx) AmfContext *ctx = avctx->priv_data; const wchar_t *codec_id = NULL; AMF_RESULT res = AMF_OK; +enum AVPixelFormat pix_fmt; switch (avctx->codec->id) { case AV_CODEC_ID_H264: @@ -276,8 +276,14 @@ static int amf_init_encoder(AVCodecContext *avctx) } AMF_RETURN_IF_FALSE(ctx, codec_id != NULL, AVERROR(EINVAL), "Codec %d is not supported\n", avctx->codec->id); -ctx->format = amf_av_to_amf_format(avctx->pix_fmt); -AMF_RETURN_IF_FALSE(ctx, ctx->format != AMF_SURFACE_UNKNOWN, AVERROR(EINVAL), "Format %d is not supported\n", avctx->pix_fmt); +if (ctx->hw_frames_ctx) +pix_fmt = ((AVHWFramesContext*)ctx->hw_frames_ctx->data)->sw_format; +else +pix_fmt = avctx->pix_fmt; + +ctx->format = amf_av_to_amf_format(pix_fmt); +AMF_RETURN_IF_FALSE(ctx, ctx->format != AMF_SURFACE_UNKNOWN, AVERROR(EINVAL), +"Format %s is not supported\n", av_get_pix_fmt_name(pix_fmt)); res = ctx->factory->pVtbl->CreateComponent(ctx->factory, ctx->context, codec_id, >encoder); AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_ENCODER_NOT_FOUND, "CreateComponent(%ls) failed with error %d\n", codec_id, res); ___ ffmpeg-cvslog mailing list ffmpeg-cvslog@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-cvslog
[FFmpeg-cvslog] lavc/amfenc: Retain a reference to D3D frames used as input during the encoding process
ffmpeg | branch: master | Alexander Kravchenko <akravchenko...@gmail.com> | Mon Apr 9 19:48:33 2018 +0300| [05f1a3face140373ae658ab1abd6bacc841a770d] | committer: Mark Thompson lavc/amfenc: Retain a reference to D3D frames used as input during the encoding process Fixes ticket #6990. Tested-by: James Almer <jamr...@gmail.com> Reviewed-by: Mark Thompson <s...@jkqxz.net> > http://git.videolan.org/gitweb.cgi/ffmpeg.git/?a=commit;h=05f1a3face140373ae658ab1abd6bacc841a770d --- libavcodec/amfenc.c | 95 - libavcodec/amfenc.h | 3 ++ 2 files changed, 97 insertions(+), 1 deletion(-) diff --git a/libavcodec/amfenc.c b/libavcodec/amfenc.c index 89a10ff253..b9418b6791 100644 --- a/libavcodec/amfenc.c +++ b/libavcodec/amfenc.c @@ -157,6 +157,9 @@ static int amf_init_context(AVCodecContext *avctx) AmfContext *ctx = avctx->priv_data; AMF_RESULT res = AMF_OK; +ctx->hwsurfaces_in_queue = 0; +ctx->hwsurfaces_in_queue_max = 16; + // configure AMF logger // the return of these functions indicates old state and do not affect behaviour ctx->trace->pVtbl->EnableWriter(ctx->trace, AMF_TRACE_WRITER_DEBUG_OUTPUT, ctx->log_to_dbg != 0 ); @@ -187,6 +190,8 @@ static int amf_init_context(AVCodecContext *avctx) if (!ctx->hw_frames_ctx) { return AVERROR(ENOMEM); } +if (device_ctx->initial_pool_size > 0) +ctx->hwsurfaces_in_queue_max = device_ctx->initial_pool_size - 1; } else { if(res == AMF_NOT_SUPPORTED) av_log(avctx, AV_LOG_INFO, "avctx->hw_frames_ctx has D3D11 device which doesn't have D3D11VA interface, switching to default\n"); @@ -443,6 +448,75 @@ int ff_amf_encode_init(AVCodecContext *avctx) return ret; } +static AMF_RESULT amf_set_property_buffer(AMFSurface *object, const wchar_t *name, AMFBuffer *val) +{ +AMF_RESULT res; +AMFVariantStruct var; +res = AMFVariantInit(); +if (res == AMF_OK) { +AMFGuid guid_AMFInterface = IID_AMFInterface(); +AMFInterface *amf_interface; +res = val->pVtbl->QueryInterface(val, _AMFInterface, (void**)_interface); + +if (res == AMF_OK) { +res = AMFVariantAssignInterface(, amf_interface); +amf_interface->pVtbl->Release(amf_interface); +} +if (res == AMF_OK) { +res = object->pVtbl->SetProperty(object, name, var); +} +AMFVariantClear(); +} +return res; +} + +static AMF_RESULT amf_get_property_buffer(AMFData *object, const wchar_t *name, AMFBuffer **val) +{ +AMF_RESULT res; +AMFVariantStruct var; +res = AMFVariantInit(); +if (res == AMF_OK) { +res = object->pVtbl->GetProperty(object, name, ); +if (res == AMF_OK) { +if (var.type == AMF_VARIANT_INTERFACE) { +AMFGuid guid_AMFBuffer = IID_AMFBuffer(); +AMFInterface *amf_interface = AMFVariantInterface(); +res = amf_interface->pVtbl->QueryInterface(amf_interface, _AMFBuffer, (void**)val); +} else { +res = AMF_INVALID_DATA_TYPE; +} +} +AMFVariantClear(); +} +return res; +} + +static AMFBuffer *amf_create_buffer_with_frame_ref(const AVFrame *frame, AMFContext *context) +{ +AVFrame *frame_ref; +AMFBuffer *frame_ref_storage_buffer = NULL; +AMF_RESULT res; + +res = context->pVtbl->AllocBuffer(context, AMF_MEMORY_HOST, sizeof(frame_ref), _ref_storage_buffer); +if (res == AMF_OK) { +frame_ref = av_frame_clone(frame); +if (frame_ref) { + memcpy(frame_ref_storage_buffer->pVtbl->GetNative(frame_ref_storage_buffer), _ref, sizeof(frame_ref)); +} else { +frame_ref_storage_buffer->pVtbl->Release(frame_ref_storage_buffer); +frame_ref_storage_buffer = NULL; +} +} +return frame_ref_storage_buffer; +} + +static void amf_release_buffer_with_frame_ref(AMFBuffer *frame_ref_storage_buffer) +{ +AVFrame *av_frame_ref; +memcpy(_frame_ref, frame_ref_storage_buffer->pVtbl->GetNative(frame_ref_storage_buffer), sizeof(av_frame_ref)); +av_frame_free(_frame_ref); +frame_ref_storage_buffer->pVtbl->Release(frame_ref_storage_buffer); +} int ff_amf_send_frame(AVCodecContext *avctx, const AVFrame *frame) { @@ -484,6 +558,8 @@ int ff_amf_send_frame(AVCodecContext *avctx, const AVFrame *frame) (ctx->hw_device_ctx && ((AVHWFramesContext*)frame->hw_frames_ctx->data)->device_ctx == (AVHWDeviceContext*)ctx->hw_device_ctx->data) )) { +AMFBuffer *frame_ref_storage_bu
[FFmpeg-cvslog] amf: Replace writer_id option with LIBAV_AMF_WRITER_ID constant
ffmpeg | branch: master | Alexander Kravchenko <aakravche...@luxoft.com> | Wed Feb 28 06:33:05 2018 +| [80a4e6a46f21256e9bf508ead686563616945ad5] | committer: Diego Biurrun amf: Replace writer_id option with LIBAV_AMF_WRITER_ID constant AMFTraceWriter is an abstraction to configure how AMF outputs its logs for the current process and can be configured to output different levels of trace output. If multiple LibavWriter objects are used in one process, there will be duplication of output in av_log. Use a constant writer_id to prevent this scenario. Signed-off-by: Diego Biurrun <di...@biurrun.de> > http://git.videolan.org/gitweb.cgi/ffmpeg.git/?a=commit;h=80a4e6a46f21256e9bf508ead686563616945ad5 --- libavcodec/amfenc.c | 8 +--- libavcodec/amfenc.h | 4 +--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/libavcodec/amfenc.c b/libavcodec/amfenc.c index f305a48bf7..74b020b4d8 100644 --- a/libavcodec/amfenc.c +++ b/libavcodec/amfenc.c @@ -46,6 +46,8 @@ #include #endif +#define LIBAV_AMF_WRITER_ID L"libav_log" + #define PTS_PROP L"PtsProp" const enum AVPixelFormat ff_amf_pix_fmts[] = { @@ -171,8 +173,8 @@ static int amf_init_context(AVCodecContext *avctx) // connect AMF logger to av_log ctx->tracer.vtbl = _vtbl; ctx->tracer.avctx = avctx; -ctx->trace->pVtbl->RegisterWriter(ctx->trace, ctx->writer_id, (AMFTraceWriter*)>tracer, 1); -ctx->trace->pVtbl->SetWriterLevel(ctx->trace, ctx->writer_id, AMF_TRACE_TRACE); +ctx->trace->pVtbl->RegisterWriter(ctx->trace, LIBAV_AMF_WRITER_ID,(AMFTraceWriter *)>tracer, 1); +ctx->trace->pVtbl->SetWriterLevel(ctx->trace, LIBAV_AMF_WRITER_ID, AMF_TRACE_TRACE); res = ctx->factory->pVtbl->CreateContext(ctx->factory, >context); AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, "CreateContext() failed with error %d\n", res); @@ -283,7 +285,7 @@ int av_cold ff_amf_encode_close(AVCodecContext *avctx) av_buffer_unref(>hw_frames_ctx); if (ctx->trace) { -ctx->trace->pVtbl->UnregisterWriter(ctx->trace, ctx->writer_id); +ctx->trace->pVtbl->UnregisterWriter(ctx->trace, LIBAV_AMF_WRITER_ID); } if (ctx->library) { dlclose(ctx->library); diff --git a/libavcodec/amfenc.h b/libavcodec/amfenc.h index f3b82be770..a8153ef12e 100644 --- a/libavcodec/amfenc.h +++ b/libavcodec/amfenc.h @@ -80,7 +80,6 @@ typedef struct AmfContext { // common encoder options int log_to_dbg; -char*writer_id; // Static options, have to be set before Init() call int usage; @@ -152,7 +151,6 @@ extern const enum AVPixelFormat ff_amf_pix_fmts[]; } #define AMF_COMMON_OPTIONS \ -{ "log_to_dbg", "Enable AMF logging to debug output", OFFSET(log_to_dbg), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, VE }, \ -{ "writer_id", "Enable AMF logging to writer id", OFFSET(writer_id), AV_OPT_TYPE_STRING, { .str = "libavcodec" }, 0, 1, VE } \ +{ "log_to_dbg", "Enable AMF logging to debug output", OFFSET(log_to_dbg), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, VE } \ #endif //AVCODEC_AMFENC_H ___ ffmpeg-cvslog mailing list ffmpeg-cvslog@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-cvslog