FFmpeg-合并两个视频文件
发布时间:
使用 FFmpeg 合并两个视频文件时区别AVFormatContext->duration和AVStream->duration
今天使用 FFmpeg 编写C++代码合并两个视频文件。整体流程如下:
- 打开两个输入视频文件
- 创建输出视频文件
- 对于第一个视频文件,直接写入输出视频文件
- 对于第二个视频文件,要修改视频流的时间戳,再写入输出视频文件
- 关闭所有文件
- 释放资源
上面过程中,修改第二个视频流的时间戳逻辑如下:
// 获取第一个视频的时常,单位微秒
int64_t begin_sec = vec_src_fmt_ctx[0]->duration;
// 计算第一个视频末尾的时间基,作为第二个视频开始的时间基
int64_t begin_video_pts = begin_sec / (1000.0 * 1000.0 * av_q2d(vec_src_video_stream[0]->time_base));
// 解码得到frame
// ...
// 将第二个视频的时间戳的时间基转换为输出视频的时间基(这里和第一个视频时间基一样)
int64_t pts = av_rescale_q(frame->pts, vec_src_video_stream[1]->time_base, vec_src_video_stream[0]->time_base);
// 转换后时间基再加上增量
frame->pts = pts + begin_video_pts;
在开发中将vec_src_fmt_ctx[0]->duration
错误写出vec_src_video_stream[0]->duration
,导致第二个视频的时间基错误,最终导致合并后的视频文件无法播放。这个错误在调试时很难发现,因为 FFmpeg 的日志输出没有提示错误信息。经过仔细检查代码,才发现了这个问题。
下面总结一下上面两个duration
的区别(问的chatGPT):
AVFormatContext->duration
vs AVStream->duration
对比
特性 | AVFormatContext->duration | AVStream->duration |
---|---|---|
作用范围 | 整个媒体文件 | 单个流(如视频、音频、字幕) |
单位 | 固定为微秒(µs,AV_TIME_BASE ) | 流的时间基(time_base ,可变单位) |
计算公式 | duration / AV_TIME_BASE → 秒 | duration * av_q2d(time_base) → 秒 |
数据来源 | 容器层(文件头信息) | 流层(帧数据统计) |
可靠性 | 容器未存储时可能不准确 | 通常更精确(依赖实际帧数据) |
典型场景 | 显示文件总时长 | 音视频同步、流剪切 |
特殊值 | AV_NOPTS_VALUE (未定义) | AV_NOPTS_VALUE (未定义) |
替代计算 | 需遍历所有包估算 | 可通过nb_frames * avg_frame_rate 计算 |
单位换算示例代码
// 文件总时长(秒)
double fmt_duration = fmt_ctx->duration / (double)AV_TIME_BASE;
// 视频流时长(秒)
double stream_duration = video_stream->duration * av_q2d(video_stream->time_base);
本次代码可以在GitHub上找到,欢迎大家交流~ 如果有问题可以在下面留言~