最近找到一张32k的jpeg图片,尝试用ffmpeg来进行解码,命令如下:
ffmpeg -i enflame_32768-32768-420.jpg 32.yuv
结果出现Picture size 32768x32768 is invalid的错误:
找到报错的代码文件imgutils.c,以及函数:
int av_image_check_size2(unsigned int w, unsigned int h, int64_t max_pixels, enum AVPixelFormat pix_fmt, int log_offset, void *log_ctx)
{
ImgUtils imgutils = {
.class = &imgutils_class,
.log_offset = log_offset,
.log_ctx = log_ctx,
};
int64_t stride = av_image_get_linesize(pix_fmt, w, 0);
if (stride <= 0)
stride = 8LL*w;
stride += 128*8;
if ((int)w<=0 || (int)h<=0 || stride >= INT_MAX || stride*(uint64_t)(h+128) >= INT_MAX) {
av_log(&imgutils, AV_LOG_ERROR, "Picture size %ux%u is invalid\n", w, h);
return AVERROR(EINVAL);
}
if (max_pixels < INT64_MAX) {
if (w*(int64_t)h > max_pixels) {
av_log(&imgutils, AV_LOG_ERROR,
"Picture size %ux%u exceeds specified max pixel count %"PRId64", see the documentation if you wish to increase it\n",
w, h, max_pixels);
return AVERROR(EINVAL);
}
}
return 0;
}
下面是gdb中的调用栈:
可以看到这一次是在avformat_find_stream_info中调用了ffmpeg默认的解码器mjpeg,但是这个解码器内部不支持导致的。
下面打印了一下栈中的参数:
可以看到,w,h都为32768,但是pixfmt为AV_PIX_FMT_NONE,如果是这样的话,stride就会要成为一个默认最大值,stride = 8LL*w;
,然后会进入到下面的判断语句中,导致size invalid,那么第一个想到的是pix_fmt提前加上会不会就好了呢。
if ((int)w<=0 || (int)h<=0 || stride >= INT_MAX || stride*(uint64_t)(h+128) >= INT_MAX) {
av_log(&imgutils, AV_LOG_ERROR, "Picture size %ux%u is invalid\n", w, h);
return AVERROR(EINVAL);
}
继续看调用代码发现这个参数是写死的,就是AV_PIX_FMT_NONE,根本无法改变。
int av_image_check_size(unsigned int w, unsigned int h, int log_offset, void *log_ctx)
{
return av_image_check_size2(w, h, INT64_MAX, AV_PIX_FMT_NONE, log_offset, log_ctx);
}
通过计算发现32k(32768)失败的原因是超过了int_max了: