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 | mfxExtOpaqueSurfaceAlloc opaque_alloc; | 92 | mfxExtOpaqueSurfaceAlloc opaque_alloc; |
| 93 | mfxExtBuffer *ext_buffers[1]; | 93 | mfxExtBuffer *ext_buffers[1]; |
| 94 | AVFrame realigned_tmp_frame; | 94 | AVFrame realigned_upload_frame; |
| 95 | AVFrame realigned_download_frame; | ||
| 95 | } QSVFramesContext; | 96 | } QSVFramesContext; |
| 96 | 97 | ||
| 97 | static const struct { | 98 | static const struct { |
| @@ -303,7 +304,8 @@ static void qsv_frames_uninit(AVHWFramesContext *ctx) · 205 unmodified lines | |||
| 303 | av_freep(&s->surface_ptrs); | 304 | av_freep(&s->surface_ptrs); |
| 304 | av_freep(&s->surfaces_internal); | 305 | av_freep(&s->surfaces_internal); |
| 305 | av_freep(&s->handle_pairs_internal); | 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 | av_buffer_unref(&s->child_frames_ref); | 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 | mfxSyncPoint sync = NULL; | 1060 | mfxSyncPoint sync = NULL; |
| 1059 | mfxStatus err; | 1061 | mfxStatus err; |
| 1060 | int ret = 0; | 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 | ret = qsv_internal_session_check_init(ctx, 0); | 1068 | ret = qsv_internal_session_check_init(ctx, 0); |
| 1063 | if (ret < 0) | 1069 | if (ret < 0) |
| 1064 | return ret; | 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 | if (!s->session_download) { | 1093 | if (!s->session_download) { |
| 1067 | if (s->child_frames_ref) | 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 | av_log(ctx, AV_LOG_ERROR, "Surface download not possible\n"); | 1097 | av_log(ctx, AV_LOG_ERROR, "Surface download not possible\n"); |
| 1071 | return AVERROR(ENOSYS); | 1098 | return AVERROR(ENOSYS); |
| 1072 | } | 1099 | } |
| 1073 | 1100 | ||
| 1074 | out.Info = in->Info; | 1101 | out.Info = in->Info; |
| 1075 | map_frame_to_surface(dst, &out); | 1102 | map_frame_to_surface(dst_frame, &out); |
| 1076 | 1103 | ||
| 1077 | do { | 1104 | do { |
| 1078 | err = MFXVideoVPP_RunFrameVPPAsync(s->session_download, in, &out, NULL, &sync); | 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 | return AVERROR_UNKNOWN; | 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 | return 0; | 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 | mfxStatus err; | 1145 | mfxStatus err; |
| 1109 | int ret = 0; | 1146 | int ret = 0; |
| 1110 | /* make a copy if the input is not padded as libmfx requires */ | 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 | const AVFrame *src_frame; | 1149 | const AVFrame *src_frame; |
| 1113 | int realigned = 0; | 1150 | int realigned = 0; |
| 1114 | 1151 | ||