移动平台播放器ijkplayer开源框架分析(以IOS源码为例)

时间:2024-03-24 18:17:27

    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开源框架分析(以IOS源码为例)

    现在我们开始分析播放器代码,主要函数调用顺序和主要线程开启位置见下图所示:

    移动平台播放器ijkplayer开源框架分析(以IOS源码为例)

     通过整理调用接口,需要弄得ijkplayer逻辑,我们需要注意一下几个点:自定义组件注册,消息循环,5个线程和ffpipeline,弄懂这些概念,逻辑结构基本清晰,想要按需修改自己的播放器也会游刃有余,下面我们大致介绍一下这几个点。

    自定义组件主要包括protocol和demuxer。协议有:ijkimp_ff_ijkio_protocolijkimp_ff_async_protocolijkimp_ff_ijktcphook_protocolijkimp_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结构有个大概印象,有时间再对各个模块做详细的介绍。

参考链接:

   https://blog.csdn.net/chenfteng/article/details/77775746