QT 6.6.0 + FFmpeg + SDL2实现音频视频播放(音视频播放改进-快进和快退)
上一篇文章我们已经讲解了关于音视频播放的同步改进,主要是大致讲解了实现的思路以及一些地方需要注意的难点。这篇文章主要是在前面改进的基础上实现视频播放的快进和快退实现,那么像播放速度,暂停,调整音量等功能呢?这些要等后期慢慢进行改进,一步一步的来,不然代码多了就不好讲解和理解了。和。
目录
上一篇文章我们已经讲解了关于音视频播放的同步改进,主要是大致讲解了实现的思路以及一些地方需要注意的难点。这篇文章主要是在前面改进的基础上实现视频播放的快进和快退实现,那么像播放速度,暂停,调整音量等功能呢?这些要等后期慢慢进行改进,一步一步的来,不然代码多了就不好讲解和理解了。参考1 和 参考2 。
不知道有没有小伙伴是这样想的,之前我们在使用QT中的自带多媒体模块(multimedia)和SDL2实现音视频播放或者录音的过程中,要改变播放进度比如快进或者快退等功能,都是直接通过当前的播放进度 + 快进或者快退的时间即可实现,那是因为自带的库已经帮我们实现好了相关的功能,比如流的处理以及缓冲区数据的刷新,但是本文使用ffmpeg实现的快进或者快退需要自己处理数据,因此看起来比较简单,实质上要实现这样的功能还需要对ffmpeg有较多的了解。
整体实现思路如下:

实现思路
- 首先根据从事件等待队列中获取当前按下的左右上下键
- 按下左键-前进10秒;按下右键-后退10秒;按下上下键-分别前进和后退60秒
- 获得当前的按下键盘状态之后,根据当前视频播放的时间戳 + 按下键盘状态 = 视频帧和音频播放的跳转位置seek video pos和seek audio pos
- 由于当前获得的播放进度为秒,根据流中的时间戳将其进行转换统一的时间戳格式
- 根据av_seek_frame和播放的视频进度获得更改之后的上下文格式
- 清空掉之前队列中的保存的数据
- 根据更改之后的上下文格式读取数据(之后的操作大家都知道了)。
前置知识点
第一点:avcodec_flush_buffers 的含义
-
清空缓冲区:该函数会清空与指定解码器相关的所有缓冲数据。任何尚未处理的帧或数据都将被丢弃,解码器将重置为初始状态。
-
重置状态:调用此函数后,解码器的状态将被重置,适用于需要重新开始解码的场景,例如在切换到新的视频流或在处理新的输入数据时。
第二点:AV_TIME_BASE_Q含义
-
分数表示:
AV_TIME_BASE_Q的值通常为AVRational { 1, AV_TIME_BASE },这意味着它表示的是 1 微秒的时间长度在 AV_TIME_BASE 单位下的分数形式。换句话说,AV_TIME_BASE_Q表示的时间单位是微秒,且相对于 AV_TIME_BASE 的比例关系。 -
时间戳转换:使用
AV_TIME_BASE_Q可以方便地将时间戳从其他单位(如秒)转换为以AV_TIME_BASE为基准的时间戳,反之亦然。这对于处理音视频流中的时间戳非常重要。
if(video_stream_index >= 0 && audio_stream_index >= 0){
//av_rescale_q (a,b,c)是一个函数,它将时间戳从一个基数重新缩放到另一个基数。它基本上计算a*b/c
seek_target_video = av_rescale_q(seek_target_video,AV_TIME_BASE_Q,pFormatCtx -> streams[video_stream_index] -> time_base);
seek_target_audio = av_rescale_q(seek_target_audio,AV_TIME_BASE_Q,pFormatCtx -> streams[audio_stream_index] -> time_base);
}
第三点:AVSEEK_FLAG_BACKWARD 的含义
-
向后寻址:当使用
AVSEEK_FLAG_BACKWARD标志时,FFmpeg 将尝试在寻址时向后查找最近的关键帧(I 帧)。如果请求的时间戳在当前播放位置之前,FFmpeg 会寻找最接近的关键帧并返回其位置。
av_seek_frame函数作用

av_seek_frame 函数用于在媒体流中进行时间戳寻址。用户可以使用它在音视频流中快速定位到特定的帧或时间点,通常用于视频播放器、编辑软件或流媒体应用中。
av_seek_frame 的作用
-
时间戳寻址:
av_seek_frame允许用户根据给定的时间戳(以 AV_TIME_BASE 为单位)查找媒体流中的特定帧。它可以用于定位到视频的某个时间点,或在音频流中查找特定的音频样本。 -
关键帧寻址:在寻址时,
av_seek_frame会优先查找关键帧(I 帧)。如果请求的时间戳在当前播放位置之前,FFmpeg 会寻找最接近的关键帧并返回其位置。这对于视频播放和编辑非常重要,因为关键帧是解码视频流的起始点。 -
流的随机访问:通过使用
av_seek_frame,用户可以实现对媒体流的随机访问,允许在播放过程中快速跳转到不同的时间点。
int av_seek_frame(AVFormatContext *s, int stream_index, int64_t timestamp, int flags);
参数:
s: 指向 AVFormatContext 的指针,表示打开的媒体文件上下文。
stream_index:要寻址的流的索引,通常是视频或音频流的索引。如果设置为 -1,则表示所有流。
timestamp: 目标时间戳,以 AV_TIME_BASE 为单位。
flags: 寻址标志,可以是 AVSEEK_FLAG_BACKWARD、AVSEEK_FLAG_ANY 等,用于控制寻址行为。
QT 6.6.0 + FFmpeg+SDL2实现音频视频播放
魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。
更多推荐
所有评论(0)