使用libavformat编码FLV时,如何提前写入尺寸信息以支持边编码边剪辑
解决FLV边编码边剪辑时的尺寸识别问题
你遇到的问题根源很明确:在边编码边写入FLV文件时,默认的libavformat FLV muxer不会在文件头部的MetaData Tag中提前写入视频宽高信息,导致ffmpeg读取未完成的文件时,无法从头部获取关键的尺寸参数。而编码完成后,muxer会自动补全这些元数据,所以此时剪辑操作就能正常执行。
下面是针对你的代码的具体修改方案,确保宽高信息被提前写入FLV头部,完美支持边编码边剪辑:
1. 切换到推荐的codecpar字段(替代废弃的codec字段)
旧版代码中使用的video_stream->codec已经被官方标记为废弃,改用codecpar来设置编码参数,能确保元数据被正确传递给muxer,避免兼容性问题:
// 替换原有的video_stream->codec相关设置 video_stream->codecpar->codec_id = AV_CODEC_ID_H264; video_stream->codecpar->codec_type = AVMEDIA_TYPE_VIDEO; video_stream->codecpar->bit_rate = bitrate; video_stream->codecpar->width = 640; video_stream->codecpar->height = 480; video_stream->codecpar->format = AV_PIX_FMT_YUV420P; // 设置时间基和帧率,让元数据更完整 video_stream->time_base = (AVRational){1, 25}; video_stream->avg_frame_rate = (AVRational){25, 1};
2. 强制写入FLV头部的MetaData Tag
在调用avformat_write_header之前,手动添加包含宽高的元数据,让FLV muxer把这些信息提前写入文件头部:
// 创建元数据字典并设置核心参数 AVDictionary *metadata = NULL; av_dict_set(&metadata, "width", "640", 0); av_dict_set(&metadata, "height", "480", 0); // 可选:额外添加帧率信息,让元数据更完整 av_dict_set(&metadata, "framerate", "25", 0); // 将元数据关联到输出上下文 avformat_set_metadata(container_format_context, metadata); // 释放字典避免内存泄漏 av_dict_free(&metadata);
3. 确保编码器全局头与extradata同步
打开编码器后,把编码器上下文的extradata(包含H264的SPS/PPS关键信息)同步到stream的codecpar中,这能让FLV muxer在头部写入正确的编码配置:
// 打开编码器之后添加这行代码 avcodec_parameters_from_context(video_stream->codecpar, avcodec_context);
4. 修改后的完整关键代码片段
整合以上修改后的核心代码如下,你可以直接替换原有的对应部分:
AVOutputFormat *container_format; AVFormatContext *container_format_context; AVStream *video_stream; char *path = "/home/user/temp.flv"; // 分配输出媒体上下文 avformat_alloc_output_context2(&container_format_context, NULL, NULL, path); container_format = container_format_context->oformat; // 查找libx264编码器 AVCodec* codec = avcodec_find_encoder_by_name("libx264"); // 创建视频流 video_stream = avformat_new_stream(container_format_context, codec); video_stream->id = container_format_context->nb_streams - 1; // 使用codecpar设置视频参数(替代废弃的codec字段) video_stream->codecpar->codec_id = AV_CODEC_ID_H264; video_stream->codecpar->codec_type = AVMEDIA_TYPE_VIDEO; video_stream->codecpar->bit_rate = bitrate; video_stream->codecpar->width = 640; video_stream->codecpar->height = 480; video_stream->codecpar->format = AV_PIX_FMT_YUV420P; video_stream->time_base = (AVRational){1, 25}; video_stream->avg_frame_rate = (AVRational){25, 1}; // 初始化编码器上下文 AVCodecContext *avcodec_context = avcodec_alloc_context3(codec); avcodec_parameters_to_context(avcodec_context, video_stream->codecpar); // 设置全局头标志(FLV容器必须) if (container_format_context->oformat->flags & AVFMT_GLOBALHEADER) { avcodec_context->flags |= AV_CODEC_FLAG_GLOBAL_HEADER; } // 补充编码器的其他配置 avcodec_context->gop_size = 10; avcodec_context->qmax = 31; avcodec_context->qmin = 2; avcodec_context->pix_fmt = AV_PIX_FMT_YUV420P; avcodec_context->time_base = (AVRational){1, 25}; // 打开编码器 int ret = avcodec_open2(avcodec_context, codec, NULL); if (ret < 0) { // 这里添加你的错误处理逻辑 } // 同步编码器上下文到stream的codecpar avcodec_parameters_from_context(video_stream->codecpar, avcodec_context); // 添加FLV头部元数据 AVDictionary *metadata = NULL; av_dict_set(&metadata, "width", "640", 0); av_dict_set(&metadata, "height", "480", 0); av_dict_set(&metadata, "framerate", "25", 0); avformat_set_metadata(container_format_context, metadata); av_dict_free(&metadata); // 打开输出文件 if (!(container_format->flags & AVFMT_NOFILE)) { ret = avio_open(&container_format_context->pb, path, AVIO_FLAG_WRITE); if (ret < 0) { // 这里添加你的错误处理逻辑 } } // 写入文件头 ret = avformat_write_header(container_format_context, NULL); if (ret < 0) { // 这里添加你的错误处理逻辑 } // 后续的帧编码和写入逻辑...
为什么这样修改有效?
- 使用
codecpar确保参数被muxer正确识别,避免废弃字段带来的兼容性问题 - 手动添加的元数据会被FLV muxer写入到文件开头的MetaData Tag中,ffmpeg读取未完成的文件时能直接从这里获取宽高
- 同步编码器的extradata确保H264的SPS/PPS被写入FLV头部,让解码器能正确解析视频流
现在你可以边编码边执行ffmpeg剪辑命令,ffmpeg就能从FLV头部获取到尺寸参数,不会再出现报错了。
内容的提问来源于stack exchange,提问作者seanr8
相关产品推荐
相关产品推荐

