[FFmpeg-cvslog] libavutil/hwcontext_qsv: Align width and heigh when download qsv frame

Wenbin Chen git at videolan.org
Wed Apr 13 08:43:33 EEST 2022


ffmpeg | branch: master | Wenbin Chen <wenbin.chen-at-intel.com at ffmpeg.org> | Wed Apr  6 18:10:08 2022 +0800| [7e7b3a4c283a4d70357cb0d2cb3fad8ae8377e2a] | committer: Haihao Xiang

libavutil/hwcontext_qsv: Align width and heigh when download qsv frame

The width and height for qsv frame to download need to be
aligned with 16. Add the alignment operation.
Now the following command works:
ffmpeg -hwaccel qsv -f rawvideo -s 1920x1080 -pix_fmt yuv420p -i \
input.yuv -vf "hwupload=extra_hw_frames=16,format=qsv,hwdownload, \
format=nv12" -f null -

Signed-off-by: Wenbin Chen <wenbin.chen at intel.com>
Signed-off-by: Haihao Xiang <haihao.xiang at intel.com>

> http://git.videolan.org/gitweb.cgi/ffmpeg.git/?a=commit;h=7e7b3a4c283a4d70357cb0d2cb3fad8ae8377e2a
---

 libavutil/hwcontext_qsv.c | 47 ++++++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 42 insertions(+), 5 deletions(-)

diff --git a/libavutil/hwcontext_qsv.c b/libavutil/hwcontext_qsv.c
index 95f8071abe..66c0e38955 100644
--- a/libavutil/hwcontext_qsv.c
+++ b/libavutil/hwcontext_qsv.c
@@ -91,7 +91,8 @@ typedef struct QSVFramesContext {
 
     mfxExtOpaqueSurfaceAlloc opaque_alloc;
     mfxExtBuffer *ext_buffers[1];
-    AVFrame realigned_tmp_frame;
+    AVFrame realigned_upload_frame;
+    AVFrame realigned_download_frame;
 } QSVFramesContext;
 
 static const struct {
@@ -303,7 +304,8 @@ static void qsv_frames_uninit(AVHWFramesContext *ctx)
     av_freep(&s->surface_ptrs);
     av_freep(&s->surfaces_internal);
     av_freep(&s->handle_pairs_internal);
-    av_frame_unref(&s->realigned_tmp_frame);
+    av_frame_unref(&s->realigned_upload_frame);
+    av_frame_unref(&s->realigned_download_frame);
     av_buffer_unref(&s->child_frames_ref);
 }
 
@@ -1058,21 +1060,46 @@ static int qsv_transfer_data_from(AVHWFramesContext *ctx, AVFrame *dst,
     mfxSyncPoint sync = NULL;
     mfxStatus err;
     int ret = 0;
+    /* download to temp frame if the output is not padded as libmfx requires */
+    AVFrame *tmp_frame = &s->realigned_download_frame;
+    AVFrame *dst_frame;
+    int realigned = 0;
 
     ret = qsv_internal_session_check_init(ctx, 0);
     if (ret < 0)
         return ret;
 
+    /* According to MSDK spec for mfxframeinfo, "Width must be a multiple of 16.
+     * Height must be a multiple of 16 for progressive frame sequence and a
+     * multiple of 32 otherwise.", so allign all frames to 16 before downloading. */
+    if (dst->height & 15 || dst->linesize[0] & 15) {
+        realigned = 1;
+        if (tmp_frame->format != dst->format ||
+            tmp_frame->width  != FFALIGN(dst->linesize[0], 16) ||
+            tmp_frame->height != FFALIGN(dst->height, 16)) {
+            av_frame_unref(tmp_frame);
+
+            tmp_frame->format = dst->format;
+            tmp_frame->width  = FFALIGN(dst->linesize[0], 16);
+            tmp_frame->height = FFALIGN(dst->height, 16);
+            ret = av_frame_get_buffer(tmp_frame, 0);
+            if (ret < 0)
+                return ret;
+        }
+    }
+
+    dst_frame = realigned ? tmp_frame : dst;
+
     if (!s->session_download) {
         if (s->child_frames_ref)
-            return qsv_transfer_data_child(ctx, dst, src);
+            return qsv_transfer_data_child(ctx, dst_frame, src);
 
         av_log(ctx, AV_LOG_ERROR, "Surface download not possible\n");
         return AVERROR(ENOSYS);
     }
 
     out.Info = in->Info;
-    map_frame_to_surface(dst, &out);
+    map_frame_to_surface(dst_frame, &out);
 
     do {
         err = MFXVideoVPP_RunFrameVPPAsync(s->session_download, in, &out, NULL, &sync);
@@ -1093,6 +1120,16 @@ static int qsv_transfer_data_from(AVHWFramesContext *ctx, AVFrame *dst,
         return AVERROR_UNKNOWN;
     }
 
+    if (realigned) {
+        tmp_frame->width  = dst->width;
+        tmp_frame->height = dst->height;
+        ret = av_frame_copy(dst, tmp_frame);
+        tmp_frame->width  = FFALIGN(dst->linesize[0], 16);
+        tmp_frame->height = FFALIGN(dst->height, 16);
+        if (ret < 0)
+            return ret;
+    }
+
     return 0;
 }
 
@@ -1108,7 +1145,7 @@ static int qsv_transfer_data_to(AVHWFramesContext *ctx, AVFrame *dst,
     mfxStatus err;
     int ret = 0;
     /* make a copy if the input is not padded as libmfx requires */
-    AVFrame *tmp_frame = &s->realigned_tmp_frame;
+    AVFrame *tmp_frame = &s->realigned_upload_frame;
     const AVFrame *src_frame;
     int realigned = 0;
 



More information about the ffmpeg-cvslog mailing list