走进音视频的世界——剖析exo播放器架构

ExoPlayer是Google开源的一款播放器,基于Android平台的可扩展多媒体播放器,支持HLS流、Smooth Streaming流、Dash流,支持扩展FFmpeg、Vpx、Av1、Flac、Opus等软件解码器。GitHub地址:https://github.com/google/ExoPlayer;开发者指南文档:ExoPlayer;API介绍文档:ExoPlayer library;另外还有就是开发人员的设计博客:https://medium.com/google-exoplayer。博主根据源码阅读与个人理解,与各位伙伴分享下exo播放器架构。

1、播放整体架构

播放器内核主要分为三层:demux解封装、decode解码、render渲染,如图1所示。其中,demux解析出VideoStream、AudioStream、SubtitleStream。如果是多音轨(mkv格式比较常见),那么会有多个AudioStream。SubtitleStream字幕流可能存在也可能不存在,可以是内置封装在格式里也可以是外置选择,如果存在会对应音轨的语言。decode把视频解码为YUV(然后YUV转成RGB),把音频解码为PCM,把字幕解析成一行行文本。render会对视频帧、音频帧、字幕进行同步渲染,一般以音频时钟作为参考时钟。如果视频帧落后30ms以内可以接受,落后30ms~500ms快速渲染,落后500ms以上则丢弃;反之,如果是视频帧超前则等待。

                                                      图1—播放器内核架构 

2、播放时序图

播放器经历的生命周期包括:init、setDataSource、setSurface、prepare同步/prepareAsync异步、play、pause、stop、release。其中init阶段会创建DataSourceFactory、TrackSelector、设置播放状态监听器。setSurface支持设置SurfaceView、TextureView、GlSurfaceView,主要是传递控件对应的Surface进去。prepare阶段主要是探测封装格式、选择对应解封装器、解析视频宽高与音频采样率声道数等参数、解析关键帧索引数组,分为同步与异步两种模式,推荐采用异步。如下图所示:

                                                      图2—播放时序图 

3、解封装

视频解封装器包括:Mp4Extractor、MatroskaExtractor、TsExtractor、FlvExtractor、AviExtractor、WmvExtractor等,音频解封装器包括:Mp3Extractor、OggExtractor、WavExtractor、Ac3Extractor、Ac4Extractor、AmrExtractor、FlacExtractor等。解封装过程包括:sniff、parseTrack、parseSeekMap、readStream。其中sniff负责探测封装格式,parseTrack解析视频轨、音频轨、字幕轨信息,parseSeekMap解析关键帧索引数组,readStream读取音视频流数据(FFmpeg对应的是av_read_frame)。如下图所示:

                                                       图3—音视频解封装器 

4、解码

解码器分为硬解与软解,硬解采用的是mediacodec,软解包括:Av1Decoder、FlacDecoder、FFmpegDecoder、VpxDecoder、SimpleSubtitleDecoder,都实现Decoder接口。解码器内部有inputBuffer和outBuffer两个缓冲队列,属于生产者/消费者模型。mediacodec在Android5.0以前是同步获取解码后的音视频帧,在Android5.0后提供异步回调接口。FFmpeg3.0以后也有提供异步解码方式:avcodec_send_packet、avcodec_receive_frame。

                                                        图4.1—解码器关系图 

字幕解码器又包括:Webvtt、Tx3g、Subrip、Ssa、Dvb、Pgs、Ttml等,继承于SimpleSubtitleDecoder,如下图所示:

                                                       图4.2—字幕解码器

5、渲染

基于BaseRender接口,渲染器分为:TextRender、MediaCodecRender、SimpleDecoderVideoRender、SimpleDecoderAudioRender。其中TextRender是字幕渲染器;MediaCodecRender基于mediacodec硬解,分为MediaCodecVideoRender与MediaCodecAudioRender;SimpleDecoderAudioRender基于音频软解,分为LibFlacAudioRender与FFmpegAudioRender;SimpleDecoderVideoRender基于视频软解,分为LibVpxVideoRender与LibAv1VideoRender。

                                                         图5—渲染器关系图 

解封装、解码、渲染有各自独立工作线程。解封装线程负责读取音视频数据包,保存于inputBuffer;解码线程从inputBuffer取出数据包解码,输出到outputBuffer;渲染线程从outputBuffer取出视频帧渲染/音频帧播放。

可以到GitHub一起学习音视频:https://github.com/xufuji456/FFmpegAndroid​​​​​​​

猜你喜欢

转载自blog.csdn.net/u011686167/article/details/113487626