使用Libav与C++解码H264后转RGB遇bad src image ptrs错误
从输出信息和代码来看,核心问题是解码输出的帧格式与代码中假设的格式不匹配,且CodecContext参数未正确初始化,导致sws_scale的源格式校验失败。
问题根源分析
输出显示解码后帧的plane0行大小为图像宽度的3倍(3840×3=11520),plane1、2行大小为0,说明实际解码输出的是单平面RGB格式(如AV_PIX_FMT_RGB24),但代码错误地强制解码器输出YUV420P格式,且未同步流参数到CodecContext,导致sws_scale使用错误的源格式进行转换,触发check_image_pointers校验失败。
具体问题点及修复
1. 未同步流参数到CodecContext
初始化CodecContext时,必须将流的codecpar参数复制到Context中,否则Context的像素格式、分辨率等参数与实际解码输出不匹配。
修复代码(构造函数中):
// 新增:复制流参数到codecContext if (avcodec_parameters_to_context(codecContext, formatContext->streams[videoStreamIndex]->codecpar) < 0) { throw std::runtime_error("Could not copy codec parameters to context"); }
2. 手动强制设置frame格式错误
初始化frame时手动设置frame->format = AV_PIX_FMT_YUV420P会干扰解码器的自动格式设置,直接删除该代码即可:
// 初始化frame - 移除手动设置format的代码 frame = av_frame_alloc(); if (!frame) { throw std::runtime_error("Could not allocate frame"); }
3. av_image_fill_arrays使用错误的linesize
初始化RGB目标帧时,错误传入源帧的frame->linesize,应改为目标帧的frame2->linesize:
// 修复:使用frame2->linesize而非frame->linesize av_image_fill_arrays(frame2->data, frame2->linesize, frame2_buffer, AV_PIX_FMT_RGB24, frame->width, frame->height, 32);
4. SwsContext重复创建未释放
每次decode都创建新的SwsContext且不释放,会造成内存泄漏。修复时需在使用后调用sws_freeContext释放,建议将SwsContext的创建移到构造函数中复用。
修复后的decode方法核心片段:
SwsContext *sws_ctx = sws_getContext(frame->width, frame->height, static_cast<AVPixelFormat>(frame->format), // 使用实际解码的帧格式 frame->width, frame->height, AV_PIX_FMT_RGB24, SWS_BICUBIC, NULL, NULL, NULL); // ... 处理帧转换 ... // 释放资源 av_free(frame2_buffer); av_frame_free(&frame2); sws_freeContext(sws_ctx);
修复后效果
修复后,CodecContext会正确同步流参数,sws_scale使用实际解码输出的帧格式作为源格式,避免格式不匹配导致的指针校验错误,同时解决内存泄漏问题。
内容的提问来源于stack exchange,提问作者Sebastian DELLING

