使用SDL2 RenderPixels结合FFmpeg生成H264视频画面错乱问题
解决SDL2 + FFmpeg编码H264画面错乱问题
以下是针对你遇到的画面错乱问题的核心排查和修复方案:
1. 处理SDL像素数据的行对齐问题
SDL_RenderReadPixels返回的像素缓冲区存在行对齐(Pitch),即每行实际占用的字节数可能大于宽度×4(RGBA每个像素4字节),这是因为SDL会按硬件要求对齐内存(比如4字节或16字节对齐)。如果直接把整块SDL像素数据传给FFmpeg,每行末尾的冗余字节会被错误解析为下一行的像素,导致画面错乱。
修复代码示例:
// 假设从SDL获取的像素数据和参数 uint8_t* sdl_pixels = ...; // SDL_RenderReadPixels得到的像素指针 int sdl_pitch = ...; // SDL返回的行跨度 int width = ...; int height = ...; // 初始化FFmpeg的AVFrame(假设格式为AV_PIX_FMT_RGBA) AVFrame* frame = av_frame_alloc(); frame->format = AV_PIX_FMT_RGBA; frame->width = width; frame->height = height; av_frame_get_buffer(frame, 0); // 逐行拷贝SDL像素到FFmpeg帧,跳过对齐冗余 for (int y = 0; y < height; y++) { memcpy(frame->data[0] + y * frame->linesize[0], sdl_pixels + y * sdl_pitch, width * 4); }
2. 转换像素格式为H264编码器支持的格式
绝大多数H264编码器不直接支持RGBA输入,它们通常要求输入为YUV420P格式。你需要用FFmpeg的sws_scale将RGBA数据转换为YUV420P,再传给编码器。
修复代码示例:
// 初始化像素转换上下文 struct SwsContext* sws_ctx = sws_getContext( width, height, AV_PIX_FMT_RGBA, width, height, AV_PIX_FMT_YUV420P, SWS_BILINEAR, NULL, NULL, NULL ); // 准备YUV420P格式的AVFrame AVFrame* yuv_frame = av_frame_alloc(); yuv_frame->format = AV_PIX_FMT_YUV420P; yuv_frame->width = width; yuv_frame->height = height; av_frame_get_buffer(yuv_frame, 0); // 转换RGBA到YUV420P sws_scale(sws_ctx, (const uint8_t* const*)&sdl_pixels, &sdl_pitch, 0, height, yuv_frame->data, yuv_frame->linesize); // 之后使用yuv_frame传给编码器
3. 验证FFmpeg帧的参数正确性
- 确保AVFrame的
width和height与SDL纹理/窗口的实际尺寸完全一致,不要出现宽高颠倒的情况。 - 检查AVCodecContext的
width、height、pix_fmt参数是否与AVFrame匹配,编码器初始化时必须指定正确的像素格式(比如AV_PIX_FMT_YUV420P)。
4. 排查帧数据的写入顺序
确认你是按从上到下的顺序写入帧数据,部分渲染API可能返回的是倒序像素(比如从底部行开始),如果SDL返回的是倒序,需要反转行的拷贝顺序:
// 倒序拷贝(如果SDL像素是底部优先) for (int y = 0; y < height; y++) { memcpy(frame->data[0] + (height - 1 - y) * frame->linesize[0], sdl_pixels + y * sdl_pitch, width * 4); }
内容的提问来源于stack exchange,提问作者Riptide
相关产品推荐
相关产品推荐

