C++ FFmpeg编码MP4流时帧率与码率异常问题求助
问题根源与修复方案
你的问题核心是时间戳处理错误和流参数配置不完整,导致播放器无法正确解析视频的时长与帧率。以下是具体修复步骤:
1. 修复Packet时间戳转换
FFmpeg中,编码器输出的Packet的PTS/DTS基于codec_context->time_base,但写入容器时需要转换为对应AVStream的time_base。你的代码直接写入Packet未做转换,导致时间戳异常,播放器计算出错误的帧率和时长。
修改编码循环中的Packet处理逻辑:
ret = avcodec_receive_packet(codec_context, pkt); if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) { break; } pkt->stream_index = video_stream->index; // 新增:将PTS/DTS转换为流的时间基准 av_packet_rescale_ts(pkt, codec_context->time_base, video_stream->time_base); av_interleaved_write_frame(output_format_context, pkt); av_packet_unref(pkt);
2. 完整配置流的帧率参数
你注释掉了流的r_frame_rate和avg_frame_rate设置,导致容器无法正确识别视频帧率。恢复这两个参数配置:
AVStream* ffmpeg_example::create_stream(AVFormatContext*& fctx, AVCodecContext*& codec_ctx) { AVStream* stream = avformat_new_stream(fctx, nullptr); avcodec_parameters_from_context(stream->codecpar, codec_ctx); stream->time_base = codec_ctx->time_base; // 恢复帧率参数配置 stream->r_frame_rate = codec_ctx->framerate; stream->avg_frame_rate = stream->r_frame_rate; return stream; }
3. 设置合理码率
你当前将bitrate设为0,编码器会使用默认超高码率,导致文件过大且播放异常。在set_codec_params中设置合理码率(例如5Mbps):
void ffmpeg_example::set_codec_params(AVFormatContext*& fctx, AVCodecContext*& codec_ctx, double width, double height, int fps, int bitrate) { std::cout << "encoding video for width:" << width << ", height:" << height << ", fps:" << fps << ", bitrate:" << bitrate << std::endl; codec_ctx->codec_id = fctx->oformat->video_codec; codec_ctx->codec_type = AVMEDIA_TYPE_VIDEO; codec_ctx->width = width; codec_ctx->height = height; codec_ctx->gop_size = 12; codec_ctx->pix_fmt = COMMON_AV_FRAME_FORMAT; codec_ctx->framerate = AVRational{ fps, 1 }; codec_ctx->time_base = AVRational{ 1, fps }; // 设置默认码率为5Mbps,若传入有效值则使用传入值 codec_ctx->bit_rate = bitrate > 0 ? bitrate : 5000000; if (fctx->oformat->flags & AVFMT_GLOBALHEADER) { codec_ctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER; } }
4. 同步编码器打开后的流参数
部分编码器(如MPEG4)在打开后会修改codec_context的time_base,因此需要将创建流的逻辑移到编码器打开之后,确保参数同步:
修改initFfmpegcontext函数的代码顺序:
// Open the codec ret = avcodec_open2(codec_context, encoder, nullptr); if (ret < 0) { std::cout << "Could not open encoder with context." << std::endl; return -1; } // 移到编码器打开后创建流,保证参数同步 // Create a new video stream video_stream = create_stream(output_format_context, codec_context); if (!video_stream) { std::cout << "Could not create stream." << std::endl; return -1; }
验证修复结果
修改后重新生成视频,使用ffmpeg -i output.mp4查看信息,应显示:
- 时长接近00:00:04.00
- 帧率为30fps
- 码率接近设置的数值
内容的提问来源于stack exchange,提问作者elmomoJacky
相关产品推荐
相关产品推荐

