美文网首页
简易播放器设计文档

简易播放器设计文档

作者: 上官宏竹 | 来源:发表于2021-09-02 11:56 被阅读0次

    EntryTask: 使用FFMpeg编写一个简单音视频播放器

    开发环境

    1. 开发语言:C++
    2. IDE:QT Creator/XCode/VS

    内容要求

    1. 编译、集成FFmpeg实现基础的视频播放器功能;【完成】
    2. 有一个简易的界面(QT),支持开始播放、暂停、继续、拖放、从文件中选择媒体文件,支持RTMP拉流;【完成】
    3. 声音,画面的播放,不能出现异常中断,实现基础的音画同步策略;【完成】
    4. 输出FFMpeg库的集成/使用文档;【完成】

    播放器功能

    播放器流程

    fmpeg播放器流程图.png

    开源框架选取

    1. 窗口显示采用QT框架
    2. 音视频解码采用FFmpeg
    3. 音频播放采用SDL

    上述三个开源组建都是跨平台的。

    读取、解码、渲染设计

    1. 设计一个音视频的packet队列,作用是使读取线程和解码线程异步工作。packet队列采用互斥锁同步。
    2. 读取文件子线程:线程作用是从本地或者网络文件流中不停地读取数据。打开文件后,循环调用av_read_frame读取文件中的packet,将其塞入对应的音视频packet队列中。
    3. 解码子线程:线程的作用是循环从音视频packet队列中读取相应的packet数据,送入解码器内部进行解码操作。其中,视频解码子线程是程序创建,音频解码子线程是由SDL创建,程序通过注册回调来执行音频解码。视频解码线程会在解码后将数据转换为RGB图像数据,再通过回调,将数据传递到MainWindow类内部。
    4. 主线程: MainWindow窗口渲染线程。接收到RGB数据后,通过QT的信号槽机制,将需要显示的数据emit到主线程。在MainWindow窗口的paintEvent事件回调中,将RGB数据转成QImage,最后通过drawImage将显示数据画到MainWindow窗口上。

    可以参考ffmpeg播放器流程图。

    抽象接口设计

    播放器和外部Window窗口解耦,给播放器传入一个外部接口指针。
    主窗口MainWindow继承一个VideoPlayerCallBack的抽象类,VideoPlayerCallBack类中声明需要回调的外部接口。在主窗口MainWindow中实现这些接口。内部播放器在合适时机调用这些接口,将数据传给窗口处理。

    音视频同步处理

    音视频同步主要存在三种方式:音频同步到视频,视频同步到音频,音视频同步到外部时间。这里选择使用视频同步到音频的方案,主要是因为SDL在音频解码时已经做好了时间的同步。

    1. 音频解码回调线程中,将音频的pts记录下来。即:m_audioCurPts = av_q2d(m_audioStream->time_base) * packet->pts;
    2. 在视频的解码线程中,处理同步。获取当前视频帧的pts,与前面获得到的音频的pts进行比较,如果视频pts大于音频的pts,表示视频快了,则让视频解码线程暂停一段时间,然后继续比较,直到视频pts小于等于音频的pts,则继续视频解码线程。
    3. 在无音频的码流中,则将视频的同步到外部时间。即在视频解码一开始时记录当前的时间戳,在解码当前视频帧时,计算当前时间与视频解码起始时间差值,如果视频pts大于这个差值,则暂停视频解码线程。

    音视频暂停播放处理

    暂停播放时,读取文件子线程停止读取数据到packet队列,解码现场也暂停从packet队列取数据解码。

    FFmpeg音视频解码过程

    1. 初始化网络 avformat_network_init
    2. 打开文件avformat_open_input
    3. 从文件中提取流信息avformat_find_stream_info
    4. 在多个数据流中找到视频流(类型为MEDIA_TYPE_VIDEO)和音频流(AVMEDIA_TYPE_AUDIO
    5. 查找相对应的解码器avcodec_find_decoder
    6. 打开解码器avcodec_open2
    7. 从数据流中读取数据到Packet中av_read_frame
    8. 将数据送入到解码器内部avcodec_send_packet
    9. 为解码帧分配内存av_frame_alloc
    10. 接收解码帧avcodec_receive_frame
    11. 解码完成后需要关闭avformat_open_input打开的输入流,avcodec_open2打开的CODEC
    image.png

    FFmpeg格式转换过程

    1. 分配保存输出RGB数据的AVFrame *rgbFrame空间。av_frame_alloc
    2. 分配rgbFramedata域的内存空间。av_image_alloc
    3. 调用sws_getContext创建一个SwsContext上下文
    4. 调用sws_scale进行数据格式转换
    5. 释放SwsContext上下文sws_freeContext,渲染之后释放rgbFramedata域的内存空间av_freep(&(rgbFrame->data[0]))rgbFrame的空间av_free(rgbFrame)

    播放器截图

    代码:myVideoPlayer

    相关文章

      网友评论

          本文标题:简易播放器设计文档

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