flutter进阶之封装ijkplayer使其支持rtsp播放

【原创不易,转载请注明出处:https://blog.csdn.net/email_jade/article/details/86650561】   

【20190222更新】

flutter_ijk 是flutter端的ijkplayer播放器,在IOS和Android native端都使用的是bilibili的ijkplayer,由于GitHub大小限制,本项目的ijkplayer源码放在https://gitee.com/jadennn/flutter_ijkplayer_source.git,已经定制过编译脚本和部分的功能代码,可以参考以下步骤来获取:

 1. ijkplayer的源码如下,支持ios和Android编译:

     编译步骤请查看源码根目录的readme.txt

     默认使用的是module-rtsp.sh,如果要增加配置,请修改此文件。

     ijkplayer源代码:

      https://gitee.com/jadennn/flutter_ijkplayer_source.git

 2. 对于Android ijk的编译,参考如下链接,请注意,使用上面的ijkplayer代码,不用再通过脚本重复下载ijkplayer了:

     a.配置jdk,sdk,ndk环境

     b.查看ijkplayer下的readme.txt,参考编译Android so库

     c.拷贝修复bug后的编译完成的so库替换flutter_ijk Android目录下的so库,注意的是多平台支持

     https://blog.csdn.net/coder_pig/article/details/79134625

  1. 对于IOS ijk的编译,参考如下链接,请注意,使用上面的ijkplayer代码,不用再通过脚本重复下载ijkplayer了:

    a. 配置环境

    b.查看ijkplayer下的readme.txt,编译ios代码

    c.制作framework(需要注意的是我的IJKMediaPlayer里面有一些关于CVPixelBufferRef的定制,都加了//add for flutter的注释,这些修改不能去掉)

    d.拷贝修复bug后的编译完成的IJKMediaFramework.framework替换flutter_ijk IOS目录下的IJKMediaFramework.framework库

    https://www.jianshu.com/p/3108c8a047ee

以上步骤可以得到ijkplayer在Android端的so库和IOS的framework文件,dart层见GitHub仓库。

    

【前言】

    项目中要用到rtsp视频流的播放,但是flutter原生播放器video_player不支持rtsp,因为原生播放器在安卓native采用的是EXOPlayer,而在IOS端采用的是AVPlayer,这两个播放器目前都不支持rtsp(可以自定义支持,但是video_player集成的版本不支持),因此必须自己来封装一个播放器,以便进行rtsp的播放。

      github地址 【https://github.com/jadennn/flutter_ijk】

    【正文】

    播放器的选择,因为之前做安卓项目用过ijkplayer,并且只要重新编译一下就可以支持rtsp了,因此,在Android和IOS的native层都采用的是ijkplayer。

    先放上效果图:

    

     首先来了解一下flutter的插件开发,就是利用平台通道在原生与flutter之间建立一个桥梁,以便在flutter中使用native的功能,具体见https://book.flutterchina.club/chapter11/platform-channel.html,所以插件的开发一般分为三个部分:native,flutter以及平台通道相关。由于平台通道部分比较简单,一般的插件都大同小异,我们本篇文章就着重讲一下ijkplayer的native和flutter部分。

    要使用ijkplayer并且支持rtsp,无论是Android还是IOS,都必须配置脚本重新编译,而在这之前,我们要先了解一下flutter的纹理渲染方式,也就是我们的视频怎么展示到屏幕上的,详见http://www.cocoachina.com/ios/20180926/25027.html,大意是说在flutter中采用的是OpenGL来进行渲染的,并且Android端和IOS端还是有一些差别的。对于Android而言,可以直接通过

TextureRegistry textures = registrar.textures();
TextureRegistry.SurfaceTextureEntry handle = textures.createSurfaceTexture();
Surface surface = new Surface(handle .surfaceTexture());

这样简单几步得到我们常见的surface,然后就可以直接将ijkplayer的视频流输出到surface上了。对于IOS而言,要渲染到屏幕上,系统提供了一个api:

@protocol FlutterTexture 
- (CVPixelBufferRef _Nullable)copyPixelBuffer;

因此我们需要得到ijkplayer的视频流CVPixelBufferRef,但是对于ios而言,ijkplayer并没有这样的接口,也就是说,我们需要去对ijkplayer做一些简单的修改,让我们能够直接获取CVPixelBufferRef流,这里参考的是ARVRSchool的三篇文章:

https://www.jianshu.com/p/8c8dceb86915

https://www.jianshu.com/p/852d7429897b

https://www.jianshu.com/p/1802b45ed612

    理清了Android和IOS对flutter的渲染方式后我们就可以着手修改编译ijkplayer了,要支持rtsp,首先要修改一下config下面的module脚本,建议基于module-lite.sh修改,这样编出来的库不至于太大,当然,除了rtsp,其他的协议格式或者编解码格式也是在module.sh里面修改配置的,如下:

##新增
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-demuxer=rtsp"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-demuxer=sdp"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-demuxer=rtp"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-protocol=tcp"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-protocol=udp"

##修改
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-protocol=rtp"

    Android端编译即可,IOS端,前文说到过,要修改源码,支持获取CVPixelBufferRef, 参考以上链接即可。

    有了Android和IOS的库然后可以开始ijkplayer flutter库的封装了,本代码参考的是官方库video_player进行封装的,值得注意的是,要保持Android和IOS native端接口的统一,因为它们最终都是通过平台通道映射到flutter中的,对于Android和IOS,ijkplayer的时间单位分别为ms和s, 这点尤其注意。为了提升rtsp的播放质量,在播放之前配置了一些ijkplayer的option,具体可以参考GitHub的源代码。

    由于本篇内容实在太多,很多细节只有在阅读代码的时候才能体现出来,因此就不再赘述了,详见https://github.com/jadennn/flutter_ijk 。

   当然,如果不想了解实现过程,想直接体验一下本文的库,参考如下步骤即可:

    1. 在pubspec.yaml中引用库:

  flutter_ijk:
    git:
      url: https://github.com/jadennn/flutter_ijk

    2. 使用:

class VideoPageState extends State {
  IjkPlayerController _controller;

  @override
  void initState(){
    super.initState();
      _controller = IjkPlayerController.network("rtsp://admin:[email protected]/h264/ch1/main/av_stream")
        ..initialize().then((_) {
          setState(() {});
          _controller.play();
        });
  }


  @override
  Widget build(BuildContext context) {
    return Material(
      child: _controller == null ? Container(): Center(
        child:
          _controller.value.initialized
              ? AspectRatio(
                  aspectRatio: _controller.value.aspectRatio,
                  child: IjkPlayer(_controller),
                )
              : Container(),
      ),
    );
  }
}

    详细接口api请阅读源码。

 

    flutter很好,路还很长,让我们一起奋斗前行!

 

    

你可能感兴趣的:(flutter,rtsp,ijkplayer,texture,flutter,plugin,flutter)