一、实现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操作

源码链接

35_音视频播放器_seek&暂停的更多相关文章

  1. Pyqt 音视频播放器

    在寻找如何使用Pyqt做一个播放器时首先找到的是openCV2 openCV2 貌似太强大了,各种关于图像处理的事情它都能完成,如 读取摄像头.图像识别.人脸识别.  图像灰度处理 . 播放视频等,强 ...

  2. 开源安卓Android流媒体音视频播放器实现声音自动停止、恢复、一键静音功能源码

    本文转自EasyDarwin团队John的博客:http://blog.csdn.net/jyt0551/article/details/60802145 我们在开发安卓Android流媒体音视频播放 ...

  3. 分享几个不错的Android开源音视频播放器

    整理了一下Github上几个开源的音视频播放器项目,有兴趣的同学可以clone代码去研究学习.   UniversalMusicPlayer https://github.com/googlesamp ...

  4. 一些不错的Android开源音视频播放器

    摘要:来自Github上的一点点整理,希望对你有用! 整理了一下Github上几个开源的音视频播放器项目,有兴趣的同学可以clone代码去研究学习. 1.UniversalMusicPlayer ht ...

  5. 自己做的一个android 音视频播放器

    欢迎大家下载: http://download.csdn.net/detail/q610098308/8504335

  6. FFmpeg简易播放器的实现-音视频播放

    本文为作者原创,转载请注明出处:https://www.cnblogs.com/leisure_chn/p/10235926.html 基于FFmpeg和SDL实现的简易视频播放器,主要分为读取视频文 ...

  7. WPF技术触屏上的应用系列(三): 视频播放器的使用及视频播放、播放、暂停、可拖动播放进度效果实现

    原文:WPF技术触屏上的应用系列(三): 视频播放器的使用及视频播放.播放.暂停.可拖动播放进度效果实现 去年某客户单位要做个大屏触屏应用,要对档案资源进行展示之用.客户端是Window7操作系统,5 ...

  8. Android 音视频深入 十九 使用ijkplayer做个视频播放器(附源码下载)

    项目地址https://github.com/979451341/Myijkplayer 前段时候我觉得FFmpeg做个视频播放器好难,虽然播放上没问题,但暂停还有通过拖动进度条来设置播放进度,这些都 ...

  9. 音视频处理之FFmpeg+SDL+MFC视频播放器20180411

    一.FFmpeg+SDL+MFC视频播放器 1.MFC知识 1).创建MFC工程的方法 打开VC++ 文件->新建->项目->MFC应用程序 应用程序类型->基于对话框 取消勾 ...

  10. 音视频处理之FFmpeg+SDL视频播放器20180409

    一.FFmpeg视频解码器 1.视频解码知识 1).纯净的视频解码流程 压缩编码数据->像素数据. 例如解码H.264,就是“H.264码流->YUV”. 2).一般的视频解码流程 视频码 ...

随机推荐

  1. 利用显卡的SR-IOV虚拟GPU技术,实现一台电脑当七台用

    背景 虚拟桌面基础设施(VDI)技术一般部署在服务器,可以实现多个用户连接到服务器上的虚拟桌面.随着桌面计算机性能的日益提升,桌面计算机在性能在很多场景下已经非常富余,足够同时满足多个用户同时使用的需 ...

  2. Centos中报错apt Command not Found

    先说结论: 在centos下用yum install xxxyum和apt-get的区别: 一般来说著名的linux系统基本上分两大类: RedHat系列:Redhat.Centos.Fedora等 ...

  3. Lambda 表达式总结

    1 Lambda 表达式简介 ​ Lambda 表达式是 JDK 8 的新特性,主要用于简化匿名内部类的定义,帮助用户方便.高效地书写优雅的代码. ​ Lambda 表达式实现的必须是一个接口,并且接 ...

  4. JVM详解

    1 JVM运行机制概述 JVM运行机制 类加载机制: 类加载过程由类加载器来完成,即由ClassLoader及其子类实现,有隐式加载和显式加载两种方式.隐式加载是指在使用new等方式创建对象时会隐式调 ...

  5. ysoserial URLDNS利用链分析

    在分析URLDNS之前,必须了解JAVA序列化和反序列化的基本概念.其中几个重要的概念: 需要让某个对象支持序列化机制,就必须让其类是可序列化,为了让某类可序列化的,该类就必须实现如下两个接口之一: ...

  6. 4.1k Star!全面的C#/.NET/.NET Core学习、工作、面试指南

    C#/.NET/.NET Core 学习.工作.面试指南 让现在的自己不再迷茫 . GitHub 开源地址:https://github.com/YSGStudyHards/DotNetGuide D ...

  7. DFS算法模板(2488:A Knight's Journey)

    DFS算法(C++版本) 题目一: 链接:http://bailian.openjudge.cn/practice/2488/ 解析思路: 骑士找路就是基本的DFS,用递归不断找到合适的路,找不到就回 ...

  8. 一秒出图?SDXL-Turbo实时AI绘画整合包下载

    SDXL Turbo是一种快速生成的AI构图模型,它基于一种称为对抗性扩散蒸馏的新训练方法,该方法允许在1到4个步骤中以高图像质量对大规模基础图像扩散模型进行采样,并将其与对抗性损失相结合,以确保即使 ...

  9. 2019年在浏览器用原生js写WebGL,绘制图形;

    因为JavaScript高级程序设计(第三版)中的运行书上15.3WebGL部分的代码时在chrome和firefox浏览器下报错,在后面我网上初步找了一圈,好像没人做出真正可以用的代码;所以我就自己 ...

  10. 硬件开发笔记(十二):RK3568底板电路电源模块和RTC模块原理图分析

    前言   做硬件做系统做驱动,很难从核心板做起,所以我们先依赖核心板,分析底板周围的电路,然后使用AD绘制原理图和设计PCB,打样我司测试底板,完成硬件测试,再继续系统适配,驱动移植,从而一步一步完善 ...