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 -
Unified · Split
| @@ -91,7 +91,8 @@ typedef struct QSVFramesContext { · 90 unmodified lines | ||
| 91 | 91 | |
| 92 | 92 | mfxExtOpaqueSurfaceAlloc opaque_alloc; |
| 93 | 93 | mfxExtBuffer *ext_buffers[1]; |
| 94 | − AVFrame realigned_tmp_frame; | |
| 94 | + AVFrame realigned_upload_frame; | |
| 95 | + AVFrame realigned_download_frame; | |
| 95 | 96 | } QSVFramesContext; |
| 96 | 97 | |
| 97 | 98 | static const struct { |
| @@ -303,7 +304,8 @@ static void qsv_frames_uninit(AVHWFramesContext *ctx) · 205 unmodified lines | ||
| 303 | 304 | av_freep(&s->surface_ptrs); |
| 304 | 305 | av_freep(&s->surfaces_internal); |
| 305 | 306 | av_freep(&s->handle_pairs_internal); |
| 306 | − av_frame_unref(&s->realigned_tmp_frame); | |
| 307 | + av_frame_unref(&s->realigned_upload_frame); | |
| 308 | + av_frame_unref(&s->realigned_download_frame); | |
| 307 | 309 | av_buffer_unref(&s->child_frames_ref); |
| 308 | 310 | } |
| 309 | 311 | |
| @@ -1058,21 +1060,46 @@ static int qsv_transfer_data_from(AVHWFramesContext *ctx, AVFrame *dst, · 748 unmodified lines | ||
| 1058 | 1060 | mfxSyncPoint sync = NULL; |
| 1059 | 1061 | mfxStatus err; |
| 1060 | 1062 | int ret = 0; |
| 1063 | + /* download to temp frame if the output is not padded as libmfx requires */ | |
| 1064 | + AVFrame *tmp_frame = &s->realigned_download_frame; | |
| 1065 | + AVFrame *dst_frame; | |
| 1066 | + int realigned = 0; | |
| 1061 | 1067 | |
| 1062 | 1068 | ret = qsv_internal_session_check_init(ctx, 0); |
| 1063 | 1069 | if (ret < 0) |
| 1064 | 1070 | return ret; |
| 1065 | 1071 | |
| 1072 | + /* According to MSDK spec for mfxframeinfo, "Width must be a multiple of 16. | |
| 1073 | + * Height must be a multiple of 16 for progressive frame sequence and a | |
| 1074 | + * multiple of 32 otherwise.", so allign all frames to 16 before downloading. */ | |
| 1075 | + if (dst->height & 15 || dst->linesize[0] & 15) { | |
| 1076 | + realigned = 1; | |
| 1077 | + if (tmp_frame->format != dst->format || | |
| 1078 | + tmp_frame->width != FFALIGN(dst->linesize[0], 16) || | |
| 1079 | + tmp_frame->height != FFALIGN(dst->height, 16)) { | |
| 1080 | + av_frame_unref(tmp_frame); | |
| 1081 | + | |
| 1082 | + tmp_frame->format = dst->format; | |
| 1083 | + tmp_frame->width = FFALIGN(dst->linesize[0], 16); | |
| 1084 | + tmp_frame->height = FFALIGN(dst->height, 16); | |
| 1085 | + ret = av_frame_get_buffer(tmp_frame, 0); | |
| 1086 | + if (ret < 0) | |
| 1087 | + return ret; | |
| 1088 | + } | |
| 1089 | + } | |
| 1090 | + | |
| 1091 | + dst_frame = realigned ? tmp_frame : dst; | |
| 1092 | + | |
| 1066 | 1093 | if (!s->session_download) { |
| 1067 | 1094 | if (s->child_frames_ref) |
| 1068 | − return qsv_transfer_data_child(ctx, dst, src); | |
| 1095 | + return qsv_transfer_data_child(ctx, dst_frame, src); | |
| 1069 | 1096 | |
| 1070 | 1097 | av_log(ctx, AV_LOG_ERROR, "Surface download not possible\n"); |
| 1071 | 1098 | return AVERROR(ENOSYS); |
| 1072 | 1099 | } |
| 1073 | 1100 | |
| 1074 | 1101 | out.Info = in->Info; |
| 1075 | − map_frame_to_surface(dst, &out); | |
| 1102 | + map_frame_to_surface(dst_frame, &out); | |
| 1076 | 1103 | |
| 1077 | 1104 | do { |
| 1078 | 1105 | err = MFXVideoVPP_RunFrameVPPAsync(s->session_download, in, &out, NULL, &sync); |
| @@ -1093,6 +1120,16 @@ static int qsv_transfer_data_from(AVHWFramesContext *ctx, AVFrame *dst, · 14 unmodified lines | ||
| 1093 | 1120 | return AVERROR_UNKNOWN; |
| 1094 | 1121 | } |
| 1095 | 1122 | |
| 1123 | + if (realigned) { | |
| 1124 | + tmp_frame->width = dst->width; | |
| 1125 | + tmp_frame->height = dst->height; | |
| 1126 | + ret = av_frame_copy(dst, tmp_frame); | |
| 1127 | + tmp_frame->width = FFALIGN(dst->linesize[0], 16); | |
| 1128 | + tmp_frame->height = FFALIGN(dst->height, 16); | |
| 1129 | + if (ret < 0) | |
| 1130 | + return ret; | |
| 1131 | + } | |
| 1132 | + | |
| 1096 | 1133 | return 0; |
| 1097 | 1134 | } |
| 1098 | 1135 | |
| @@ -1108,7 +1145,7 @@ static int qsv_transfer_data_to(AVHWFramesContext *ctx, AVFrame *dst, · 9 unmodified lines | ||
| 1108 | 1145 | mfxStatus err; |
| 1109 | 1146 | int ret = 0; |
| 1110 | 1147 | /* make a copy if the input is not padded as libmfx requires */ |
| 1111 | − AVFrame *tmp_frame = &s->realigned_tmp_frame; | |
| 1148 | + AVFrame *tmp_frame = &s->realigned_upload_frame; | |
| 1112 | 1149 | const AVFrame *src_frame; |
| 1113 | 1150 | int realigned = 0; |
| 1114 | 1151 | |