C#推流RTMP,攝像頭、麥克風、桌面、音效卡(附原始碼)
這段時間一直都在研究推流的技術,經過斷斷續續將近兩個月的摸索實踐,終於能穩定地推流了。
這個demo的主要功能就是將採集到的攝像頭或桌面的視訊、以及麥克風或音效卡的音訊資料推到Nginx-RTMP伺服器上,再由Web瀏覽器去拉流並播放。
接下來介紹Demo整個功能的實現原理和程式碼邏輯,大家可以從文末下載原始碼後,對照原始碼再來看下面的介紹就會更清晰些。
一.客戶端實現
客戶端的介面效果圖如下所示:
客戶端的具體功能:可以採集攝像頭或者桌面影象,也可以採集麥克風與音效卡的聲音 並將它們推送到Nginx流伺服器上。
從上面功能就可以看出這裡需要有多個採集器來採集相關的資料:攝像頭採集器、麥克風採集器、桌面採集器、以及音效卡採集器。如果需要將麥克風或音效卡的聲音混音(比如,主播一邊用電腦播放背景音樂一邊播講),則還需要使用混音器。
在點選啟動裝置按鈕時,我們就需要來啟動各自對應的採集器,並開始採集:
#region 設定採集器 if (this.radioButton_desktop.Checked) { //桌面採集器 //如果需要錄製滑鼠的操作,第二個引數請設定為true this.desktopCapturer = CapturerFactory.CreateDesktopCapturer(frameRate, false,new Rectangle(0,0,1920,1080)); this.desktopCapturer.ImageCaptured += this.Form1_ImageCaptured; } else if (this.radioButton_camera.Checked) { //攝像頭採集器 this.cameraCapturer = CapturerFactory.CreateCameraCapturer(0, this.defaultVideoSize, frameRate); this.cameraCapturer.ImageCaptured += new CbGeneric<Bitmap>(this.Form1_ImageCaptured); } if (this.checkBox_micro.Checked) { //麥克風採集器 this.microphoneCapturer = CapturerFactory.CreateMicrophoneCapturer(0); this.microphoneCapturer.CaptureError += new CbGeneric<Exception>(this.CaptureError); } if (this.checkBox_soundCard.Checked) { //音效卡採集器 【目前音效卡採集僅支援vista以及以上系統】揚聲器 屬性 高階設定 16位 48000HZ(DVD音質) this.soundcardCapturer = CapturerFactory.CreateSoundcardCapturer(); this.soundcardCapturer.CaptureError += this.CaptureError; if (this.soundcardCapturer.SampleRate != 48000) { throw new Exception("音效卡取樣率必須為48000HZ"); } audioSampleRate = this.soundcardCapturer.SampleRate; this.channelCount = this.soundcardCapturer.ChannelCount; } if (this.checkBox_micro.Checked && this.checkBox_soundCard.Checked) { //混音器 this.audioMixter = CapturerFactory.CreateAudioMixter(this.microphoneCapturer, this.soundcardCapturer, SoundcardMode4Mix.DoubleChannel, true); this.audioMixter.AudioMixed += audioMixter_AudioMixed; audioSampleRate = this.audioMixter.SampleRate; this.channelCount = this.audioMixter.ChannelCount; } else if (this.checkBox_micro.Checked) { this.microphoneCapturer.AudioCaptured += audioMixter_AudioMixed; } else if (this.checkBox_soundCard.Checked) { this.soundcardCapturer.AudioCaptured += audioMixter_AudioMixed; } #endregion #region //開始採集 if (this.checkBox_micro.Checked) { this.microphoneCapturer.Start(); } if (this.checkBox_soundCard.Checked) { this.soundcardCapturer.Start(); } if (this.radioButton_camera.Checked) { this.cameraCapturer.Start(); } else if (this.radioButton_desktop.Checked) { this.desktopCapturer.Start(); } #endregion
開始採集後,我們就可以點選開始推流按鈕,初始化推流器,將採集的資料推到流伺服器上:
//TODO 開始錄製桌面,依據 聲音複選框 來選擇使用 音效卡 麥克風 還是混合錄製, 影象複選框來選擇 影象的採集器 try { int videoWidth = 0, videoHeight = 0; if (this.radioButton_desktop.Checked) { videoWidth = this.desktopCapturer.VideoSize.Width; videoHeight = this.desktopCapturer.VideoSize.Height; } else { videoWidth = this.defaultVideoSize.Width; videoHeight = this.defaultVideoSize.Height; }this.streamPusher.UpsideDown4RGB24 = true; this.streamPusher.Initialize("192.168.1.56", 9000, true, this.streamID, videoWidth, videoHeight, NPusher.InputAudioDataType.PCM, NPusher.InputVideoDataType.RGB24,this.channelCount); this.isPushing = true; this.button_start.Enabled = false; this.button_stop.Enabled = true; this.button3.Enabled = false; this.ShowStateMsg("推流中..."); } catch (Exception ee) { MessageBox.Show(ee.Message); }
上述程式碼中紅色標記部分,即是初始化推流器:由於我們採集到的視訊是H264資料,聲音是PCM資料,所以,在初始化時,選擇InputAudioDataType.PCM和InputVideoDataType.RGB24。
在採集時我們預定了對應的採集事件,採集到資料後我們就加到推流器中,它會自動將資料推到我們的Nginx伺服器上:
//採集到的視訊或桌面影象 void Form1_ImageCaptured(Bitmap img) { if (this.radioButton_camera.Checked)//顯示攝像頭的影象到窗體 { Image copy = ESBasic.Helpers.ImageHelper.CopyImageDeeply(img); this.DisplayVideo(copy); } if (this.isPushing) { img.RotateFlip(RotateFlipType.Rotate180FlipY); byte[] data = ESBasic.Helpers.ImageHelper.GetRGB24CoreData(img); this.streamPusher.PushVideoFrame(data); } } //採集到的音效卡、麥克風、音效卡麥克風的混音資料 void audioMixter_AudioMixed(byte[] audioData) { if (this.isPushing) { if (this.checkBox_soundCard.Checked && !this.checkBox_micro.Checked) { audioData = AudioHelper.ConvertTo16kFrom48k(audioData ,this.channelCount); } this.streamPusher.PushAudioFrame(audioData); } }
程式碼中標記為紅色的部分PushVideoFrame和PushAudioFrame方法,即是將採集到的視訊幀和音訊幀推流到流伺服器。
二.Nginx服務端部署
這裡可以在文末網盤下載服務端來部署到伺服器上,其中有3個地方需要根據伺服器的配置自行做修改
- conf目錄下nginx.conf 檔案中 rtmp 埠 9000、http 埠8000 。
- html目錄下index.html 檔案中 設定流伺服器的IP
src: "rtmp://192.168.1.56:9000/hls/"+pqs._parameters.id[0], //將192.168.1.56改成流伺服器的IP
-
html目錄下mobile.html 檔案中 也同樣設定流伺服器的IP
var hls_url = "http://192.168.1.56:8000/hls/" + pqs._parameters.id[0] + ".m3u8"; //將192.168.1.56改成流伺服器的IP
三.瀏覽器訪問
PC的瀏覽器訪問 http://192.168.1.56:8000/?id=aa01,其中aa01為流的ID。效果如下圖
手機瀏覽器訪問 http://192.168.1.56:8000/mobile.html?id=aa01,其中aa01為流的ID。效果如下圖
四.原始碼下載
(1) C#推流RTMP(攝像頭、麥克風、桌面、音效卡)-原始碼
(2)Nginx部署版下載 網盤下載 (提取碼: 1234)
注:檢視Nginx執行狀態可訪問: http://192.168.1.56:8000/stat 。