X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavutil%2Fhwcontext_qsv.c;h=8f9838d7d819b64db7e5251988a6c77d871451ef;hb=5ba769214f91f099f93185d33bd28e0460cc3908;hp=250091c4e85a26b16d018663a12c35ae3f403216;hpb=fb4a12cda4033f2f3d3d1039739f6e0e6f9afb82;p=ffmpeg diff --git a/libavutil/hwcontext_qsv.c b/libavutil/hwcontext_qsv.c index 250091c4e85..8f9838d7d81 100644 --- a/libavutil/hwcontext_qsv.c +++ b/libavutil/hwcontext_qsv.c @@ -23,6 +23,10 @@ #include "config.h" +#if HAVE_PTHREADS +#include +#endif + #if CONFIG_VAAPI #include "hwcontext_vaapi.h" #endif @@ -56,7 +60,13 @@ typedef struct QSVDeviceContext { typedef struct QSVFramesContext { mfxSession session_download; + int session_download_init; mfxSession session_upload; + int session_upload_init; +#if HAVE_PTHREADS + pthread_mutex_t session_lock; + pthread_cond_t session_cond; +#endif AVBufferRef *child_frames_ref; mfxFrameSurface1 *surfaces_internal; @@ -90,6 +100,7 @@ static const struct { uint32_t fourcc; } supported_pixel_formats[] = { { AV_PIX_FMT_NV12, MFX_FOURCC_NV12 }, + { AV_PIX_FMT_BGRA, MFX_FOURCC_RGB4 }, { AV_PIX_FMT_P010, MFX_FOURCC_P010 }, { AV_PIX_FMT_PAL8, MFX_FOURCC_P8 }, }; @@ -147,12 +158,19 @@ static void qsv_frames_uninit(AVHWFramesContext *ctx) MFXClose(s->session_download); } s->session_download = NULL; + s->session_download_init = 0; if (s->session_upload) { MFXVideoVPP_Close(s->session_upload); MFXClose(s->session_upload); } s->session_upload = NULL; + s->session_upload_init = 0; + +#if HAVE_PTHREADS + pthread_mutex_destroy(&s->session_lock); + pthread_cond_destroy(&s->session_cond); +#endif av_freep(&s->mem_ids); av_freep(&s->surface_ptrs); @@ -371,7 +389,7 @@ static mfxStatus frame_alloc(mfxHDL pthis, mfxFrameAllocRequest *req, !(req->Type & (MFX_MEMTYPE_FROM_VPPIN | MFX_MEMTYPE_FROM_VPPOUT)) || !(req->Type & MFX_MEMTYPE_EXTERNAL_FRAME)) return MFX_ERR_UNSUPPORTED; - if (i->Width != i1->Width || i->Height != i1->Height || + 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", @@ -535,13 +553,16 @@ static int qsv_frames_init(AVHWFramesContext *ctx) s->mem_ids[i] = frames_hwctx->surfaces[i].Data.MemId; } - ret = qsv_init_internal_session(ctx, &s->session_download, 0); - if (ret < 0) - return ret; + s->session_download = NULL; + s->session_upload = NULL; - ret = qsv_init_internal_session(ctx, &s->session_upload, 1); - if (ret < 0) - return ret; + s->session_download_init = 0; + s->session_upload_init = 0; + +#if HAVE_PTHREADS + pthread_mutex_init(&s->session_lock, NULL); + pthread_cond_init(&s->session_cond, NULL); +#endif return 0; } @@ -731,6 +752,37 @@ static int qsv_transfer_data_child(AVHWFramesContext *ctx, AVFrame *dst, return ret; } +static int map_frame_to_surface(const AVFrame *frame, mfxFrameSurface1 *surface) +{ + switch (frame->format) { + case AV_PIX_FMT_NV12: + case AV_PIX_FMT_P010: + surface->Data.Y = frame->data[0]; + surface->Data.UV = frame->data[1]; + break; + + case AV_PIX_FMT_YUV420P: + surface->Data.Y = frame->data[0]; + surface->Data.U = frame->data[1]; + surface->Data.V = frame->data[2]; + break; + + case AV_PIX_FMT_BGRA: + surface->Data.B = frame->data[0]; + surface->Data.G = frame->data[0] + 1; + surface->Data.R = frame->data[0] + 2; + surface->Data.A = frame->data[0] + 3; + break; + + default: + return MFX_ERR_UNSUPPORTED; + } + surface->Data.Pitch = frame->linesize[0]; + surface->Data.TimeStamp = frame->pts; + + return 0; +} + static int qsv_transfer_data_from(AVHWFramesContext *ctx, AVFrame *dst, const AVFrame *src) { @@ -740,6 +792,32 @@ static int qsv_transfer_data_from(AVHWFramesContext *ctx, AVFrame *dst, mfxSyncPoint sync = NULL; mfxStatus err; + int ret = 0; + + while (!s->session_download_init && !s->session_download && !ret) { +#if HAVE_PTHREADS + if (pthread_mutex_trylock(&s->session_lock) == 0) { +#endif + if (!s->session_download_init) { + ret = qsv_init_internal_session(ctx, &s->session_download, 0); + if (s->session_download) + s->session_download_init = 1; + } +#if HAVE_PTHREADS + pthread_mutex_unlock(&s->session_lock); + pthread_cond_signal(&s->session_cond); + } else { + pthread_mutex_lock(&s->session_lock); + while (!s->session_download_init && !s->session_download) { + pthread_cond_wait(&s->session_cond, &s->session_lock); + } + pthread_mutex_unlock(&s->session_lock); + } +#endif + } + + if (ret < 0) + return ret; if (!s->session_download) { if (s->child_frames_ref) @@ -750,11 +828,7 @@ static int qsv_transfer_data_from(AVHWFramesContext *ctx, AVFrame *dst, } out.Info = in->Info; - out.Data.PitchLow = dst->linesize[0]; - out.Data.Y = dst->data[0]; - out.Data.U = dst->data[1]; - out.Data.V = dst->data[2]; - out.Data.A = dst->data[3]; + map_frame_to_surface(dst, &out); do { err = MFXVideoVPP_RunFrameVPPAsync(s->session_download, in, &out, NULL, &sync); @@ -787,21 +861,67 @@ static int qsv_transfer_data_to(AVHWFramesContext *ctx, AVFrame *dst, mfxSyncPoint sync = NULL; mfxStatus err; + int ret = 0; + /* make a copy if the input is not padded as libmfx requires */ + AVFrame tmp_frame; + const AVFrame *src_frame; + int realigned = 0; + + + while (!s->session_upload_init && !s->session_upload && !ret) { +#if HAVE_PTHREADS + if (pthread_mutex_trylock(&s->session_lock) == 0) { +#endif + if (!s->session_upload_init) { + ret = qsv_init_internal_session(ctx, &s->session_upload, 1); + if (s->session_upload) + s->session_upload_init = 1; + } +#if HAVE_PTHREADS + pthread_mutex_unlock(&s->session_lock); + pthread_cond_signal(&s->session_cond); + } else { + pthread_mutex_lock(&s->session_lock); + while (!s->session_upload_init && !s->session_upload) { + pthread_cond_wait(&s->session_cond, &s->session_lock); + } + pthread_mutex_unlock(&s->session_lock); + } +#endif + } + if (ret < 0) + return ret; + + + if (src->height & 16 || src->linesize[0] & 16) { + realigned = 1; + memset(&tmp_frame, 0, sizeof(tmp_frame)); + tmp_frame.format = src->format; + tmp_frame.width = FFALIGN(src->width, 16); + tmp_frame.height = FFALIGN(src->height, 16); + ret = av_frame_get_buffer(&tmp_frame, 32); + if (ret < 0) + return ret; + + ret = av_frame_copy(&tmp_frame, src); + if (ret < 0) { + av_frame_unref(&tmp_frame); + return ret; + } + } + + src_frame = realigned ? &tmp_frame : src; if (!s->session_upload) { if (s->child_frames_ref) - return qsv_transfer_data_child(ctx, dst, src); + return qsv_transfer_data_child(ctx, dst, src_frame); av_log(ctx, AV_LOG_ERROR, "Surface upload not possible\n"); return AVERROR(ENOSYS); } in.Info = out->Info; - in.Data.PitchLow = src->linesize[0]; - in.Data.Y = src->data[0]; - in.Data.U = src->data[1]; - in.Data.V = src->data[2]; - in.Data.A = src->data[3]; + map_frame_to_surface(src_frame, &in); do { err = MFXVideoVPP_RunFrameVPPAsync(s->session_upload, &in, out, NULL, &sync); @@ -822,6 +942,9 @@ static int qsv_transfer_data_to(AVHWFramesContext *ctx, AVFrame *dst, return AVERROR_UNKNOWN; } + if (realigned) + av_frame_unref(&tmp_frame); + return 0; }