ijkplayer框架的集成( 从开始到优化秒开)

 

ijkplayer是bibiliB站开源的一个三方,面向对象开发。

苹果提供了:AVPlayer播放不了直播文件。需要自己去基于ffmpeg播放。

ijkplayer框架是专门用来做 视频直播 的开源框架,基于ffmpeg,同时支持 Android 和 iOS 平台。
对于 App 中的直播功能,集成ijkplayer ,那么就算完成一半的工程了。接下来,只要获取到 拉流 URL,就能实现视频直播功能。
本文针对ios端编译流程安卓参考流程大体一样,提出跨平台优化方案。
1.  github (https://www.githubs.cn/) 搜索查找 

 

 

 

 

2.克隆ijkplayer到桌面 
 cd Desktop/
 git clone https://github.com/Bilibili/ijkplayer.git ijkplayer

或者直接下载zip.解压,切到解压的文件夹内

 

(请忽略背景😂,年轻时候弄得电脑。)

 

打开 IJKMediaDemo,并编译

提示: 'libavformat/avformat.h' file not found

 
查看 ijkplayer 的 README.md。
原因libavformat 是 ffmpeg 框架中的库,而 ijkplayer 又是基于 ffmpeg 框架的,因此需要编译 ffmpeg

3.下载ffmpeg

 cd ijkplayer

git checkout -B latest k0.8.8 ./init-ios.sh (下载ffmpeg)

注:下载最好使用FQ软件,本人使用蓝灯设置全局代理。下载很快,否则容易失败。

要下载一会,下载完成之后,在ios目录下就有了ffmpeg文件:

这时候我们的 ffmpeg 就下载好了,再次运行 IJKMediaDemo

发现还是报上面的错误,因为执行init-ios.sh,只是下载ffmpeg源码,但是源码并没有参与编译,需要把源码编译成.a文件:

4、编译 ffmpeg 库

进入 ios 文件的目录中

cd ios 
./compile-ffmpeg.sh clean
./compile-ffmpeg.sh all

注:1.执行 ./compile-ffmpeg.sh clean ,目的是删除一些文件和文件夹,为编译ffmpeg.sh做准备,在编译ffmpeg.sh的时候,会自动创建刚刚

删除的那些文件,为避免文件名冲突,因此在编译ffmpeg.sh之前先删除等会会自动创建的文件夹或者文件

      2.执行 ./compile-ffmpeg.sh all 目的是编译各个平台的ffmpeg库,并生成所以平台的通用库。      

可能遇到的问题:

warning: optimization flag '-fomit-frame-pointer' is not supported for target 'armv7' [-Wignored-optimization-argument]

AS libavcodec/arm/aacpsdsp_neon.o

./libavutil/arm/asm.S:50:9: error: unknown directive

        .arch armv7-a

        ^

make: *** [libavcodec/arm/aacpsdsp_neon.o] Error 1

make: *** Waiting for unfinished jobs....

 不支持arm7

 那么删除这个编译目标

 解决办法:

打开ios目录下这个 compile-ffmpeg.sh  文件

第24行 改为: FF_ALL_ARCHS_IOS8_SDK="arm64 i386 x86_64"

第120行 改为: if [ "$FF_TARGET" = "armv7s" -o "$FF_TARGET" = "arm64" ]; then

第159行 改为: echo " compile-ffmpeg.sh arm64|i386|x86_64"

其问题参考 https://www.jianshu.com/p/8668b38a629e

5.这时候编译成功已经可以运行列子了

如需打包framework参考:文章三

ijkplayer - 拓展:

6.优化加速

延迟优化

发现拉流存在3-6秒延迟,这个根据七牛直播云大牛讲解的一些问题点。进行优化。 

丢包处理方案参考

a),有音频流和视频流,或者只有音频流情况下,当audioq达到一定的duration,就丢掉前面一部分数据包,因为默认是AV_SYNC_AUDIO_MASTER,视频会追上来。
b),只有视频流情况,当videoq达到一定的duration,就丢掉前面一部分数据包。

 

开始本人修改丢失帧数过大,虽然延迟不存在了,但是同时测试局域网出现供不应求现象,就是画面过一混会卡顿。因此还是修改缓存时间比较好。

ff_ffplay.c read_thread 线程中,在每次 av_read_frame后去判断缓存队列有没有达到最大时长。这里需要把原来的realtime设置为0。

别的不说直接上代码

通过修改源文件,因为ijkplayer实际上是基于ffplay.c实现的: 
ijkmedia>ijkplayer>ff_ffplay.c这个文件

 

static double vp_duration(VideoState *is, Frame *vp, Frame *nextvp) {
    if(vp->serial == nextvp->serial) {
        doubleduration = nextvp->pts - vp->pts;
    if(isnan(duration) || duration <=0|| duration > is->max_frame_duration)
        return vp->duration;
      else
       return duration;
   }else{
    return 0.0;
  }
}

改成直接返回duration

static double vp_duration(VideoState*is,Frame*vp,Frame*nextvp) {
     return vp->duration;
}

接着改staticintffplay_video_thread这个方法:

static int ffplay_video_thread(void*arg){
    FFPlayer*ffp = arg;
    VideoState*is = ffp->is;
    AVFrame*frame =av_frame_alloc();
    doublepts;
    doubleduration;
    intret;
    AVRationaltb = is->video_st->time_base;
    //注释如下一行代码
    //AVRational frame_rate = av_guess_frame_rate(is->ic, is->video_st, NULL);

    //......省略部分代码

    //注释如下一行代码
    //duration = (frame_rate.num && frame_rate.den ? av_q2d((AVRational)  {frame_rate.den, frame_rate.num}) : 0);
    //直接这里写出
    duration=0.01;

   //........
}

延迟明显降低,高分辨率开启硬解码,不支持的话会自动切换到软解,就算开启mediacodec,如果设备不支持,显示的解码器也是avcodec软解

参数配合设置如下(由于c码,安卓苹果参数基本一样)

修改后基本延迟很低了1秒左右。然后

直接上修改后的代码参数配合编译的包

    
  //播放前的探测Size,默认是1M, 改小一点会出画面更快
  [options setFormatOptionIntValue:1024 * 16 forKey:@"probesize"];
  //播放前的探测时间
  [options setFormatOptionIntValue:50000 forKey:@"analyzeduration"];
  //默认好像是硬解开启软解
  [options setPlayerOptionIntValue:0 forKey:@"videotoolbox"];
  //解码参数,画面更清晰
  [options setCodecOptionIntValue:IJK_AVDISCARD_DEFAULT forKey:@"skip_loop_filter"];
  //这个目前理解应该是丢帧数设置
  [options setCodecOptionIntValue:IJK_AVDISCARD_DEFAULT forKey:@"skip_frame"];
  [options setPlayerOptionIntValue:3000 forKey:@"max_cached_duration"];   // 最大缓存大小是3秒,可以依据自己的需求修改
  [options setPlayerOptionIntValue:1 forKey:@"infbuf"];  // 无限读
  [options setPlayerOptionIntValue:0 forKey:@"packet-buffering"];  //  关闭播放器缓冲
    

7.如此设置已经基本可以实现0延迟播放了。

集成到自己项目见:
ijkplayer - 拓展:之打包framwork

其他一些优化本人也做了一些尝试。详情见下篇。

ijkplayer的一些优化

安卓端本人根据参数翻译代码设置如下:

ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "probesize", 1024 * 16);
ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "analyzeduration", 50000);
ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_CODEC, "skip_loop_filter", 0);
ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_CODEC, "skip_frame", 0);
ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "max_cached_duration", 3000);
ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "infbuf", 1);
ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "packet-buffering", 0);
  

 

另外如果是后台播放可以参考改变设置

// Param for playback
//ios
[options setPlayerOptionIntValue:0 forKey:@"max_cached_duration"]; [options setPlayerOptionIntValue:0 forKey:@"infbuf"]; [options setPlayerOptionIntValue:1 forKey:@"packet-buffering"];
//android
ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "max_cached_duration", 0); ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "infbuf", 0);
ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "packet-buffering", 1);

另外一些其他参数参考定义如下,跟据需要修改。

//开启硬件解码
[options setPlayerOptionIntValue:1 forKey:@"videotoolbox"];

// 设置音量大小,256为标准音量。(要设置成两倍音量时则输入512,依此类推)
[options setPlayerOptionIntValue:512 forKey:@"vol"];

// 最大fps
[options setPlayerOptionIntValue:30 forKey:@"max-fps"];

// 跳帧开关,如果cpu解码能力不足,可以设置成5,否则
// 会引起音视频不同步,也可以通过设置它来跳帧达到倍速播放
[options setPlayerOptionIntValue:0 forKey:@"framedrop"];

// 指定最大宽度,我没试过
[options setPlayerOptionIntValue:960 forKey:@"videotoolbox-max-frame-width"];

// 自动转屏开关,我没试过
[options setFormatOptionIntValue:0 forKey:@"auto_convert"];

// 重连次数, 我没试过
[options setFormatOptionIntValue:1 forKey:@"reconnect"];

// 超时时间,timeout参数只对http设置有效,若果你用rtmp设置timeout,ijkplayer内部会忽略timeout参数。rtmp的timeout参数含义和http的不一样。
[options setFormatOptionIntValue:30 * 1000 * 1000 forKey:@"timeout"];

// 帧速率(fps)  我没试过(可以改,确认非标准桢率会导致音画不同步,所以只能设定为15或者29.97)
[options setPlayerOptionIntValue:29.97 forKey:@"r"];

Note: 这里有个比较有用的参数,skip_loop_filter

// for codec option 'skip_loop_filter' and 'skip_frame'
typedef enum IJKAVDiscard {
    /* We leave some space between them for extensions (drop some
     * keyframes for intra-only or drop just some bidir frames). */
    IJK_AVDISCARD_NONE    =-16, ///< discard nothing
    IJK_AVDISCARD_DEFAULT =  0, ///< discard useless packets like 0 size packets in avi
    IJK_AVDISCARD_NONREF  =  8, ///< discard all non reference
    IJK_AVDISCARD_BIDIR   = 16, ///< discard all bidirectional frames
    IJK_AVDISCARD_NONKEY  = 32, ///< discard all frames except keyframes
    IJK_AVDISCARD_ALL     = 48, ///< discard all
} IJKAVDiscard;

前面两个都看得懂
第三个是抛弃非参考帧(I帧)
第四个是抛弃B帧
第五个是抛弃除关键帧以外的,比如B,P帧
第六个是抛弃所有的帧,这我就奇怪了,之前Android默认的就是48,难道把所有帧都丢了?
那就没有视频帧了, 所以应该不是这么理解,
应该是skip_loop_filter和skip_frame的对象要过滤哪些帧类型。

skip_loop_filter这个是解码的一个参数,叫环路滤波,
设置成48和0,图像清晰度对比,0比48清楚,理解起来就是,
0是开启了环路滤波,过滤的是大部分,
而48基本没启用环路滤波,所以清晰度更低,但是解码性能开销小

skip_loop_filter(环路滤波)简言之:
a:环路滤波器可以保证不同水平的图像质量。
b:环路滤波器更能增加视频流的主客观质量,同时降低解码器的复杂度。
具体参考:
http://blog.csdn.net/h514434485/article/details/52241778
http://www.cnblogs.com/TaigaCon/p/5500110.html
skip_frame我没完全理解意思,应该是等同上面这个类似。

另外安卓参数基本一样
接口不同而已,注意属性的分类
eg:OPT_CATEGORY_PLAYER
//可以打开h265硬解;
ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "mediacodec-hevc", 1);

//开启mediacodec硬解
ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "mediacodec", 1);
ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "mediacodec-auto-rotate", 1);
ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "mediacodec-handle-resolution-change", 1);
 


 下篇

ijkplayer的一些优化

 

参考前人经验更新

轮子使用中

1、https://blog.csdn.net/ssy_1992/article/details/79191727    //编译流程

或 https://www.jianshu.com/p/9a69af13835e 

注意FQ下载编译。

2、优化

https://mp.weixin.qq.com/s?__biz=MjM5NzAwNDI4Mg==&mid=2652193023&idx=1&sn=d01045267be48621ac93c145af46cd53&chksm=bd01766a8a76ff7cd9e1e1994f5db2dab53560c44579b3bfef14a32bf638245b28de1405b026&scene=21#wechat_redirect

 


 

 

觉得有用的同学点个关注,或者留言评论区,看到邮件提示消息尽快回复。

 

 

posted @ 2020-04-21 15:48  M·emor·Y  阅读(10029)  评论(4编辑  收藏  举报