diff mbox

[FFmpeg-devel,2/2] lavu/qsv: make a copy as libmfx alignment requirement for uploading

Message ID 1538298911-27149-2-git-send-email-zhong.li@intel.com
State Accepted
Headers show

Commit Message

Zhong Li Sept. 30, 2018, 9:15 a.m. UTC
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 <zhong.li@intel.com>
---
 libavutil/hwcontext_qsv.c | 31 +++++++++++++++++++++++++++++--
 1 file changed, 29 insertions(+), 2 deletions(-)

Comments

Max Dmitrichenko Oct. 1, 2018, 11:07 a.m. UTC | #1
On Sun, Sep 30, 2018 at 11:14 AM Zhong Li <zhong.li@intel.com> wrote:

> 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 <zhong.li@intel.com>
> ---
>  libavutil/hwcontext_qsv.c | 31 +++++++++++++++++++++++++++++--
>  1 file changed, 29 insertions(+), 2 deletions(-)
>
> diff --git a/libavutil/hwcontext_qsv.c b/libavutil/hwcontext_qsv.c
> index 33e121b..3039cfa 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;
>  }
>
> --
> 2.7.4
>
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel@ffmpeg.org
> http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


LGTM

regards
Max
diff mbox

Patch

diff --git a/libavutil/hwcontext_qsv.c b/libavutil/hwcontext_qsv.c
index 33e121b..3039cfa 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;
 }