2019独角兽企业重金招聘Python工程师标准>>>
背景: 在项目应用中,需要实现节目单程序重启后,能够准确定位到节目单时间轴的正确位置。例如,虚拟频道11点开始放11:00-12:00的新闻(点播文件),在11:20时断开2分钟,11:22是应该播放点播文件里第22分钟时的新闻,而不是从头播放或接着上次断开的地方播。
为实现这一需求,有两个要点:
1.确定正确的时间偏移;
2.设置ffmpeg将流偏移到正确的起始位置。
对于要点1,可以根据节目单的时间和当前时间计算得到。(当前时间-小于当前时间的节目开始播放时间)
对于要点2, 通过av_seek_frame()实现。
av_seek_frame()的定义如下:
int av_seek_frame(AVFormatContext *s, int stream_index, int64_t timestamp, int flags){}
参数1: s为容器内容;
参数2: stream_index 流索引
参数3: timestamp将要定位处的时间戳
参数4: flags功能flag
参数1没啥可说的了,流的上下文指针。
参数2是流索引,指定某个流。当然也可以不指定某个流(设置为-1),函数会在流中查找默认的索引。
参数3 timestamp是期望定位处的时间戳,实际应用中因为不知道它的值怎么描述而做了一些尝试(时间戳的基准是多少?)。 项目中已知read到的frame的时间戳是从0开始的,所以我们计算得到的时间偏移就是需要的时间戳。
算了还是看源码吧,提取源码中对参数设置比较重要的部分。
if(stream_index < 0){
stream_index= av_find_default_stream_index(s);
if(stream_index < 0)
return -1;
st= s->streams[stream_index];
/* timestamp for default must be expressed in AV_TIME_BASE units */
timestamp = av_rescale(timestamp, st->time_base.den, AV_TIME_BASE * (int64_t)st->time_base.num);
}
对于参数4,如代码中注释。
#define AVSEEK_FLAG_BACKWARD 1 ///< seek backward
#define AVSEEK_FLAG_BYTE 2 ///< seeking based on position in bytes
#define AVSEEK_FLAG_ANY 4 ///< seek to any frame, even non-keyframes
#define AVSEEK_FLAG_FRAME 8 ///< seeking based on frame number
OK,贴一下实际使用代码吧。
int64_t timestamp = handle->params.seekoffset*AV_TIME_BASE;
ret = av_seek_frame(ic, -1, timestamp, AVSEEK_FLAG_BACKWARD);
if (ret < 0) {
ERR("mod:%d, %s: could not seek to position %d\n", handle->id,
handle->params.path, handle->params.seekoffset);
}