正确设置avframe->pts并调用avcodec_send_frame()+avcodec_receive_packet()循环推帧可避免丢帧:需按avstream->time_base递增设置pts,用av_rescale_q计算;禁用手动设pict_type;libx264启用ultrafast preset、crf=20、tune=stillimage;rgb转yuv时指定src_colorspace=avcol_spc_rgb、dst_colorspace=avcol_spc_bt709;编码结束必须调avcodec_send_frame(null)清空缓冲。

ffmpeg_encode_images_to_h264 函数怎么写才不丢帧
直接用 avcodec_send_frame() + avcodec_receive_packet() 循环推帧,但常见错误是没控制好 AVFrame->pts。FFmpeg 的 H.264 编码器(如 libx264)依赖 PTS 计算 GOP 结构和帧间依赖,若所有帧 PTS 设为 0 或乱序,会导致编码器内部缓冲异常、B 帧错位、甚至只输出 I 帧或卡死。
正确做法是按时间基(AVStream->time_base)递增设置 PTS:
- 先调用
avformat_write_header()获取输出流的time_base - 每送一帧,设
frame->pts = frame_index * time_base_den / fps / time_base_num(注意整数除法溢出),更稳妥用av_rescale_q(frame_index, (AVRational){1, fps}, stream->time_base) - 确保
frame->pict_type为AV_PICTURE_TYPE_NONE(让编码器自动决定),别强行设 I/B/P
libx264 参数调哪些能兼顾速度和质量
默认参数下 libx264 会启用大量耗时优化(如 RD、psy-trellis),对批量图片编码纯属浪费。关键改三项:
-
"preset"设为"ultrafast"或"superfast":跳过运动估计的多级搜索,帧内预测也简化 -
"crf"控制质量,18–23 是合理区间;低于 17 文件体积暴涨,高于 24 视觉质量明显下降 - 必须加
"tune"="stillimage":启用针对静态内容的量化偏置和 CABAC 模式优化,比默认"film"或"zerolatency"更合适
示例设置:
av_dict_set(&opt, "preset", "ultrafast", 0); av_dict_set(&opt, "crf", "20", 0); av_dict_set(&opt, "tune", "stillimage", 0);
RGB 图片转 YUV 怎么避免颜色偏移
多数图片是 RGB24,而 H.264 编码器只接受 AV_PIX_FMT_YUV420P。直接用 sws_getContext() 转换时,若没指定色彩空间参数,sws_scale() 默认按 ITU-R BT.601 转换,但 JPEG/PNG 常用 sRGB —— 这会导致绿色偏黄、肤色发灰。
- 创建 sws 上下文时显式传参:
src_colorspace = AVCOL_SPC_RGB,dst_colorspace = AVCOL_SPC_BT709 - 源帧
AVFrame->colorspace和color_range也要同步设(AVCOL_RANGE_JPEG对应 full range) - 若输入图是 PNG(带 alpha),先用
sws_convertPalette4toN()或手动丢弃 alpha 通道,否则sws_scale()可能崩溃
为什么 av_interleaved_write_frame() 总返回 -22(EINVAL)
这个错误几乎全是时间戳问题:PTS 或 DTS 不单调递增,或超出 AVStream->duration 范围。尤其当最后一帧 PTS 算错,导致 packet->pts >= stream->duration * stream->time_base.den / stream->time_base.num 时必触发。
- 写帧前务必校验:
if (packet->pts != AV_NOPTS_VALUE && packet->dts != AV_NOPTS_VALUE && packet->pts dts)→ 跳过或重设 DTS - 编码结束时,必须调用
avcodec_send_frame(NULL)清空编码器剩余帧,再循环avcodec_receive_packet()直到返回AVERROR(EAGAIN),否则最后几帧永远不输出 - 别忘了在
av_write_trailer()前调用avio_flush(),否则 MP4 封装可能损坏
多图编码真正难的不是 API 调用链,而是时间戳和色彩空间这两处隐性依赖 —— 它们不出错时不显眼,一错就全盘静音或花屏,且日志里几乎不报具体原因。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











