隨著國際政治經濟形勢的變化,尤其是中美科技競爭日益激烈,軟體信創國產化已經迫在眉睫。在這種大環境下,我們將現有的Windows版軟體逐步遷移到信創國產化基礎設施上,適配國產作業系統(如銀河麒麟、統信UOS)、國信晶片(如飛騰、鯤鵬、海光、龍芯、麒麟)以及國產DB。
我們經常有這樣的需求,比如需要在銀河麒麟或統信UOS上實現RTMP推流攝像頭影片和麥克風聲音到流媒體伺服器(如nginx或srs),那麼這個要如何實現了?
一. 技術方案
要完成這個功能,具體來說,需要解決如下幾個技術問題:
(1)麥克風資料採集。
(2)攝像頭資料採集。
(3)音訊資料AAC編碼。
(4)影片資料H264編碼。
(5)將編碼後的資料按RTMP協議推送給流媒體伺服器。
(6)透過時間戳(PTS)保證音訊影片的同步。
我們使用跨平臺的 .NET Core (C#),跨平臺的UI框架Avalonia,再借助 LinuxCapture 和 NPusher.NetCore 這兩個元件,就很容易採集到麥克風和攝像頭的資料,並且將它們推流到流媒體伺服器上。
我們先看看推流程式在銀河麒麟上的執行效果:
兩個下拉選單可以選擇要使用的麥克風和攝像頭裝置。
點選“開始”按鈕,麥克風和攝像頭將開始採集資料,並推流至流媒體Server。
如果中途網路斷開,推流將會中斷,並嘗試自動重連,重連成功後,將恢復推流。
點選“結束”按鈕,則將結束音影片採集和推流。
二.具體實現
(1)ICameraCapturer是攝像頭影片採集元件;IMicrophoneCapturer是麥克風聲音採集元件。
(2)我們可以透過呼叫CapturerFactory的CreateXXXX方法來建立對應的採集器例項。
(3)得到採集器例項後,呼叫Start方法,即可開始採集;呼叫Stop方法,即停止採集。
(4)採集得到的資料,將透過相應的事件(ImageCaptured、AudioCaptured)暴露出來,我們預定這些事件,即可拿到採集的資料。
(5)將拿到的資料餵給IStreamPusher,就會將其推流到指定的流媒體伺服器。
我們這裡列一下核心程式碼,完整的程式碼大家可以從文末下載原始碼進行了解。
建立並啟動採集器:
//攝像頭採集器 this.cameraCapturer = CapturerFactory.CreateCameraCapturer(cameraIndex, videoSize, frameRate); this.cameraCapturer.ImageCaptured += CameraCapturer_ImageCaptured; this.cameraCapturer.CaptureError += CameraCapturer_CaptureError; //麥克風採集器 this.microphoneCapturer = CapturerFactory.CreateMicrophoneCapturer(micIndex); this.microphoneCapturer.AudioCaptured += MicrophoneCapturer_AudioCaptured; this.microphoneCapturer.CaptureError += MicrophoneCapturer_CaptureError; this.microphoneCapturer.Start(); this.cameraCapturer.Start();
建立並啟動推流器:
string nginxServerIP = ConfigurationManager.AppSettings["NginxServerIP"]; int nginxServerPort = int.Parse(ConfigurationManager.AppSettings["NginxServerPort"]); string rtmpUrl = $"rtmp://{nginxServerIP}:{nginxServerPort}/hls/{streamID}"; this.streamPusher.UpsideDown4RGB24 = true; this.streamPusher.Initialize(rtmpUrl, videoSize.Width, videoSize.Height, InputAudioDataType.PCM, InputVideoDataType.RGBA, this.channelCount);
將採集到的資料餵給推流器:
private void CameraCapturer_ImageCaptured(byte[] agba32Data) { if (this.isRecording) { this.streamPusher.PushVideoFrame(agba32Data); UiSafeInvoker.ActionOnUI(() => { WriteableBitmap writeableBitmap = CreateBitmapFromPixelData(agba32Data, videoSize.Width, videoSize.Height); img.Source = writeableBitmap; }); } } private void MicrophoneCapturer_AudioCaptured(byte[] pcm) { if (this.isRecording) { this.streamPusher.PushAudioFrame(pcm); } }
推流器內部會對音影片資料進行編碼,並依據RTMP協議傳送給流媒體伺服器。
停止推流:
private void FinishRecorded(bool success) { this.RecordState_Changed(false); this.cameraCapturer?.Stop(); this.cameraCapturer?.Dispose(); this.microphoneCapturer?.Stop(); this.microphoneCapturer?.Dispose(); this.streamPusher?.Close(); string tip = success ? "推流停止!" : "推流器斷開,推流停止!"; ShowStateMsg(tip); }
三. 部署執行
如果要在銀河麒麟或統信UOS上執行這裡的RTMP推流程式,則需要現在目標作業系統上安裝.NET Core 3.1。
然後將VS生成目錄下的 netcoreapp3.1 資料夾複製到目標電腦上,進入netcoreapp3.1資料夾,開啟終端,並在終端中輸入如下命令:
dotnet Oraycn_Avalonias_PusherDemo.Desktop.dll
回車執行後,就會出現前面截圖的UI介面,然後我們就可以預覽攝像頭,並開始推流麥克風攝像頭了。
四. 原始碼下載
Oraycn.Avalonias.PusherDemo.rar
原始碼中包含的非託管庫是X64架構的,如果需要在其它架構的國產晶片上執行該程式,可以聯絡我獲取對應架構的非託管庫。