35_音视频播放器_seek&暂停

一、实现seek功能

我们主要是使用ffmpeg的av_seek_frame方法实现seek功能,但是我们给外界提供seek功能的方法可以不叫seek,我这里使用setTime方法,单位是秒。

/**
 * 移动视频到指定的关键帧位置
 *
 * @param s 输入媒体的上下文
 * @param stream_index 流索引,要seek的那个流,-1代表默认情况,FFmpeg自动选择音频还是视频做seek操作,
 * @param timestamp 起始位置的时间戳,单位是AVStream.time_base
 * @param flags seek的具体策略
 * @return >= 0 on success
 */
int av_seek_frame(AVFormatContext *s, int stream_index, int64_t timestamp,
                  int flags);

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

这里的timestamp代表的是想要移动到的起始位置的时间戳,注意这里是起始位置的时间戳,不是起始位置的秒数! 通俗地讲,它就是起始位置的pts,因此一个10s的视频,你想移动到5s的位置,直接传5是不对的。在 FFmpeg 中,时间戳(timestamp)的单位是时间基数(time_base),时间戳值乘以时间基,可以得到实际的时刻值(以秒等为单位)。例如,如果一个视频帧的 dts 是 40,pts 是 160,其 time_base 是 1/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
  1. AVSEEK_FLAG_BACKWARD
    则优, 例如:拖到8的位置是B帧,则找附件的关键帧6,如果找不到它会花屏
  2. AVSEEK_FLAG_BYTE
    基于字节位置的跳转
  3. AVSEEK_FLAG_ANY
    (老实)直接精准到拖动的位置,问题:如果不是关键帧,B帧 可能回造成花屏情况
  4. AVSEEK_FLAG_FRAME
    找关键帧(非常不准确,可能会跳的太多),一般不会直接用,但是会配合用

可以参考:
音视频技术应用(18)- 控制播放进度——av_seek_frame()
音视频从入门到精通——FFmpeg之av_seek_frame函数分析

我们在使用av_read_frame方法不断的从视频文件中读取数据出来,当我们想要实现seek的时候,就需要重新地位到seek的地方,在重新使用av_read_frame方法开始读取数据,因此av_seek_frame方法需要在av_read_frame方法之前使用。

// 现实时间 -> 时间戳
AVRational timeBase = _fmtCtx->streams[streamIdx]->time_base;
int64_t ts = _seekTime / av_q2d(timeBase);
ret = av_seek_frame(_fmtCtx, streamIdx, ts, AVSEEK_FLAG_BACKWARD);

if(ret < 0){// seek失败
   qDebug() << "seek失败" << _seekTime << ts << streamIdx;
   _seekTime = -1;
}else{// seek成功
    qDebug() << "seek成功" << _seekTime << ts << streamIdx;
    // 清空之前读取的数据包
    clearAudioPktList();
    clearVideoPktList();
    _vSeekTime = _seekTime;
    _aSeekTime = _seekTime;
    _seekTime = -1;
    // 恢复时钟
    _aTime = 0;
    _vTime = 0;
}

二、解决点击seek操作时会出现画面快速闪过

上面代码进行运行后进行seek会发现,在seek到那个位置的时候,会出现画面快速的闪过,而且快速闪过的画面是seek点附近的画面。

我们同在videoplayer_video.cpp里的decodeVideo方法里的最后添加一条打印qDebug()<< "渲染了一帧"<< _vTime << _aTime;

通过上面的日志打印,可以看到我们要seek到89,音频到了88确实差不多到了89,但是视频没有直接到89,而是经历了好多帧,因此_vTime < _aTime,所以下面代码中while (_vTime > _aTime && _state == Playing)不成立,就会走下面的代码,就会送到解码中去显示,就会出现画面快速闪过。

找到原因了,我们就知道该如何去解决了,我们可以把那些多余的帧扔掉


从上面我们知道音频也不是很准确的定位到seek的位置,因此音频也可以进行控制


三、实现暂停功能

我们在VideoPlayer类里的pause方法里修改了状态为暂停状态,所以我们要根据这个pause状态来做事,而要实现暂停功能,有两个方面要暂停,一个是音频暂停还有一个是视频暂停

3.1、音频暂停

我们需要在videoplayer_audio.cpp里的sdlAudioCallback方法里添加if判断

音频暂停

3.2、视频暂停

我们需要在videoplayer_video.cpp里的decodeVideo方法里添加if判读

视频暂停

这里我们if判断不能跟音频一样使用break,因为我们的decodeVideo方法是在子线程中执行的,你一但break退出循环了,那么这个子线程就销毁了,就再也没有机会解码视频了,所以这里需要用continue
我们还要实现暂停的时候能够实现seek功能,所以还要判断_vSeekTime == -1表面当前没有seek操作

源码链接

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,826评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,968评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,234评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,562评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,611评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,482评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,271评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,166评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,608评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,814评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,926评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,644评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,249评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,866评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,991评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,063评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,871评论 2 354