美文网首页
ffmpeg # AVSEEK_FLAG

ffmpeg # AVSEEK_FLAG

作者: FlyingPenguin | 来源:发表于2018-07-31 17:15 被阅读171次

avformat_seek_file

/**
 * Seek to timestamp ts.
 * Seeking will be done so that the point from which all active streams
 * can be presented successfully will be closest to ts and within min/max_ts.
 * Active streams are all streams that have AVStream.discard < AVDISCARD_ALL.
 *
 * If flags contain AVSEEK_FLAG_BYTE, then all timestamps are in bytes and
 * are the file position (this may not be supported by all demuxers).
 * If flags contain AVSEEK_FLAG_FRAME, then all timestamps are in frames
 * in the stream with stream_index (this may not be supported by all demuxers).
 * Otherwise all timestamps are in units of the stream selected by stream_index
 * or if stream_index is -1, in AV_TIME_BASE units.
 * If flags contain AVSEEK_FLAG_ANY, then non-keyframes are treated as
 * keyframes (this may not be supported by all demuxers).
 * If flags contain AVSEEK_FLAG_BACKWARD, it is ignored.
 *
 * @param s media file handle
 * @param stream_index index of the stream which is used as time base reference
 * @param min_ts smallest acceptable timestamp
 * @param ts target timestamp
 * @param max_ts largest acceptable timestamp
 * @param flags flags
 * @return >=0 on success, error code otherwise
 *
 * @note This is part of the new seek API which is still under construction.
 *       Thus do not use this yet. It may change at any time, do not expect
 *       ABI compatibility yet!
 */
int avformat_seek_file(AVFormatContext *s, 
                       int stream_index, 
                       int64_t min_ts, 
                       int64_t ts, 
                       int64_t max_ts, 
                       int flags);

If flags contain AVSEEK_FLAG_BYTE, then all timestamps are in bytes and
are the file position (this may not be supported by all demuxers)
.
如果flags 中包含AVSEEK_FLAG_BYTE,那么时间戳的单位应该为字节,也就是在文件中的坐标。

av_seek_frame

/**
 * Seek to the keyframe at timestamp.
 * 'timestamp' in 'stream_index'.
 *
 * @param s media file handle
 * @param stream_index If stream_index is (-1), a default
 * stream is selected, and timestamp is automatically converted
 * from AV_TIME_BASE units to the stream specific time_base.
 * @param timestamp Timestamp in AVStream.time_base units
 *        or, if no stream is specified, in AV_TIME_BASE units.
 * @param flags flags which select direction and seeking mode
 * @return >= 0 on success
 */
int av_seek_frame(AVFormatContext *s, int stream_index, int64_t timestamp,
                  int flags);

Seek to the keyframe at timestamp.

flags可能包含的值如下:

#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

AVSEEK_FLAG_BACKWARD是seek到请求的timestamp之前最近的关键帧
AVSEEK_FLAG_BYTE 是基于字节位置的查找
AVSEEK_FLAG_ANY 是可以seek到任意帧,注意不一定是关键帧,因此使用时可能会导致花屏
AVSEEK_FLAG_FRAME是基于帧数量快进

flags可能同时包含以上的多个值。如AVSEEK_FLAG_BACKWARD和AVSEEK_FLAG_BYTE

flags = AVSEEK_FLAG_BACKWARD | AVSEEK_FLAG_BYTE;
AVSEEK_FLAG_BACKWARD

av_seek_frame 可以帮我们定位到关键帧和非关键帧。定位到非关键帧肯定是不行的,因为视频的解码需要依赖于关键帧。
如果跳过关键帧,解码出来的图像是会出现马赛克的,影响用户体验。
通常情况下,我们的 seek 接口都是以 ms 为单位的,如果指定的 ms 时间点,刚好不是关键帧(这个概率很大),ffmpeg 会自动往回 seek 到最近的关键帧,这就是 AVSEEK_FLAG_BACKWARD 这个 flag 的含义
如果不加入这个 flag,av_seek_frame 可以精确的定位到 timestamp 附近的音视频帧上,但是不会保证是关键帧;如果加上这个 flag 可以保证关键帧,但是又没法保证 seek 的精度,因为有可能会往回 seek。

通常使用的seek方式为BACKWARD,这种方式查找虽然定位并不是非常精确,但是能够很好的处理掉马赛克的问题,因为BACKWARD的方式会去向回查找keyframe处,定位到keyframe处。

AVSEEK_FLAG_BYTE
调用堆栈.png

调用堆栈: avformat_seek_file->avformat_seek_file->seek_frame_internal->seek_frame_byte

  • avformat_seek_file用法:
int avformat_seek_file(AVFormatContext *s, 
                       int stream_index, 
                       int64_t min_ts, 
                       int64_t ts, 
                       int64_t max_ts, 
                       int flags);
avformat_seek_file (pFormatCtx,-1,INT64_MIN,pFormatCtx->data_offset,INT64_MAX, AVSEEK_FLAG_BYTE);
  • av_seek_frame
int av_seek_frame(AVFormatContext *s, int stream_index, int64_t timestamp,
                  int flags);
  • seek_frame_internal
static int seek_frame_internal(AVFormatContext *s, int stream_index,
                               int64_t timestamp, int flags)
{
    int ret;
    AVStream *st;

    if (flags & AVSEEK_FLAG_BYTE) {
        if (s->iformat->flags & AVFMT_NO_BYTE_SEEK)
            return -1;
        ff_read_frame_flush(s);
        return seek_frame_byte(s, stream_index, timestamp, flags);
    }

...
}
  • seek_frame_byte
static int seek_frame_byte(AVFormatContext *s, int stream_index,
                           int64_t pos, int flags)
{
    int64_t pos_min, pos_max;

    pos_min = s->internal->data_offset;
    pos_max = avio_size(s->pb) - 1;

    if (pos < pos_min)
        pos = pos_min;
    else if (pos > pos_max)
        pos = pos_max;

    avio_seek(s->pb, pos, SEEK_SET);

    s->io_repositioned = 1;

    return 0;
}

References:

https://github.com/rockcarry/ffplayer/wiki/%E9%9A%BE%E7%82%B9-seek-%E6%93%8D%E4%BD%9C
https://blog.csdn.net/m0_37684310/article/details/79544720
http://bbs.chinaffmpeg.com/forum.php?mod=viewthread&tid=14

相关文章

网友评论

      本文标题:ffmpeg # AVSEEK_FLAG

      本文链接:https://www.haomeiwen.com/subject/zhqhvftx.html