ijkplayer是一个Android和ios双移动平台开源播放器,其内核基于ffplay,很多互联网公司播放器都采用了该播放器,尤其是大部分直播应用app,因此如果我们自己开发移动端播放器,ijkplayer将是不二选择。我因为公司直播项目用过ijkplayer,对里面代码也比较熟悉,所以写此博客与大家分享一下该项目的源码框架结构,如有理解不正之处,还望多多指教。
首先我们来看看从用户界面真正到达播放器代码前的那部分的代码。Demo的初始界面为IJKDemoMainViewController,其中维护了几种音视频源入口,包括本地文件、扫二维码和在线视频等列表,当列表Item被点击的时候,将会导航到选择媒体源界面,当媒体源的Item被选择的时候,将获取到媒体源位置,要么是filePath,要么是URL,然后传给播放器。我们以Online Samples为例进行分析,当选择Online Sample Item,将被导航到IJKDemoSampleViewController界面,里面有在线媒体源列表,当列表中媒体源被选择,将被导航到IJKVideoViewController界面,通过方法initWithURL将url传递过去,在IJKVideoViewController的viewDidLoad方法里面创建播放器实例IJKFFMoviePlayerController,至此达到播放内核代码部分,上面部分简单调用图如下所示:
现在我们开始分析播放器代码,主要函数调用顺序和主要线程开启位置见下图所示:
通过整理调用接口,需要弄得ijkplayer逻辑,我们需要注意一下几个点:自定义组件注册,消息循环,5个线程和ffpipeline,弄懂这些概念,逻辑结构基本清晰,想要按需修改自己的播放器也会游刃有余,下面我们大致介绍一下这几个点。
自定义组件主要包括protocol和demuxer。协议有:ijkimp_ff_ijkio_protocol,ijkimp_ff_async_protocol,ijkimp_ff_ijktcphook_protocol,ijkimp_ff_ijkhttphook_protocol和ijkimp_ff_ijklongurl_protocol;demuxer为ijkimp_ff_ijklivehook_demuxer。
demuxer的注册相对比较简单,主要是通过宏IJK_REGISTER_DEMUXER来完成,在宏里通过调用ijkav_register_input_format完成demuxer的注册。
protocol的注册在最近新版ijkplayer有所改变。旧版ijkplayer跟demuxer注册很像,通过IJK_REGISTER_DEMUXER来完成,里面ijkav_register_protocol调用的是ffurl_register_protocol完成protocol的注册。新版ffmpeg去掉了ffurl_register_protocol接口,而是通过在文件libavformat/protocols.c里面声明协议来注册,ijkav_register_protocol实现为空。
消息循环处理函数media_player_msg_loop是在调用接口ijkmp_ios_create时候传到底层的,调用ijkmp_prepare_async时,创建了消息处理线程。media_player_msg_loop里面主要就是获取消息并处理消息。
在函数ffp_prepare_async_l调用stream_open,stream_open中创建了视频渲染线程,该线程主要是进行视频渲染工作,并对视频进行同步,同步相关逻辑主要在这个线程里面,同步的大概思路就是:有一个绝对时间作为同步起点,然后计算当前帧与上一帧时间差,然后与当前绝对时间基准源比较,如果不到时间,计算remaining_time,然后sleep等待。如果时间参考时钟不是视频源,还会时钟就行调整,如果当前视频帧落后于主时钟源,则需要减小下一帧画面的等待时间,如果视频帧超前,并且该帧的显示时间大于显示更新门槛,则显示下一帧的时间为超前的时间差加上上一帧的显示时间,如果视频帧超前,并且上一帧的显示时间小于显示更新门槛,则采取加倍延时的策略。
stream_open还创建了read_thread,read_thread里面主要有打开文件或流,然后并获取媒体信息。拿到信息后,初始化音视频解码器,并开创建了音视频解码线程。线程创建后,开始demuxer文件,并解除音视频pkt,并将pkt放到对应的音频、视频和字幕pkt队列里面。
音频解码线程和视频解码线程的主要工作是从音频和视频pkt队列里面取包并解码,并将解码数据送到缓冲区等待渲染。
ffpipeline主要就是运用c函数指针,实现动态选择编解码接口,并与在硬解和软解之间切换。
至此ijkplayer主要模块大致介绍完毕,希望大家对ijkplayer结构有个大概印象,有时间再对各个模块做详细的介绍。
参考链接: