0.引言
本篇文章主要講解RTSP推流實戰,整體推流流程與RTMP推流流程類似。如果對於RTSP協議不瞭解,還可以參考前面的文章。文章參考列表如下:
1.專案環境準備和演示
先準備好環境,準備好YUV檔案和PCM檔案。
執行如下命令:
(1)從檔案提取pcm資料
ffmpeg -i a.mp3 -ar 48000 -ac 2 -f s16le 48000_2_s16le.pcm
(2)從檔案提取yuv資料
ffmpeg -i b.mp4 -an -c:v rawvideo -pix_fmt yuv420p 720x480_25fps_420p.yuv
(3)將檔案複製到如下目錄:
(4)伺服器使用EasyDarwin,僅僅當做測試使用。伺服器上推流的列印,推流的過程描述。
(5)ffplay拉流測試命令:
ffplay -i rtsp://192.168.129.48/live/livestream
本地預覽與拉流顯示對比。
2.整體框架分析
音影片採集模組,經過採集後有資料就使用回撥函式去呼叫音影片編碼模組,音影片編碼後首先就要放到佇列,可以放到同一個佇列或不同的佇列。rtsp推流模組從佇列裡面去取資料。其框圖和資料結構如下:
AudioCapture---->PcmCallback----->AACEncoder
------->post到佇列------->RTSP_Pusher
VideoCapture----->YuvCallback------->H264Encoder
3.音影片採集
音影片採集都是獨立的執行緒。CommonLooper實現一個執行緒的Looper。AudioCaptuer和VideoCapturer都會去繼承CommonLooper。
(1).模擬的採集,是實時,按照播放速度去讀取yuv/pcm資料。
(2).每幀資料都需要打上時間戳。重新封裝了一個類,專門去打時間戳。
PushWork是一個開放個使用者的類,由使用者去設定引數等操作。引數類,使用key-value的方式去做。
(3)讀取pcm資料,音訊採集完資料後,透過回撥函式callback_get_pcm_(pcm_buf_, nb_samples *4)傳送出去。如下程式碼:
4.重取樣
如果麥克風採集的聲音的輸出格式和編碼音訊的輸入引數不一致(音訊解碼和音訊播放不一致,也需要做重取樣),那就需要做重取樣。
(1)音訊編碼引數設定,如下程式碼:
(2)影片引數設定,如下程式碼:
(3)初始化影片編碼器引數設定,如下程式碼:
這裡的rtsp_debug設定為1,表示可以開啟預覽。
properties.SetProperty("rtsp_debug", 1)
(4)使用SDL開啟預覽,如下程式碼:
(5)讀取使用者設定的音影片引數,如下程式碼:
5.影片編碼類H264Encoder
如果影片間隔不勻稱,波動比較大,這裡就做了一個幀間隔的校正演算法,讓幀間隔勻稱。
(1)啟動rtsp推流模組,並做初始化,如下程式碼:
(2)rtsp推流的時候,需要設定對應的音影片編碼引數。如下:
為了防止連線時堵塞,開啟連線超時機制。假如伺服器卡死或斷開,這個時候推流模組去連線就會堵住。所以要使用超時斷開重連機制。
注意:在前面專門講最佳化的文章分析過,為了節省時間,在初始化順序,一定是首先初始化推流模組開啟網路連線,因為網路比較比較耗時,可能會導致資料幀的快取。具體原因可以看看前面講最佳化的文章。音影片的捕獲是放在最後面。如下順序:
(3)設定和開啟音訊捕獲,並設定回撥,把捕獲的資料傳送給音訊編碼器。如下圖:
(4)在音訊採集的回撥函式中開啟開啟編碼。如下程式碼:
注意:ffmpeg 內建的aac編碼器,需要的格式都是float的 planar的格式。
(5)設定和開啟影片捕獲,並設定回撥,把捕獲的資料傳送給影片編碼器。如下程式碼:
(6)在影片採集的回撥函式中開啟開啟編碼。如下程式碼:
注意:音影片採集回來就一定要去讀取時間戳。
(7)編碼後的音影片放到同一個佇列,需要標記是音訊包還是影片包。如下:
這裡的推流模組rtsp_pusher,就會開一個執行緒,迴圈去推送。
(8)呼叫RTSPPusher::sendPacket(AVPacket *packet, RTSPMediaType_T mediatype)去傳送資料。如下:
(9)關閉推流的流程,一般都是與初始化相反。關閉流程如下:
音訊的capture->音訊reseample->音訊encoder->音訊pusher。
影片的capture->影片reseample->影片encoder->影片pusher。
6.總結