ffmpeg简易播放器的实现-音视频播放

基于FFmpeg和SDL实现的简易视频播放器,主要分为读取视频文件解码和调用SDL显示两大部分。
前面两个实验分别实现了视频播放和音频播放:
FFmpeg简易播放器的实现-视频播放
FFmpeg简易播放器的实现-音频播放
本实验将视频播放和音频播放结合在一起。
本实验主要参考如下两篇文章:
[1]. 最简单的基于FFMPEG+SDL的视频播放器ver2(采用SDL2.0)
[2]. An ffmpeg and SDL Tutorial

1. 视频播放器基本原理

下图引用自“雷霄骅,视音频编解码技术零基础学习方法”,因原图太小,看不太清楚,故重新制作了一张图片。
播放器基本原理示意图
如下内容引用自“雷霄骅,视音频编解码技术零基础学习方法”:

解协议
将流媒体协议的数据,解析为标准的相应的封装格式数据。视音频在网络上传播的时候,常常采用各种流媒体协议,例如HTTP,RTMP,或是MMS等等。这些协议在传输视音频数据的同时,也会传输一些信令数据。这些信令数据包括对播放的控制(播放,暂停,停止),或者对网络状态的描述等。解协议的过程中会去除掉信令数据而只保留视音频数据。例如,采用RTMP协议传输的数据,经过解协议操作后,输出FLV格式的数据。

解封装
将输入的封装格式的数据,分离成为音频流压缩编码数据和视频流压缩编码数据。封装格式种类很多,例如MP4,MKV,RMVB,TS,FLV,AVI等等,它的作用就是将已经压缩编码的视频数据和音频数据按照一定的格式放到一起。例如,FLV格式的数据,经过解封装操作后,输出H.264编码的视频码流和AAC编码的音频码流。

解码
将视频/音频压缩编码数据,解码成为非压缩的视频/音频原始数据。音频的压缩编码标准包含AAC,MP3,AC-3等等,视频的压缩编码标准则包含H.264,MPEG2,VC-1等等。解码是整个系统中最重要也是最复杂的一个环节。通过解码,压缩编码的视频数据输出成为非压缩的颜色数据,例如YUV420P,RGB等等;压缩编码的音频数据输出成为非压缩的音频抽样数据,例如PCM数据。

音视频同步
根据解封装模块处理过程中获取到的参数信息,同步解码出来的视频和音频数据,并将视频音频数据送至系统的显卡和声卡播放出来。

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

2.1 实验平台

实验平台:openSUSE Leap 42.3
FFmpeg版本:4.1
SDL版本:2.0.9
FFmpeg开发环境搭建可参考“ffmpeg开发环境构建

2.2 源码流程分析

参考如下:
FFmpeg简易播放器-音频播放流程图

2.3 解复用线程

解复用线程就是main()函数所在的主线程。main()函数作一些必要的初始化工作后,创建音频处理线程和视频处理线程。
然后main()函数进入主循环,从输入文件中读取packet,并根据packet类型,将之放入视频packet队列或音频packet队列。

2.4 音频处理线程

音频处理线程是SDL库内建线程。用户提供回调函数供音频处理线程调用。实现过程参考:
FFmpeg简易播放器的实现-音频播放

2.5 视频处理线程

视频处理线程实现视频解码及播放。实现过程参考:
FFmpeg简易播放器的实现-音频播放

2.6 源码清单

代码已经变得挺长了,不贴完整源码了,源码参考:
https://github.com/leihl/exercises/tree/master/source/ffmpeg/player_avideo/ffplayer.c

源码清单中涉及的一些概念简述如下:
container:
对应数据结构AVFormatContext
封装器,将流数据封装为指定格式的文件,文件格式如AVI、MP4等。
FFmpeg可识别五种流类型:视频video(v)、音频audio(a)、attachment(t)、数据data(d)、字幕subtitle。

codec:
对应数据结构AVCodec
编解码器。编码器将未压缩的原始图像或音频数据编码为压缩数据。解码器与之相反。

codec context:
对应数据结构AVCodecContext
编解码器上下文。此为非常重要的一个数据结构,后文分析。各API大量使用AVCodecContext来引用编解码器。

codec par:
对应数据结构AVCodecParameters
编解码器参数。新版本增加的字段。新版本建议使用AVStream->codepar替代AVStream->codec。

packet:
对应数据结构AVPacket
经过编码的数据。通过av_read_frame()从媒体文件中获取得到的一个packet可能包含多个(整数个)音频帧或单个
视频帧,或者其他类型的流数据。

frame:
对应数据结构AVFrame
解码后的原始数据。解码器将packet解码后生成frame。

2.7 编译

gcc -o ffplayer ffplayer.c -lavutil -lavformat -lavcodec -lavutil -lswscale -lSDL2

2.8 测试

选用clock_320.avi测试文件,此文件

ffprobe clock_320.avi

打印视频文件信息如下:

[avi @ 0x9286c0] non-interleaved AVI
Input #0, avi, from 'clock_320.avi':
  Duration: 00:00:12.00, start: 0.000000, bitrate: 42 kb/s
    Stream #0:0: Video: msrle ([1][0][0][0] / 0x0001), pal8, 320x320, 1 fps, 1 tbr, 1 tbn, 1 tbc
    Stream #0:1: Audio: truespeech ([34][0][0][0] / 0x0022), 8000 Hz, mono, s16, 8 kb/s

运行测试命令:

./ffplayer clock_320.avi 

可以听到每隔1秒播放一次“嘀”声,声音播放12次。时针每隔1秒跳动一格,跳动12次。声音播放正常,画面播放也正常,但是声音和画面不能对应,因为没有考虑音视频同步。下一次实验研究音视频同步问题。

3. 参考资料

[1] 雷霄骅,视音频编解码技术零基础学习方法
[2] 雷霄骅,最简单的基于FFMPEG+SDL的视频播放器ver2(采用SDL2.0)
[3] SDL WIKI, https://wiki.libsdl.org/
[4] Martin Bohme, An ffmpeg and SDL Tutorial, Tutorial 03: Playing Sound

4. 修改记录

2018-12-06 V1.0 初稿

猜你喜欢

转载自www.cnblogs.com/leisure_chn/p/10235926.html