ffmpeg中使用av_seek_frame()设置流偏移(起始位置)

    背景: 在项目应用中,需要实现节目单程序重启后,能够准确定位到节目单时间轴的正确位置。例如,虚拟频道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);
    }



    从代码中可以看出,当 参数2(stream_index)的值小于0时(即非法索引,我设置为-1),会查找默认的流索引,具体是啥目前可以不关心啦。还有比较重要的就是当stream_index<0时,我们设置的参数timestamp的时间基准是AV_TIME_BASE。若stream_index被指定了,则timestamp的时基是指定流的时间基准。


    对于参数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);
}






你可能感兴趣的:(ffmpeg,av_seek_frame)