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。效果如下图

C#推流RTMP,摄像头、麦克风、桌面、声卡(附源码)的更多相关文章
- 构建ASP.NET MVC4+EF5+EasyUI+Unity2.x注入的后台管理系统(2)-easyui构建前端页面框架[附源码]
原文:构建ASP.NET MVC4+EF5+EasyUI+Unity2.x注入的后台管理系统(2)-easyui构建前端页面框架[附源码] 开始,我们有了一系列的解决方案,我们将动手搭建新系统吧. 用 ...
- 为SRS流媒体服务器添加HLS加密功能(附源码)
为SRS流媒体服务器添加HLS加密功能(附源码) 之前测试使用过nginx的HLS加密功能,会使用到一个叫做nginx-rtmp-module的插件,但此插件很久不更新了,网上搜索到一个中国制造的叫做 ...
- 13行代码实现:Python实时视频采集(附源码)
一.前言 本文是<人脸识别完整项目实战>系列博文第3部分:程序设计篇(Python版),第1节<Python实时视频采集程序设计>,本章内容系统介绍:基于Python+open ...
- 在网站开发中很有用的8个 jQuery 效果【附源码】
jQuery 作为最优秀 JavaScript 库之一,改变了很多人编写 JavaScript 的方式.它简化了 HTML 文档遍历,事件处理,动画和 Ajax 交互,而且有成千上万的成熟 jQuer ...
- Web 开发中很实用的10个效果【附源码下载】
在工作中,我们可能会用到各种交互效果.而这些效果在平常翻看文章的时候碰到很多,但是一时半会又想不起来在哪,所以养成知识整理的习惯是很有必要的.这篇文章给大家推荐10个在 Web 开发中很有用的效果,记 ...
- MVC系列——MVC源码学习:打造自己的MVC框架(二:附源码)
前言:上篇介绍了下 MVC5 的核心原理,整篇文章比较偏理论,所以相对比较枯燥.今天就来根据上篇的理论一步一步进行实践,通过自己写的一个简易MVC框架逐步理解,相信通过这一篇的实践,你会对MVC有一个 ...
- C#进阶系列——一步一步封装自己的HtmlHelper组件:BootstrapHelper(三:附源码)
前言:之前的两篇封装了一些基础的表单组件,这篇继续来封装几个基于bootstrap的其他组件.和上篇不同的是,这篇的有几个组件需要某些js文件的支持. 本文原创地址:http://www.cnblog ...
- 轻量级通信引擎StriveEngine —— C/S通信demo(2) —— 使用二进制协议 (附源码)
在网络上,交互的双方基于TCP或UDP进行通信,通信协议的格式通常分为两类:文本消息.二进制消息. 文本协议相对简单,通常使用一个特殊的标记符作为一个消息的结束. 二进制协议,通常是由消息头(Head ...
- jquery自定义插件结合baiduTemplate.js实现异步刷新(附源码)
上一篇记录了BaiduTemplate模板引擎使用示例附源码,在此基础上对使用方法进行了封装 自定义插件jajaxrefresh.js 代码如下: //闭包限定命名空间 (function ($) { ...
随机推荐
- 第10天 | 12天搞定Python,文件操作(超详细)
在开发系统的过程中,经常会用到XML存储和传输数据,XML是一种用于标记电子文件使其具有结构性的标记语言,在博客中经常会见到. JSON是一种轻量级的数据交换格式,常被用在后端和前端的数据交互上,如你 ...
- 自学Python可以吗?怎样从入门到大师?我写这篇文章告诉你
前言 很多粉丝朋友问我该如何去学习爬虫.学习Python.自学能找到工作吗?等一系列的问题.今天我就来回答一下大家. 第一点 确定好方向与目标 当决定踏入这个行业那一刻起,我想每一个人都爱已经准备投身 ...
- 《我想进大厂》之JVM夺命连环10问
这是面试专题系列第五篇JVM篇. 说说JVM的内存布局? Java虚拟机主要包含几个区域: 堆:堆Java虚拟机中最大的一块内存,是线程共享的内存区域,基本上所有的对象实例数组都是在堆上分配空间.堆区 ...
- maven 配置文件 settings.xml pom.xml
maven涉及的配置文件一般有三个:(作用范围依次减小,优先级依次升高) 全局配置(maven安装包中):${M2_HOME}/conf/settings.xml 用户配置(该文件是拷贝全局配置而来的 ...
- c语言之指针特性
0x01.指针的声明 char x; char* x; short y; short* y; int z; int* z; float f; float* f; double d; double* d ...
- DLL转存为IL文件及修改后重新生成DLL文件
DLL反编译工具有:dotPeek (jetbrains) .ILSpy DLL转存IL使用:ildasm 打开DLL文件,选择file->dump. il .res重新生成DLL工具: ila ...
- SpringApplication.run(xxx.class, args)背后的东东——整体脉络
从spring到springmvc,再到springboot.springcloud,应用程序api开发调用方面都已经非常熟悉,但对spring背后的扩展机制:为何一个简单的main方法可以实现这么强 ...
- SourceTree安装及卸载
一.安装步骤 下载地址: 链接:https://pan.baidu.com/s/1K5ImZASuThJZoGLz6Ay_4g 提取码:hqkp 1. 点击安装包,点击下一步 2. 出现账户注册的页面 ...
- Kubernetes YAML最佳实践和策略
Kubernetes工作负载最常用YAML格式的文件来定义. YAML的问题之一就是很难描述清单文件之间的约束或关系. 如果你希望检查是否已从受信任的注册表中提取部署到群集中的所有映像,该怎么办? 如 ...
- AdaBoost算法详解与python实现
1. 概述 1.1 集成学习 目前存在各种各样的机器学习算法,例如SVM.决策树.感知机等等.但是实际应用中,或者说在打比赛时,成绩较好的队伍几乎都用了集成学习(ensemble learning)的 ...