近期遇到項目,其中有在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);
}