diff options
author | Anton Khirnov <anton@khirnov.net> | 2016-05-27 13:23:19 +0200 |
---|---|---|
committer | Anton Khirnov <anton@khirnov.net> | 2016-06-21 19:53:38 +0200 |
commit | a0524d9b1e1bb0012207584f067096df7792df6c (patch) | |
tree | bdfb1267c302c700a8a4c5830631320a22d381fa | |
parent | 59e7361cc791e5103be1712dc59a2055f118d0da (diff) | |
download | ffmpeg-a0524d9b1e1bb0012207584f067096df7792df6c.tar.gz |
qsvdec: support getting the session from an AVHWFramesContext
-rw-r--r-- | libavcodec/qsv.c | 240 | ||||
-rw-r--r-- | libavcodec/qsv_internal.h | 11 | ||||
-rw-r--r-- | libavcodec/qsvdec.c | 62 | ||||
-rw-r--r-- | libavcodec/qsvdec.h | 2 | ||||
-rw-r--r-- | libavcodec/qsvdec_h2645.c | 2 | ||||
-rw-r--r-- | libavcodec/qsvdec_mpeg2.c | 2 |
6 files changed, 268 insertions, 51 deletions
diff --git a/libavcodec/qsv.c b/libavcodec/qsv.c index e08518be24..25147f206a 100644 --- a/libavcodec/qsv.c +++ b/libavcodec/qsv.c @@ -25,7 +25,10 @@ #include <string.h> #include "libavutil/avstring.h" +#include "libavutil/common.h" #include "libavutil/error.h" +#include "libavutil/hwcontext.h" +#include "libavutil/hwcontext_qsv.h" #include "avcodec.h" #include "qsv_internal.h" @@ -86,6 +89,56 @@ int ff_qsv_error(int mfx_err) } } +static int qsv_load_plugins(mfxSession session, const char *load_plugins, + void *logctx) +{ + if (!load_plugins || !*load_plugins) + return 0; + + while (*load_plugins) { + mfxPluginUID uid; + mfxStatus ret; + int i, err = 0; + + char *plugin = av_get_token(&load_plugins, ":"); + if (!plugin) + return AVERROR(ENOMEM); + if (strlen(plugin) != 2 * sizeof(uid.Data)) { + av_log(logctx, AV_LOG_ERROR, "Invalid plugin UID length\n"); + err = AVERROR(EINVAL); + goto load_plugin_fail; + } + + for (i = 0; i < sizeof(uid.Data); i++) { + err = sscanf(plugin + 2 * i, "%2hhx", uid.Data + i); + if (err != 1) { + av_log(logctx, AV_LOG_ERROR, "Invalid plugin UID\n"); + err = AVERROR(EINVAL); + goto load_plugin_fail; + } + + } + + ret = MFXVideoUSER_Load(session, &uid, 1); + if (ret < 0) { + av_log(logctx, AV_LOG_ERROR, "Could not load the requested plugin: %s\n", + plugin); + err = ff_qsv_error(ret); + goto load_plugin_fail; + } + + if (*load_plugins) + load_plugins++; +load_plugin_fail: + av_freep(&plugin); + if (err < 0) + return err; + } + + return 0; + +} + int ff_qsv_init_internal_session(AVCodecContext *avctx, mfxSession *session, const char *load_plugins) { @@ -101,45 +154,10 @@ int ff_qsv_init_internal_session(AVCodecContext *avctx, mfxSession *session, return ff_qsv_error(ret); } - if (load_plugins && *load_plugins) { - while (*load_plugins) { - mfxPluginUID uid; - int i, err = 0; - - char *plugin = av_get_token(&load_plugins, ":"); - if (!plugin) - return AVERROR(ENOMEM); - if (strlen(plugin) != 2 * sizeof(uid.Data)) { - av_log(avctx, AV_LOG_ERROR, "Invalid plugin UID length\n"); - err = AVERROR(EINVAL); - goto load_plugin_fail; - } - - for (i = 0; i < sizeof(uid.Data); i++) { - err = sscanf(plugin + 2 * i, "%2hhx", uid.Data + i); - if (err != 1) { - av_log(avctx, AV_LOG_ERROR, "Invalid plugin UID\n"); - err = AVERROR(EINVAL); - goto load_plugin_fail; - } - - } - - ret = MFXVideoUSER_Load(*session, &uid, 1); - if (ret < 0) { - av_log(avctx, AV_LOG_ERROR, "Could not load the requested plugin: %s\n", - plugin); - err = ff_qsv_error(ret); - goto load_plugin_fail; - } - - if (*load_plugins) - load_plugins++; -load_plugin_fail: - av_freep(&plugin); - if (err < 0) - return err; - } + ret = qsv_load_plugins(*session, load_plugins, avctx); + if (ret < 0) { + av_log(avctx, AV_LOG_ERROR, "Error loading plugins\n"); + return ret; } MFXQueryIMPL(*session, &impl); @@ -164,3 +182,147 @@ load_plugin_fail: return 0; } + +static mfxStatus qsv_frame_alloc(mfxHDL pthis, mfxFrameAllocRequest *req, + mfxFrameAllocResponse *resp) +{ + QSVFramesContext *ctx = pthis; + mfxFrameInfo *i = &req->Info; + mfxFrameInfo *i1 = &ctx->info; + + if (!(req->Type & MFX_MEMTYPE_VIDEO_MEMORY_DECODER_TARGET) || + !(req->Type & (MFX_MEMTYPE_FROM_DECODE)) || + !(req->Type & MFX_MEMTYPE_EXTERNAL_FRAME)) + return MFX_ERR_UNSUPPORTED; + if (i->Width != i1->Width || i->Height != i1->Height || + i->FourCC != i1->FourCC || i->ChromaFormat != i1->ChromaFormat) { + av_log(ctx, AV_LOG_ERROR, "Mismatching surface properties in an " + "allocation request: %dx%d %d %d vs %dx%d %d %d\n", + i->Width, i->Height, i->FourCC, i->ChromaFormat, + i1->Width, i1->Height, i1->FourCC, i1->ChromaFormat); + return MFX_ERR_UNSUPPORTED; + } + + resp->mids = ctx->mids; + resp->NumFrameActual = ctx->nb_mids; + + return MFX_ERR_NONE; +} + +static mfxStatus qsv_frame_free(mfxHDL pthis, mfxFrameAllocResponse *resp) +{ + return MFX_ERR_NONE; +} + +static mfxStatus qsv_frame_lock(mfxHDL pthis, mfxMemId mid, mfxFrameData *ptr) +{ + return MFX_ERR_UNSUPPORTED; +} + +static mfxStatus qsv_frame_unlock(mfxHDL pthis, mfxMemId mid, mfxFrameData *ptr) +{ + return MFX_ERR_UNSUPPORTED; +} + +static mfxStatus qsv_frame_get_hdl(mfxHDL pthis, mfxMemId mid, mfxHDL *hdl) +{ + *hdl = mid; + return MFX_ERR_NONE; +} + +int ff_qsv_init_session_hwcontext(AVCodecContext *avctx, mfxSession *psession, + QSVFramesContext *qsv_frames_ctx, + const char *load_plugins, int opaque) +{ + static const mfxHandleType handle_types[] = { + MFX_HANDLE_VA_DISPLAY, + MFX_HANDLE_D3D9_DEVICE_MANAGER, + MFX_HANDLE_D3D11_DEVICE, + }; + mfxFrameAllocator frame_allocator = { + .pthis = qsv_frames_ctx, + .Alloc = qsv_frame_alloc, + .Lock = qsv_frame_lock, + .Unlock = qsv_frame_unlock, + .GetHDL = qsv_frame_get_hdl, + .Free = qsv_frame_free, + }; + + AVHWFramesContext *frames_ctx = (AVHWFramesContext*)qsv_frames_ctx->hw_frames_ctx->data; + AVQSVFramesContext *frames_hwctx = frames_ctx->hwctx; + AVQSVDeviceContext *device_hwctx = frames_ctx->device_ctx->hwctx; + mfxSession parent_session = device_hwctx->session; + + mfxSession session; + mfxVersion ver; + mfxIMPL impl; + mfxHDL handle = NULL; + mfxHandleType handle_type; + mfxStatus err; + + int i, ret; + + err = MFXQueryIMPL(parent_session, &impl); + if (err == MFX_ERR_NONE) + err = MFXQueryVersion(parent_session, &ver); + if (err != MFX_ERR_NONE) { + av_log(avctx, AV_LOG_ERROR, "Error querying the session attributes\n"); + return ff_qsv_error(err); + } + + for (i = 0; i < FF_ARRAY_ELEMS(handle_types); i++) { + err = MFXVideoCORE_GetHandle(parent_session, handle_types[i], &handle); + if (err == MFX_ERR_NONE) { + handle_type = handle_types[i]; + break; + } + handle = NULL; + } + if (!handle) { + av_log(avctx, AV_LOG_VERBOSE, "No supported hw handle could be retrieved " + "from the session\n"); + } + + err = MFXInit(impl, &ver, &session); + if (err != MFX_ERR_NONE) { + av_log(avctx, AV_LOG_ERROR, + "Error initializing a child MFX session: %d\n", err); + return ff_qsv_error(err); + } + + if (handle) { + err = MFXVideoCORE_SetHandle(session, handle_type, handle); + if (err != MFX_ERR_NONE) { + av_log(avctx, AV_LOG_ERROR, "Error setting a HW handle: %d\n", err); + return ff_qsv_error(err); + } + } + + ret = qsv_load_plugins(session, load_plugins, avctx); + if (ret < 0) { + av_log(avctx, AV_LOG_ERROR, "Error loading plugins\n"); + return ret; + } + + if (!opaque) { + av_freep(&qsv_frames_ctx->mids); + qsv_frames_ctx->mids = av_mallocz_array(frames_hwctx->nb_surfaces, + sizeof(*qsv_frames_ctx->mids)); + if (!qsv_frames_ctx->mids) + return AVERROR(ENOMEM); + + qsv_frames_ctx->info = frames_hwctx->surfaces[0].Info; + qsv_frames_ctx->nb_mids = frames_hwctx->nb_surfaces; + for (i = 0; i < frames_hwctx->nb_surfaces; i++) + qsv_frames_ctx->mids[i] = frames_hwctx->surfaces[i].Data.MemId; + + err = MFXVideoCORE_SetFrameAllocator(session, &frame_allocator); + if (err != MFX_ERR_NONE) { + av_log(avctx, AV_LOG_ERROR, "Error setting a frame allocator: %d\n", err); + return ff_qsv_error(err); + } + } + + *psession = session; + return 0; +} diff --git a/libavcodec/qsv_internal.h b/libavcodec/qsv_internal.h index 1b7a2e77b2..ceee8df1dd 100644 --- a/libavcodec/qsv_internal.h +++ b/libavcodec/qsv_internal.h @@ -47,6 +47,13 @@ typedef struct QSVFrame { struct QSVFrame *next; } QSVFrame; +typedef struct QSVFramesContext { + AVBufferRef *hw_frames_ctx; + mfxFrameInfo info; + mfxMemId *mids; + int nb_mids; +} QSVFramesContext; + /** * Convert a libmfx error code into a libav error code. */ @@ -57,4 +64,8 @@ int ff_qsv_codec_id_to_mfx(enum AVCodecID codec_id); int ff_qsv_init_internal_session(AVCodecContext *avctx, mfxSession *session, const char *load_plugins); +int ff_qsv_init_session_hwcontext(AVCodecContext *avctx, mfxSession *session, + QSVFramesContext *qsv_frames_ctx, + const char *load_plugins, int opaque); + #endif /* AVCODEC_QSV_INTERNAL_H */ diff --git a/libavcodec/qsvdec.c b/libavcodec/qsvdec.c index e3e5bba508..ac7a1e60b9 100644 --- a/libavcodec/qsvdec.c +++ b/libavcodec/qsvdec.c @@ -27,6 +27,8 @@ #include <mfx/mfxvideo.h> #include "libavutil/common.h" +#include "libavutil/hwcontext.h" +#include "libavutil/hwcontext_qsv.h" #include "libavutil/mem.h" #include "libavutil/log.h" #include "libavutil/pixfmt.h" @@ -49,19 +51,42 @@ int ff_qsv_map_pixfmt(enum AVPixelFormat format) } } -static int qsv_init_session(AVCodecContext *avctx, QSVContext *q, mfxSession session) +static int qsv_init_session(AVCodecContext *avctx, QSVContext *q, mfxSession session, + AVBufferRef *hw_frames_ref) { - if (!session) { + int ret; + + if (session) { + q->session = session; + } else if (hw_frames_ref) { + if (q->internal_session) { + MFXClose(q->internal_session); + q->internal_session = NULL; + } + av_buffer_unref(&q->frames_ctx.hw_frames_ctx); + + q->frames_ctx.hw_frames_ctx = av_buffer_ref(hw_frames_ref); + if (!q->frames_ctx.hw_frames_ctx) + return AVERROR(ENOMEM); + + ret = ff_qsv_init_session_hwcontext(avctx, &q->internal_session, + &q->frames_ctx, q->load_plugins, + q->iopattern == MFX_IOPATTERN_OUT_OPAQUE_MEMORY); + if (ret < 0) { + av_buffer_unref(&q->frames_ctx.hw_frames_ctx); + return ret; + } + + q->session = q->internal_session; + } else { if (!q->internal_session) { - int ret = ff_qsv_init_internal_session(avctx, &q->internal_session, - q->load_plugins); + ret = ff_qsv_init_internal_session(avctx, &q->internal_session, + q->load_plugins); if (ret < 0) return ret; } q->session = q->internal_session; - } else { - q->session = session; } /* make sure the decoder is uninitialized */ @@ -73,6 +98,7 @@ static int qsv_init_session(AVCodecContext *avctx, QSVContext *q, mfxSession ses static int qsv_decode_init(AVCodecContext *avctx, QSVContext *q) { mfxSession session = NULL; + int iopattern = 0; mfxVideoParam param = { { 0 } }; int ret; @@ -86,12 +112,28 @@ static int qsv_decode_init(AVCodecContext *avctx, QSVContext *q) if (avctx->hwaccel_context) { AVQSVContext *user_ctx = avctx->hwaccel_context; session = user_ctx->session; - q->iopattern = user_ctx->iopattern; + iopattern = user_ctx->iopattern; q->ext_buffers = user_ctx->ext_buffers; q->nb_ext_buffers = user_ctx->nb_ext_buffers; } - ret = qsv_init_session(avctx, q, session); + if (avctx->hw_frames_ctx) { + AVHWFramesContext *frames_ctx = (AVHWFramesContext*)avctx->hw_frames_ctx->data; + AVQSVFramesContext *frames_hwctx = frames_ctx->hwctx; + + if (!iopattern) { + if (frames_hwctx->frame_type & MFX_MEMTYPE_OPAQUE_FRAME) + iopattern = MFX_IOPATTERN_OUT_OPAQUE_MEMORY; + else if (frames_hwctx->frame_type & MFX_MEMTYPE_VIDEO_MEMORY_DECODER_TARGET) + iopattern = MFX_IOPATTERN_OUT_VIDEO_MEMORY; + } + } + + if (!iopattern) + iopattern = MFX_IOPATTERN_OUT_SYSTEM_MEMORY; + q->iopattern = iopattern; + + ret = qsv_init_session(avctx, q, session, avctx->hw_frames_ctx); if (ret < 0) { av_log(avctx, AV_LOG_ERROR, "Error initializing an MFX session\n"); return ret; @@ -360,6 +402,10 @@ int ff_qsv_decode_close(QSVContext *q) if (q->internal_session) MFXClose(q->internal_session); + av_buffer_unref(&q->frames_ctx.hw_frames_ctx); + av_freep(&q->frames_ctx.mids); + q->frames_ctx.nb_mids = 0; + return 0; } diff --git a/libavcodec/qsvdec.h b/libavcodec/qsvdec.h index 698d8c89b4..9853591a99 100644 --- a/libavcodec/qsvdec.h +++ b/libavcodec/qsvdec.h @@ -43,6 +43,8 @@ typedef struct QSVContext { // one mfxSession internal_session; + QSVFramesContext frames_ctx; + /** * a linked list of frames currently being used by QSV */ diff --git a/libavcodec/qsvdec_h2645.c b/libavcodec/qsvdec_h2645.c index a65be995c4..134b5a614a 100644 --- a/libavcodec/qsvdec_h2645.c +++ b/libavcodec/qsvdec_h2645.c @@ -108,8 +108,6 @@ static av_cold int qsv_decode_init(AVCodecContext *avctx) goto fail; } - s->qsv.iopattern = MFX_IOPATTERN_OUT_SYSTEM_MEMORY; - return 0; fail: qsv_decode_close(avctx); diff --git a/libavcodec/qsvdec_mpeg2.c b/libavcodec/qsvdec_mpeg2.c index c319ac0df1..2daad566eb 100644 --- a/libavcodec/qsvdec_mpeg2.c +++ b/libavcodec/qsvdec_mpeg2.c @@ -80,8 +80,6 @@ static av_cold int qsv_decode_init(AVCodecContext *avctx) goto fail; } - s->qsv.iopattern = MFX_IOPATTERN_OUT_SYSTEM_MEMORY; - return 0; fail: qsv_decode_close(avctx); |