Android之音視訊點、直播模組開發
隨著音視訊領域的火熱,在很多領域(教育,遊戲,娛樂,體育,跑步,餐飲,音樂等)嘗試做音視訊直播、點播功能,那麼,如何快速學習音視訊基礎知識,瞭解音視訊編解碼的傳輸協議,編解碼方式,以及如何技術選型,如何解決遇到的難題呢,下面來看看,歡迎大咖交流。
一. 音視訊的基礎知識
1.1 基本概念
視訊是什麼
<code class="hljs mel has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">靜止的畫面叫影象(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">picture</span>)。連續的影象變化每秒超過<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">24</span>幀(frame)畫面以上時,根椐視覺暫留原理, 人眼無法辨別每付單獨的靜態畫面,看上去是平滑連續的視覺效果。這樣的連續畫面叫視訊。 當連續影象變化每秒低於<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">24</span>幀畫面時,人眼有不連續的感覺叫動畫(cartoon)</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li></ul>
流媒體
<code class="hljs has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">指採用流式傳輸的方式在Internet / Intranet播放的媒體格式.流媒體的資料流隨時傳送隨 時播放,只是在開始時有些延遲 邊下載邊播入的流式傳輸方式不僅使啟動延時大幅度地縮短,而且對系統快取容量的需求也大大降低,極大地減少使用者用在等待的時間</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li></ul>
解析度
<code class="hljs has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">解析度是一個表示平面圖像精細程度的概念,通常它是以橫向和縱向點的數量來衡量的,表示成水平點數垂直點數的形式, 在計算機顯示領域我們也表示成“每英寸畫素”(ppi).在一個固定的平面內,解析度越高,意味著可使用的點數越多,影象越細緻</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li></ul>
碼流
<code class="hljs has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"> 資料傳輸時單位時間傳送的資料位數,可以理解其為取樣率,單位時間內取樣率越大,精度就越高,處理出來的檔案就越接近原始檔案,但是檔案體積與取樣率是成正比的 如何用最低的位元速率達到最少的失真,一般我們用的單位是kbps即千位每秒</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li></ul>
幀率
<code class="hljs livecodeserver has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">幀/秒(frames per <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">second</span>)的縮寫,也稱為幀速率,測量用於儲存、顯示動態視訊的資訊數量。每一幀都是靜止的圖象,快速連續地顯示幀便形成了運動的假象。 每秒鐘幀數 (fps) 愈多,所顯示的動作就會愈流暢,可理解為<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>秒鐘時間裡重新整理的圖片的幀數,也可以理解為圖形處理器每秒鐘能夠重新整理幾次,也就是指每秒鐘能夠播放(或者錄製)多少格畫面。</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li></ul>
1.2 多媒體的格式分類
封裝格式(專業上講叫容器,通俗的叫檔案格式),視訊編解碼,音訊編解碼
####1.1常見的封裝格式
* MPEG : 編碼採用的容器,具有流的特性。裡面又分為 PS,TS 等,PS 主要用於 DVD 儲存,TS 主要用於 HDTV.
* MPEG Audio Layer 3 :大名鼎鼎的 MP3,已經成為網路音訊的主流格式,能在 128kbps 的位元速率接近 CD 音質
* MPEG-4(Mp4) : 編碼採用的容器,基於 QuickTime MOV 開發,具有許多先進特性;實際上是對Apple公司開發的MOV格式(也稱Quicktime格式)的一種改進.
* MKV: 它能把 Windows Media Video,RealVideo,MPEG-4 等視訊音訊融為一個檔案,而且支援多音軌,支援章節字幕等;開源的容器格式
* 3GP : 3GPP視訊採用的格式, 主要用於流媒體傳送;3GP其實是MP4格式的一種簡化版本,是手機視訊格式的絕對主流.
* MOV : QuickTime 的容器,恐怕也是現今最強大的容器,甚至支援虛擬現實技術,Java等,它的變種 MP4,3GP都沒有這麼厲害;廣泛應用於Mac OS作業系統,在Windows作業系統上也可相容,但是遠比不上AVI格式流行
* AVI : 最常見的音訊視訊容器,音訊視訊交錯(Audio Video Interleaved)允許視訊和音訊交錯在一起同步播放.
* WAV : 一種音訊容器,大家常說的 WAV 就是沒有壓縮的 PCM 編碼,其實 WAV 裡面還可以包括 MP3 等其他 ACM 壓縮編碼
等等
1.3 流媒體協議(RTP RTCP RTSP RTMP HLS)
- RTP RTCP RTSP
- RTMP
- HLS
二. android音視訊的開發
播放流程: 獲取流–>解碼–>播放
錄製播放路程: 錄製音訊視訊–>剪輯–>編碼–>上傳伺服器 別人播放.
直播過程 : 錄製音視訊–>編碼–>流媒體傳輸–>伺服器—>流媒體傳輸到其他app–>解碼–>播放
幾個重要的環節
- 錄製音視訊 AudioRecord/MediaRecord
- 視訊剪輯 mp4parser 或ffmpeg
- 音視訊編碼 aac&h264
- 上傳大檔案 網路框架,進度監聽,斷點續傳
- 流媒體傳輸 流媒體傳輸協議rtmp rtsp hls
- 音視訊解碼 aac&h264
- 渲染播放 MediaPlayer
問題
Android本身有提供MediaPlayer,那麼mediaplayer支援哪些格式的流媒體協議吶?又支援哪些解碼器吶?相容性如何,性功能如何?
Supported Media Formats
Media Playback
MPEG-2:制定於1994年,設計目標為高階工業標準的影象質量以及更高的傳輸率。這種格式主要應用在DVD/SVCD的製作(壓縮)方面,同時在一些HDTV(高清晰電視廣播)和一些高要求視訊編輯、處理上面也有相當的應用。使用MPEG-2的壓縮演算法,可以把一部120分鐘長的電影壓縮到4到8GB的大小。這種視訊格式的副檔名包括.mpg、.mpe、.mpeg、.m2v及DVD光碟上的.vob檔案等。MPEG-4:制定於1998年,MPEG-4是為了播放流式媒體的高質量視訊而專門設計的,它可利用很窄的頻寬,通過幀重建技術,壓縮和傳輸資料,以求使用最少的資料獲得最佳的影象質量。目前MPEG-4最有吸引力的地方在於它能夠儲存接近於DVD畫質的小體積視訊檔案。另外,這種檔案格式還包含了以前MPEG壓縮標準所不具備的位元率的可伸縮性、動畫精靈、互動性甚至版權保護等一些特殊功能。這種視訊格式的副檔名包括.asf、.mov和DivX
AVI等。
從上圖我們也看到,android平臺自身支援的音視訊解碼是有限的 一般的mp3 mp4….3gp 等等 其他的只能自己解碼了。。。
那麼如何解碼吶?
經過一番調研對比,選擇樂ijkplayer.
三. ijkplayer的引入&介紹&使用
正如上文所說,android本事對音視訊流媒體傳輸協議,以及音視訊編解碼支援有限.所以對於直播類應用,要自己解碼
3.1 調研過程
先說下 vitamio這個是功能很強大,但是企業收費版的,個人使用者可以玩玩.
目前WebRtc只適合小範圍(8人以內)音視訊會議,不適合做直播可以用WebRTC來做視訊直播嗎?
接下來介紹下 ffmpeg vlc ijkplayer以及選擇方案
ffmpeg是一個非常強大的音視訊編解碼開源庫,目前市場上流行的播放器,大部分都是基於此開發的,包括暴風,騰訊,等等以及上面提到的vitamio,vlc,ijkplayer
關於ffmpeg原始碼分析,有興趣的請看雷霄驊(leixiaohua1020)的專欄
vlc 支援android開發 ,ijkplayer也支援. 通過反編譯網易雲音樂,以及YY等音視訊app.發現網易雲音樂,鬥魚用的ijkplayer,YY用的VLC.
那麼vlc&ijkplayer相比較各有什麼優缺點吶,該如何選擇吶?[待深入使用,或者用過的可以交流下]
其實這個沒有深入分析,ijkplayer是bilibili開源的音視訊編解碼庫,對android,iOS進行和很好的抽取封裝,易於編譯使用.vlc嘗試過,稍微複雜些.
3.2 ijkplayer的匯入&編譯&使用
如果不需要對原始碼進行修改,在app的build.gradle中加入如下依賴即可
dependencies {
# required, enough for most devices.
compile 'tv.danmaku.ijk.media:ijkplayer-java:0.4.5.1'
compile 'tv.danmaku.ijk.media:ijkplayer-armv7a:0.4.5.1'
# Other ABIs: optional
compile 'tv.danmaku.ijk.media:ijkplayer-armv5:0.4.5.1'
compile 'tv.danmaku.ijk.media:ijkplayer-arm64:0.4.5.1'
compile 'tv.danmaku.ijk.media:ijkplayer-x86:0.4.5.1'
# ExoPlayer as IMediaPlayer: optional, experimental
compile 'tv.danmaku.ijk.media:ijkplayer-exo:0.4.5.1'
}
當然如何你想對其原始碼進行修改,採用如下方式
1. 需要
下載配置 NDK r10e
配置androidsdk
# add these lines to your ~/.bash_profile or ~/.profile
# export ANDROID_SDK=
# export ANDROID_NDK=
2.
Build Android
git clone https://github.com/Bilibili/ijkplayer.git ijkplayer-android
cd ijkplayer-android
git checkout -B latest k0.4.5.1
./init-android.sh //此步用於下載ffmpeg,初始化配置
cd android/contrib
./compile-ffmpeg.sh clean
./compile-ffmpeg.sh all
cd ..
./compile-ijk.sh all
然後通過androidstudio把生成的project匯入工程
# Android Studio:
# Open an existing Android Studio project
# Select android/ijkplayer/ and import
可以根據需要對音視訊編解碼庫進行裁剪.編譯出最小的滿足需要的庫
bilibili提供三種裁剪方式
If you prefer more codec/format
cd config
rm module.sh
ln -s module-default.sh module.sh
cd android/contrib
sh compile-ffmpeg clean
If you prefer less codec/format for smaller binary size (include hevc function)
cd config
rm module.sh
ln -s module-lite-hevc.sh module.sh
cd android/contrib
sh compile-ffmpeg clean
If you prefer less codec/format for smaller binary size (by default)
cd config
rm module.sh
ln -s module-lite.sh module.sh
cd android/contrib
sh compile-ffmpeg clean
當然也可以根據需要自己裁剪.
我們來看下ijkplayer/config/module-lite.sh 即default裁剪模式支援哪些編解碼方式
我們可以看到
export COMMON_FF_CFG_FLAGS=”COMMONFFCFGFLAGS–enable−demuxer=hls”exportCOMMONFFCFGFLAGS=”COMMON_FF_CFG_FLAGS
–enable-parser=aac”
export COMMON_FF_CFG_FLAGS=”COMMONFFCFGFLAGS–enable−parser=h264”exportCOMMONFFCFGFLAGS=”COMMON_FF_CFG_FLAGS
–disable-protocol=rtp”
export COMMON_FF_CFG_FLAGS=”$COMMON_FF_CFG_FLAGS –enable-protocol=rtmp”
四. ijkplayer的java層原始碼分析
【先佔坑,接下來詳解】
五. 專案中ijkplayer的封裝以及mediaview的封裝以及使用
【先佔坑,接下來詳解】
六. ijkplayer底層學習
【先佔坑,接下來重點學習】
七. 開源專案
【接下來仿網易雲音樂,寫一個開源專案,歡迎多多關注】
七. 常見問題以及解決方案
- 全屏播放
- 有時候會開始直播時出現黑屏
- 有時候會出現花屏
- 解碼方式設定
- 如何區分點播直播
- 是否需要開啟硬體加速
- 如何設定後臺播放
- 視訊載入速度慢
The traffic speed is mostly depending on the quality of video CDN, not player itself. - 怎麼靜音 和非靜音
mute/unmute system volume.There is no mute/unmute API in ijkplayer. - 視訊黑屏,但是有聲音
確定下視訊源的編碼方式,ijk預設只帶了h264解碼code - 適配問題,對於不同的cpu架構,需要編譯不同的so庫
- 播放視訊有的裝置聲畫不同步
- 如何檢視m3u8時長
cat game05.m3u8 | grep EXTINF | wc -l 32 - how to change the video quality?
Video quality is determined when being encoded.I don’t think it can be changed by player. - 倍速播放
Not until Android 6.0 - 為什麼往前拖動進度條後,還會往後退幾秒
seek只支援關鍵幀,出現這個情況就是原始的視訊檔案中i 幀比較少,播放器會在拖動的位置找最近的關鍵幀。 - how to change URL when ijkplayer is playing RTMP video
Create new player. - 怎樣新增字幕呢?
如果希望字幕時間精確,可以在native層做解析和時間同步,到了時間後回撥給java層,一般字幕檔案載入都是在java層做的,解析檔案格式,然後按照時間區間來顯示。 - 如何設定硬解?
ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, “mediacodec”, 1);
ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "http-detect-range-support", 0);
ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "overlay-format", IjkMediaPlayer.SDL_FCC_RV32);
ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "analyzeduration", "2000000");
ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "probsize", "4096");
ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_CODEC, "skip_loop_filter", 0);