关于流媒体开发的若干笔记

移动开发 来源:bbdlg 75℃ 0评论

近期遇到项目,其中有在Android平台播放rtsp流媒体的需求。整理若干资料如下,备查。

何谓流媒体

有别于传统的视频文件播放,流媒体是专门用于在网络上传输的,采用所谓的流式传输方式。

既然在网络上传输,就免不了有协议用来规定传输过程中的各个场景。流媒体的协议很多,经过前期选型,项目中采用了较为常用的RTSP协议。也曾经考虑过用RTMP协议,但考虑到RTSP的实时性要好于RTMP,更贴合项目需求,故而选择了RTSP。

百度百科的词条里介绍的比较清楚了,在决定开发之前,最好先通读一遍。

编码器、服务器与解码器

以近期火爆的直播为例,编码器是指流媒体的采集端,如美女主播用的手机APP、游戏直播用的PC端软件(如OBS)等。编码器将摄像头、屏幕或具体的视频文件,处理成流媒体特定的格式发往服务器。而项目中使用的则是专门的硬件编码器,作用是将HDMI传输的视频流编码成网络信号传给服务器。

服务器起到中转的作用,一方面接收编码器的推送,另一方面负责向单个或多个解码器分发视频流。当然,很多时候还会有存储功能。

解码器就是用来播放视频流的,如各类视频播放器。

常见的解决方案

VLCFFmpeg 是最为常用的开源跨平台的音视频流解决方案。live555是一个为流媒体提供解决方案的跨平台的C++开源项目,据说是为VLC提供了视频播放方案,由于没有官方的Android支持,故而未曾深入研究。

对编码器而言,常见的OBS可以支持win、mac、Linux三大平台,Android上有libstreaming,而iOS未曾深入研究。当然,还有前面提到的专门的编码器设备。

服务器的解决方案主要有(引自知乎李杨的回答

  • 流媒体解决方案 Live555 (C++)
  • 流媒体平台框架 EasyDarwin (C++,国产精品)
  • 实时流媒体播放服务器程序DarwinStreamingSrvr (C++)
  • Flash流媒体服务器 Red5 (Java)
  • 流媒体服务器 Open Streaming Server (Java)
  • FMS流媒体服务器 (Adobe,收费的)
  • Wowza流媒体服务器(Java)
  • 开源流媒体平台FreeCast(Java)
  • Nginx+RTMP插件(可以走走歪门邪道)

开放的直播平台也不失为一种快速解决方案,如目睹直播(亲测,无需认证或充值即可测试)、乐视云视频(资质认证一直未能通过)等。一些直播方面的知识也可从这些网站上获取。

国内的开发者平台,如阿里云的视频直播百度云的音视频直播LSS等,是无需自己捣腾服务器软件、而又可自主掌控直播的另一种途径。并且,作为开发者平台的产物,要比普通直播平台提供了更为开放的接口和扩展能力。

此外,mplayerffdshow 提供了开源的解码器方案,但相对复杂。vitamio支持Android和iOS,是国产媒体播放领域的翘楚。需要注意的是,vitamio对于企业商用是需要授权的,但官网提到的执行周期是14年底,也算是对混乱的国内知识产权领域的一种冷嘲吧。

使用vitamio播放rtsp遇到的问题

vitamio官网官方github 的版本较乱,但好在使用并不复杂。

从官网下载vitamio20160930.zip,加压后有InitActivityVitamioListActivity两个文件夹,后面这个目测用不到,在AndroidStudio中将前者引入成Module,并在原项目Module中增加InitActivity的依赖。

接下来的开发中遇到了些许问题,记录如下。

  • 无法固定外框大小
    单独的使用io.vov.vitamio.widget.VideoView插件,即使在xml中设置了高和宽,或者在代码中动态设置,均无法生效。下面是一个无效的例子:
<io.vov.vitamio.widget.VideoView   
  android:id="@+id/surface_view"   
  android:layout_width="280dp"  
  android:layout_height="210dp"  
  android:layout_centerHorizontal="true" 
  android:layout_centerVertical="true" />
  • 动态调整外框大小后无法正确显示
    网上一般的写法,是在io.vov.vitamio.widget.VideoView外面包裹一层io.vov.vitamio.widget.CenterLayout,这对于意图在代码中动态调整外框的需求是无效的。
    同时,记得在调整大小后,调用
    videoView.setVideoLayout(VideoView.VIDEO_LAYOUT_FIT_PARENT, 0);
    经过尝试,下面的做法是可行的:
<RelativeLayout
    android:padding="4dp"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:background="@drawable/bg_video">

    <io.vov.vitamio.widget.VideoView
        android:id="@+id/surface_view"
        android:layout_width="280dp"
        android:layout_height="210dp"
        android:layout_centerHorizontal="true"
        android:layout_centerVertical="true" />

</RelativeLayout>
  • 透屏及花屏问题
    项目中是在百度地图上层放置一个VideoView播放视频,而实际使用中发现,启动后,VideoView不显示;而将地图层先隐藏再手动显示后,会出现花屏现象,且显示极不清晰。
    网上介绍的两种方法在我的项目中并没能生效:

    1. vitamio插件的io.vov.vitamio.widget.VideoView.java
        152行 surfaceCreated函数,加入一行代码搞定
        mSurfaceHolder.setFormat(PixelFormat.RGBX_8888);
    2. AndroidManifest.xml文件中,播放器的Activity主题背景修改为
        android:theme="@android:style/Theme.Translucent.NoTitleBar.Fullscreen"

    据查,原因应该是VideoView启动后,默认至于最下层。
    修改VideoView.java源码,在initVideoView函数中任意地方增加如下代码即可:

    setZOrderOnTop(true);
  • 无法响应click事件
    项目需求是在VideoView上单击后变大,再次单击后返回原始状态。
    而setOnClickListener后,发现点击事件不会被触发。
    原因是VideoView.java中的onTouchEvent将事件“消化”掉了,修改即可。

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        if (isInPlaybackState() && mMediaController != null)
            toggleMediaControlsVisiblity();
        //return false;
        return super.onTouchEvent(ev);
    }