1. 程式人生 > >C#推流RTMP,攝像頭、麥克風、桌面、音效卡(附原始碼)

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個地方需要根據伺服器的配置自行做修改

  1. conf目錄下nginx.conf 檔案中 rtmp 埠 9000、http 埠8000 。
  2. html目錄下index.html 檔案中 設定流伺服器的IP
    src: "rtmp://192.168.1.56:9000/hls/"+pqs._parameters.id[0],    //將192.168.1.56改成流伺服器的IP
  3. 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 。