这段时间一直都在研究推流的技术,经过断断续续将近两个月的摸索实践,终于能稳定地推流了。
这个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 。
转自:https://www.cnblogs.com/zhuweisky/p/14024966.html