From 681aa7d14f97fd98181ca6d61e11be48fe65692d Mon Sep 17 00:00:00 2001 From: Zhong Li Date: Mon, 17 Sep 2018 19:16:44 +0800 Subject: lavu/qsv: make a copy as libmfx alignment requirement for uploading Libmfx requires 16 bytes aligned input/output for uploading. Currently only output is 16 byte aligned and assigning same width/height to input with smaller buffer size actually, thus definitely will cause segment fault. Can reproduce with any 1080p nv12 rawvideo input: ffmpeg -init_hw_device qsv=qsv:hw -hwaccel qsv -filter_hw_device qsv -f rawvideo -pix_fmt nv12 -s:v 1920x1080 -i 1080p_nv12.yuv -vf 'format=nv12,hwupload=extra_hw_frames=16,hwdownload,format=nv12' -an -y out_nv12.yuv It can fix #7418 Signed-off-by: Zhong Li --- libavutil/hwcontext_qsv.c | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) (limited to 'libavutil') diff --git a/libavutil/hwcontext_qsv.c b/libavutil/hwcontext_qsv.c index 33e121b..814ce21 100644 --- a/libavutil/hwcontext_qsv.c +++ b/libavutil/hwcontext_qsv.c @@ -862,6 +862,10 @@ 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, *src_frame; + int realigned = 0; + while (!s->session_upload_init && !s->session_upload && !ret) { #if HAVE_PTHREADS @@ -887,16 +891,36 @@ static int qsv_transfer_data_to(AVHWFramesContext *ctx, AVFrame *dst, 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; - map_frame_to_surface(src, &in); + map_frame_to_surface(src_frame, &in); do { err = MFXVideoVPP_RunFrameVPPAsync(s->session_upload, &in, out, NULL, &sync); @@ -917,6 +941,9 @@ static int qsv_transfer_data_to(AVHWFramesContext *ctx, AVFrame *dst, return AVERROR_UNKNOWN; } + if (realigned) + av_frame_unref(&tmp_frame); + return 0; } -- cgit v1.1