這段時間一直都在研究推流的技術,經過斷斷續續將近兩個月的摸索實踐,終於能穩定地推流了。
這個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 。
