ffmpeg使用protocol concat合并ts流时,如何精确计算时间戳并实现音画同步?

2026-04-18 02:133阅读0评论SEO资讯
  • 内容介绍
  • 文章标签
  • 相关推荐

本文共计1298个文字,预计阅读时间需要6分钟。

ffmpeg使用protocol concat合并ts流时,如何精确计算时间戳并实现音画同步?

使用ffmpeg的protocol concat功能进行ts流合并,涉及时间戳计算及音视频同步的方法浅析。

通过ffmpeg的protocol concat功能,可以将多个ts视频流合并为一个,同时计算时间戳并进行音视频同步。以下是一个简单的操作步骤:

1. 准备ts文件列表,使用以下格式创建一个txt文件(例如,input.txt):

file 'stream1.ts'file 'stream2.ts'file 'stream3.ts'

2. 使用ffmpeg命令进行合并:

ffmpeg -f concat -safe 0 -i input.txt -c copy output.ts

这里,-f concat指定输入格式为concat,-safe 0允许合并包含相同文件名的文件,-i指定输入文件列表,-c copy使用相同的编码器复制音视频流。

3. 时间戳计算及音视频同步:

- 在ts文件中,每个视频帧都有一个时间戳,ffmpeg会根据这些时间戳自动进行音视频同步。- 如果需要手动调整时间戳,可以使用ffmpeg的setts选项。例如,将时间戳调整为0:

ffmpeg -i stream1.ts -setts 0:0 output.ts

4. 音视频同步测试:

为了测试音视频同步,可以使用以下命令:

ffmpeg -i output.ts -vf vflip -af aresample=0:0:44100 -c:v libx264 -c:a aac -b:v 5000k -b:a 128k -y output.mp4

这里,-vf vflip用于垂直翻转视频,-af aresample=0:0:44100调整音频采样率,-c:v和-c:a指定视频和音频编码器,-b:v和-b:a设置视频和音频码率。

通过以上步骤,可以使用ffmpeg的protocol concat功能进行ts流合并,并进行时间戳计算及音视频同步。

ffmpeg protocol concat 进行ts流合并视频的时间戳计算及音画同步方式一点浅析

目录
  • ffmpeg protocol concat 进行ts流合并视频的时间戳计算及音画同步方式一点浅析
    • audio 10 video 5s 衔接测试
    • audio 5s video 10s 接着音频短的片尾斜街一段
    • 小结


ffmpeg 有三种常见的视频合并方式: demuxerprotocolfilter

这里有介绍它的使用 :

ffmpeg使用protocol concat合并ts流时,如何精确计算时间戳并实现音画同步?

trac.ffmpeg.org/wiki/Concatenate#demuxer

本文主要介绍ts流合并视频时候合并后视频的pkt是如何计算的,音画是怎么同步的。


这种方式 是以复制pkt的方式进行的,不需要解码,不像fitler方式合并没有编码损失。
其基本命令如下 :

ffmpeg -i input1.mp4 -c copy -bsf:v h264_mp4toannexb -f mpegts intermediate1.ts ffmpeg -i input2.mp4 -c copy -bsf:v h264_mp4toannexb -f mpegts intermediate2.ts ffmpeg -i "concat:intermediate1.ts|intermediate2.ts" -c copy -bsf:a aac_adtstoasc output.mp4

libavformat/concat.c中会处理 -i concat:"...." 打开所有输入文件,

输出的 pkt 的 dts 和 pts 为 所有输入pkt的 dts 、 pts + 上一个 ts_offset
第一个片段的ts_offset 应该是 0 - 第一个片段的起始时间
第二个片段的ts_offset 是第一个片段中 最长流的 pts + 上一段的ts_ofsset
依此类推后面的。

main->tanscode()->transcoder_step()->process_input(): 中的这段代码 即处理了 一个片段末尾新ts_offset的计算:

if ((ist->dec_ctx->codec_type == AVMEDIA_TYPE_VIDEO || ist->dec_ctx->codec_type == AVMEDIA_TYPE_AUDIO) && pkt_dts != AV_NOPTS_VALUE && ist->next_dts != AV_NOPTS_VALUE && !disable_discontinuity_correction) { int64_t delta = pkt_dts - ist->next_dts; if (is->iformat->flags & AVFMT_TS_DISCONT) { if (delta < -1LL*dts_delta_threshold*AV_TIME_BASE || delta > 1LL*dts_delta_threshold*AV_TIME_BASE || pkt_dts + AV_TIME_BASE/10 < FFMAX(ist->pts, ist->dts)) { ifile->ts_offset -= delta; av_log(NULL, AV_LOG_DEBUG, "timestamp discontinuity for stream #%d:%d " "(id=%d, type=%s): %"PRId64", new offset= %"PRId64"\n", ist->file_index, ist->st->index, ist->st->id, av_get_media_type_string(ist->dec_ctx->codec_type), delta, ifile->ts_offset); pkt.dts -= av_rescale_q(delta, AV_TIME_BASE_Q, ist->st->time_base); if (pkt.pts != AV_NOPTS_VALUE) pkt.pts -= av_rescale_q(delta, AV_TIME_BASE_Q, ist->st->time_base); }

因此 其合并 方式 应该如下图所示 :

如是,生成两个测试源,验证一下 :

audio 10 video 5s 衔接测试

ffprobe -i c.mp4 -select_streams v:0 -show_packets -of json |grep pts

可以看到 pts 在 5s 处 会有一段 跳变 而 audio 在5-10s是连续的 ->

"pts_time": "4.776667", "pts": 432900, "pts_time": "4.810000", "pts": 435900, "pts_time": "4.843333", "pts": 438900, "pts_time": "4.876667", "pts": 441900, "pts_time": "4.910000", "pts": 444900, "pts_time": "4.943333", "pts": 447900, "pts_time": "4.976667", "pts": 450900, "pts_time": "5.010000", "pts": 904341, "pts_time": "10.048233", "pts": 907341, "pts_time": "10.081567", "pts": 910341, "pts_time": "10.114900", "pts": 913341, "pts_time": "10.148233", "pts": 916341, "pts_time": "10.181567",

打开 deug_ts 在ffmeg日志处 可以看到 ts 合并方式 下一段新的 偏移 取得是audio 的长度。

audio 5s video 10s 接着音频短的片尾斜街一段

ffprobe -i c.mp4 -select_streams a:0 -show_packets -of json |grep pts

这次我们检查音频流,可以看到音频在断点处 时间戳是有跳变的。

"pts": 657792, "pts_time": "14.915918", "pts": 658944, "pts_time": "14.942041", "pts": 660096, "pts_time": "14.968163", "pts": 661248, "pts_time": "14.994286", "pts": 882216, "pts_time": "20.004898", "pts": 883368, "pts_time": "20.031020", "pts": 884520, "pts_time": "20.057143"

因此 基本符合开头猜想的逻辑:

小结

这种合并方式的优点是 能够 不打乱 原来每段的 音视频时间戳 进而确保音画同步,

缺点是 在音画 duration 差别过大的片段后面进行衔接 会留出一段 音或视频的空隙。 这种 空隙 播放器可能会卡最后一帧处理,不过建议是 转码处理是自行补齐静音 或视频 最后一帧。

再或者 尝试使用 ffmpeg -shortest 选项 截掉 音画 偏长的那一段内容 ,来进行 concat。

作者 —— 靑い空゛

出处:www.cnblogs.com/ailumiyana/

除特别注明外,本站所有文章均为靑い空゛原创,欢迎转载分享,但请注明出处。

本文共计1298个文字,预计阅读时间需要6分钟。

ffmpeg使用protocol concat合并ts流时,如何精确计算时间戳并实现音画同步?

使用ffmpeg的protocol concat功能进行ts流合并,涉及时间戳计算及音视频同步的方法浅析。

通过ffmpeg的protocol concat功能,可以将多个ts视频流合并为一个,同时计算时间戳并进行音视频同步。以下是一个简单的操作步骤:

1. 准备ts文件列表,使用以下格式创建一个txt文件(例如,input.txt):

file 'stream1.ts'file 'stream2.ts'file 'stream3.ts'

2. 使用ffmpeg命令进行合并:

ffmpeg -f concat -safe 0 -i input.txt -c copy output.ts

这里,-f concat指定输入格式为concat,-safe 0允许合并包含相同文件名的文件,-i指定输入文件列表,-c copy使用相同的编码器复制音视频流。

3. 时间戳计算及音视频同步:

- 在ts文件中,每个视频帧都有一个时间戳,ffmpeg会根据这些时间戳自动进行音视频同步。- 如果需要手动调整时间戳,可以使用ffmpeg的setts选项。例如,将时间戳调整为0:

ffmpeg -i stream1.ts -setts 0:0 output.ts

4. 音视频同步测试:

为了测试音视频同步,可以使用以下命令:

ffmpeg -i output.ts -vf vflip -af aresample=0:0:44100 -c:v libx264 -c:a aac -b:v 5000k -b:a 128k -y output.mp4

这里,-vf vflip用于垂直翻转视频,-af aresample=0:0:44100调整音频采样率,-c:v和-c:a指定视频和音频编码器,-b:v和-b:a设置视频和音频码率。

通过以上步骤,可以使用ffmpeg的protocol concat功能进行ts流合并,并进行时间戳计算及音视频同步。

ffmpeg protocol concat 进行ts流合并视频的时间戳计算及音画同步方式一点浅析

目录
  • ffmpeg protocol concat 进行ts流合并视频的时间戳计算及音画同步方式一点浅析
    • audio 10 video 5s 衔接测试
    • audio 5s video 10s 接着音频短的片尾斜街一段
    • 小结


ffmpeg 有三种常见的视频合并方式: demuxerprotocolfilter

这里有介绍它的使用 :

ffmpeg使用protocol concat合并ts流时,如何精确计算时间戳并实现音画同步?

trac.ffmpeg.org/wiki/Concatenate#demuxer

本文主要介绍ts流合并视频时候合并后视频的pkt是如何计算的,音画是怎么同步的。


这种方式 是以复制pkt的方式进行的,不需要解码,不像fitler方式合并没有编码损失。
其基本命令如下 :

ffmpeg -i input1.mp4 -c copy -bsf:v h264_mp4toannexb -f mpegts intermediate1.ts ffmpeg -i input2.mp4 -c copy -bsf:v h264_mp4toannexb -f mpegts intermediate2.ts ffmpeg -i "concat:intermediate1.ts|intermediate2.ts" -c copy -bsf:a aac_adtstoasc output.mp4

libavformat/concat.c中会处理 -i concat:"...." 打开所有输入文件,

输出的 pkt 的 dts 和 pts 为 所有输入pkt的 dts 、 pts + 上一个 ts_offset
第一个片段的ts_offset 应该是 0 - 第一个片段的起始时间
第二个片段的ts_offset 是第一个片段中 最长流的 pts + 上一段的ts_ofsset
依此类推后面的。

main->tanscode()->transcoder_step()->process_input(): 中的这段代码 即处理了 一个片段末尾新ts_offset的计算:

if ((ist->dec_ctx->codec_type == AVMEDIA_TYPE_VIDEO || ist->dec_ctx->codec_type == AVMEDIA_TYPE_AUDIO) && pkt_dts != AV_NOPTS_VALUE && ist->next_dts != AV_NOPTS_VALUE && !disable_discontinuity_correction) { int64_t delta = pkt_dts - ist->next_dts; if (is->iformat->flags & AVFMT_TS_DISCONT) { if (delta < -1LL*dts_delta_threshold*AV_TIME_BASE || delta > 1LL*dts_delta_threshold*AV_TIME_BASE || pkt_dts + AV_TIME_BASE/10 < FFMAX(ist->pts, ist->dts)) { ifile->ts_offset -= delta; av_log(NULL, AV_LOG_DEBUG, "timestamp discontinuity for stream #%d:%d " "(id=%d, type=%s): %"PRId64", new offset= %"PRId64"\n", ist->file_index, ist->st->index, ist->st->id, av_get_media_type_string(ist->dec_ctx->codec_type), delta, ifile->ts_offset); pkt.dts -= av_rescale_q(delta, AV_TIME_BASE_Q, ist->st->time_base); if (pkt.pts != AV_NOPTS_VALUE) pkt.pts -= av_rescale_q(delta, AV_TIME_BASE_Q, ist->st->time_base); }

因此 其合并 方式 应该如下图所示 :

如是,生成两个测试源,验证一下 :

audio 10 video 5s 衔接测试

ffprobe -i c.mp4 -select_streams v:0 -show_packets -of json |grep pts

可以看到 pts 在 5s 处 会有一段 跳变 而 audio 在5-10s是连续的 ->

"pts_time": "4.776667", "pts": 432900, "pts_time": "4.810000", "pts": 435900, "pts_time": "4.843333", "pts": 438900, "pts_time": "4.876667", "pts": 441900, "pts_time": "4.910000", "pts": 444900, "pts_time": "4.943333", "pts": 447900, "pts_time": "4.976667", "pts": 450900, "pts_time": "5.010000", "pts": 904341, "pts_time": "10.048233", "pts": 907341, "pts_time": "10.081567", "pts": 910341, "pts_time": "10.114900", "pts": 913341, "pts_time": "10.148233", "pts": 916341, "pts_time": "10.181567",

打开 deug_ts 在ffmeg日志处 可以看到 ts 合并方式 下一段新的 偏移 取得是audio 的长度。

audio 5s video 10s 接着音频短的片尾斜街一段

ffprobe -i c.mp4 -select_streams a:0 -show_packets -of json |grep pts

这次我们检查音频流,可以看到音频在断点处 时间戳是有跳变的。

"pts": 657792, "pts_time": "14.915918", "pts": 658944, "pts_time": "14.942041", "pts": 660096, "pts_time": "14.968163", "pts": 661248, "pts_time": "14.994286", "pts": 882216, "pts_time": "20.004898", "pts": 883368, "pts_time": "20.031020", "pts": 884520, "pts_time": "20.057143"

因此 基本符合开头猜想的逻辑:

小结

这种合并方式的优点是 能够 不打乱 原来每段的 音视频时间戳 进而确保音画同步,

缺点是 在音画 duration 差别过大的片段后面进行衔接 会留出一段 音或视频的空隙。 这种 空隙 播放器可能会卡最后一帧处理,不过建议是 转码处理是自行补齐静音 或视频 最后一帧。

再或者 尝试使用 ffmpeg -shortest 选项 截掉 音画 偏长的那一段内容 ,来进行 concat。

作者 —— 靑い空゛

出处:www.cnblogs.com/ailumiyana/

除特别注明外,本站所有文章均为靑い空゛原创,欢迎转载分享,但请注明出处。