前言
最近在开发中发现一部分m3u8文件在播放时无法快进,并且在播放时播放一段时间后时间会重置为0,经过一通分析后发现这部分m3u8文件中有#EXT-X-DISCONTINUITY这个标签,ffmpeg目前对这个标签是不支持的,ijkplayer是支持的,但是ijkplayer没有添加带这个标签的视频seek的处理,会造成当前的分片视频可以seek,但是直接跳到后面的分片视频会无法seek,#EXT-X-DISCONTINUITY标签后面的视频的pts和标签之前的视频是不连续的,而ffmpeg在seek时,会去将要seek的timestamp与当前包的pts区间进行对比,来查看查找的是否是当前包,但由于pts不连续的问题,会导致seek的timestamp总是大于包的pts区间,所以到会导致一直卡着,无法播放,后面在ijkplayer的issue中找到处理方法。
处理过程
首先在hls.c文件里添加一个函数,用于查找当前packet之前的视频的总时长,用于得出正确的pts:
static int find_timestamp_in_seq_no( struct playlist *pls,int64_t *timestamp, int seq_no)
{
int i;
*timestamp=0;
for (i = 0; i < seq_no; i++) {
*timestamp += pls->segments[i]->duration ;
}
return 0;
}
修改hls_read_packet函数
1.声明变量
int64_t timestamp = AV_NOPTS_VALUE;
2.调用find_timestamp_in_seq_no函数
for (i = 0; i < c->n_playlists; i++) {
struct playlist *pls = c->playlists[i];
find_timestamp_in_seq_no(pls,×tamp,pls->cur_seq_no);//add
/* Make sure we've got one buffered packet from each open playlist
* stream */
if (pls->needed && !pls->pkt.data) {
....
}
3.最后在计算seek的timestamp是否在当前packet的区间的代码上加上这个时长
ts_diff = timestamp + av_rescale_rnd(pls->pkt.dts, AV_TIME_BASE,
tb.den, AV_ROUND_DOWN) -
pls->seek_timestamp;//edit
if (ts_diff >= 0 && (pls->seek_flags & AVSEEK_FLAG_ANY ||
pls->pkt.flags & AV_PKT_FLAG_KEY)) {
pls->seek_timestamp = AV_NOPTS_VALUE;
break;
}
结语
目前测试是没问题的,但是在issue中有人反馈出现崩溃情况,后续会跟进。