长达26个小时的KPL直播.Seek到中间偏后的时候会卡死不动.但是前面1-2个小时可以Seek.
大家有兴趣可以先看看Mac上终端调试FFmpeg任意版本源码的最佳实践
这个问题刚开始跟踪的时候,首先想到的是是不是视频源的问题.是用vlc和flv去尝试.奇怪的是vlc也不支持.但是ffmpeg支持.
此时我们来跟踪问题,发现到了JitterBuffer层之后无法往解码层送数据
// 正在 seek
if (packet->pts - packet->start_pts < seek_to_timestamp_) {
LOG_DEBUG("OnAudioPacketDemuxed, drop audio packet : %lld, start : %lld, seek time : %lld", packet->pts, packet->start_pts, seek_to_timestamp_);
return true;
}
两者相减为负数,我们要去seek的pts不对.到底为什么不对呢?
因为此流地址是
http://xxx/playlist_eof.m3u8
我们下载后看里面ts文件可知
流的第一个ts分片:
http://xxx_1.ts?start=0&end=2475019&type=mpegts
pts=8171962796中间的某一个:
http://xxx_525.ts?start=24645672&end=26180503&type=mpegts
pts=4399514004最后一个:
http://xxx_1302.ts?start=24598860&end=25023363&type=mpegts
pts=6771267804
现在通过ffmpeg工具查看ts分片后得知:
ffplay http://xxx_1.ts\?start\=0\&end\=2475019\&type\=mpegts
可正常播放.
然后用命令行看一下pts.
ffprobe -show_packets http://xxx_1.ts\?start\=0\&end\=2475019\&type\=mpegts或者ffprobe -of xml -show_streams http://xxx_1.ts\?start\=0\&end\=2475019\&type\=mpegts
可以看到start_pts是8171962796
看起来也没有pts也和上面和代码解复用之后拿到的pts是一样的.那么就是说解析到的pts是对的.那么为什么会出现pts先逐渐增大,然后变小后再增大的问题呢?
起始值一样.但是我seek拖到中途之后pts竞然没有变小.通过
static int64_t wrap_timestamp(const AVStream *st, int64_t timestamp)
{
if (st->pts_wrap_behavior != AV_PTS_WRAP_IGNORE &&
st->pts_wrap_reference != AV_NOPTS_VALUE && timestamp != AV_NOPTS_VALUE) {
if (st->pts_wrap_behavior == AV_PTS_WRAP_ADD_OFFSET &&
timestamp < st->pts_wrap_reference)
return timestamp + (1ULL << st->pts_wrap_bits);
else if (st->pts_wrap_behavior == AV_PTS_WRAP_SUB_OFFSET &&
timestamp >= st->pts_wrap_reference)
return timestamp - (1ULL << st->pts_wrap_bits);
}
return timestamp;
}
打断点可知,这里对pts如果小区
对时间戳循环到头的处理:
ts流中的三个时间戳,pts(33bit),dts(33bit),pcr(42bit)
当时间戳增加到语法无法容纳时,产生时间戳循环,时间线开始变小,循环点计算方式是:将要设置的值减去时间戳最大值,将差值写入语法结构。
编码器设置时钟,以及解码器自己的系统时钟在达到最大值后,都根据此方式计算,不会产生时钟的不连续。
现在加上这一段即可
//ts流中的时间戳,pts(33bit),dts(33bit)
//当时间戳增加到语法无法容纳时,产生时间戳循环,时间线开始变小,循环点计算方式是:将要设置的值减去时间戳最大值,将差值写入语法结构。
int64_t TsParser::getVideoRevisedPts(int64_t pts){
if(video_packet_){
int64_t startPts_Real = video_start_pts_*kTimeBase; //转换成ms之前的从流中获取的时间戳
if(pts < startPts_Real){
pts += kMaxPtsFrame;
}
}
return pts;
}int64_t TsParser::getAudioRevisedPts(int64_t pts){
if(audio_packet_){
int64_t startPts_Real = audio_start_pts_*kTimeBase; //转换成ms之前的从流中获取的时间戳
if(pts < startPts_Real){
pts += kMaxPtsFrame;
}
}
return pts;
}
关于更多的格式的具体细节可以参考30分钟学会FLV和HLS
1.总结TS中的pcr、dts、pts问题