关于流媒体开发的若干笔记
近期遇到项目,其中有在Android平台播放rtsp流媒体的需求。整理若干资料如下,备查。
何谓流媒体
有别于传统的视频文件播放,流媒体是专门用于在网络上传输的,采用所谓的流式传输方式。
既然在网络上传输,就免不了有协议用来规定传输过程中的各个场景。流媒体的协议很多,经过前期选型,项目中采用了较为常用的RTSP协议。也曾经考虑过用RTMP协议,但考虑到RTSP的实时性要好于RTMP,更贴合项目需求,故而选择了RTSP。
百度百科的词条里介绍的比较清楚了,在决定开发之前,最好先通读一遍。
编码器、服务器与解码器
以近期火爆的直播为例,编码器是指流媒体的采集端,如美女主播用的手机APP、游戏直播用的PC端软件(如OBS)等。编码器将摄像头、屏幕或具体的视频文件,处理成流媒体特定的格式发往服务器。而项目中使用的则是专门的硬件编码器,作用是将HDMI传输的视频流编码成网络信号传给服务器。
服务器起到中转的作用,一方面接收编码器的推送,另一方面负责向单个或多个解码器分发视频流。当然,很多时候还会有存储功能。
解码器就是用来播放视频流的,如各类视频播放器。
常见的解决方案
VLC 和 FFmpeg 是最为常用的开源跨平台的音视频流解决方案。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等,是无需自己捣腾服务器软件、而又可自主掌控直播的另一种途径。并且,作为开发者平台的产物,要比普通直播平台提供了更为开放的接口和扩展能力。
此外,mplayer、ffdshow 提供了开源的解码器方案,但相对复杂。vitamio支持Android和iOS,是国产媒体播放领域的翘楚。需要注意的是,vitamio对于企业商用是需要授权的,但官网提到的执行周期是14年底,也算是对混乱的国内知识产权领域的一种冷嘲吧。
使用vitamio播放rtsp遇到的问题
vitamio官网 和 官方github 的版本较乱,但好在使用并不复杂。
从官网下载vitamio20160930.zip,加压后有InitActivity和VitamioListActivity两个文件夹,后面这个目测用不到,在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);
}