summaryrefslogtreecommitdiff
path: root/libavutil
diff options
context:
space:
mode:
authorWenbin Chen <wenbin.chen-at-intel.com@ffmpeg.org>2022-04-06 18:10:08 +0800
committerHaihao Xiang <haihao.xiang@intel.com>2022-04-13 13:41:27 +0800
commit7e7b3a4c283a4d70357cb0d2cb3fad8ae8377e2a (patch)
tree5252c4128c72e5c0cae8d26d2566e0ba37967ecf /libavutil
parent7427b87e44908a56d559c31b2c6f7a1e1575f5f9 (diff)
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@intel.com> Signed-off-by: Haihao Xiang <haihao.xiang@intel.com>
Diffstat (limited to 'libavutil')
-rw-r--r--libavutil/hwcontext_qsv.c47
1 files 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;