音视频技术应用(18) 控制播放进度——av_seek_frame()

一. 概述

用于将视频移动到指定的关键帧位置。

二. 函数说明

/**
 * 移动视频到指定的关键帧位置
 *
 * @param s 输入媒体的上下文
 * @param stream_index seek的流索引。就是seek时究竟是以音频流索引还是以视频流索引为基准进行seek
 * @param timestamp 起始位置的时间戳,单位是AVStream.time_base
 * @param flags seek的具体策略
 * @return >= 0 on success
 */
int av_seek_frame(AVFromatContext *s, int stream_index, int64_t timestmap, int flags);

第二个参数timestamp的详细说明:

这里的timestamp代表的是想要移动到的起始位置的时间戳,注意这里是起始位置的时间戳,不是起始位置的秒数! 通俗地讲,它就是起始位置的pts,因此一个10s的视频,你想移动到5s的位置,直接传5是不对的。在 FFmpeg 中,时间戳(timestamp)的单位是时间基数(time_base)时间戳值乘以时间基,可以得到实际的时刻值(以秒等为单位)。例如,如果一个视频帧的 dts 是 40,pts 是 160,其 time_base1/1000 秒,那么可以计算出此视频帧的解码时刻是 40 毫秒(40/1000),显示时刻是 160 毫秒(160/1000)。FFmpeg 中时间戳(pts/dts)的类型是 int64_t 类型,如果把一个 time_base 看作一个时钟脉冲,那么 dts/pts 则可以看作是时钟脉冲的计数。

第四个参数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操作。

比方说总时长是1000ms, 那如果用户拖动到中间的位置,那就应该seek到500ms的位置,这个时候把500ms传入到上面的函数中进行seek就可以了。可这样有一个问题,你把500ms传入到上面的视频帧当中,是否真的有pts为500ms的视频帧呢?很难,有可能根本就没有pts为500ms的视频帧,这个时候可能有498,也有可能有501的,那到底是取498的呢?还是取501的呢?这个时候就要有一套策略,AVSEEK_FLAG_BACKWARD 这个FLAG就相当于标识往后走,也就是找pts为501的视频帧。

二. AVSEEK_FLAG_BYTE

这种对应的另外一种场景:假设我想移动视频到中间的位置,但是当前视频文件却没有索引, 不过我却知道这个视频文件的大小(1M), 那这个时候要移动视频到中间位置的话,其实就是应该对应在500KB左右的位置,AVSEEK_FLAG_BYTE这个FLAG就相当于是根据字节数来移动它的位置。

三. AVSEEK_FLAG_ANY

移动视频到任意帧的位置。也就是说,seek到的位置可能是关键帧,也可能是非关键帧,注意:如果移动到的是非关键帧,这个时候解码可能会失败(因为少了前面的关键帧做参考),出现的后果是可能会造成花屏。

四. AVSEEK_FLAG_FRAME

移动视频到关键帧位置。与上面的FLAG不同,这种情况下会强制移动到关键帧位置,比如你要移动的位置是500ms, 但是在500ms没有关键帧,但是在前面400ms的位置有关键帧,它就会移到400ms的位置,这样的话画面就能够正常显示。

注意这种策略也有一定的问题,假设当前视频的GOP是100帧,这100帧的时长是4s, 那这样的话拖动到这4s的任意位置,画面可能都不会改变(由于设置了移动到关键帧,而一个GOP中只有第一帧才是关键帧),这样会给人一个错觉——移动失败了,这点需要注意。

原文地址:https://www.cnblogs.com/yongdaimi/p/15796060.html