这段时间一直都在研究推流的技术,经过断断续续将近两个月的摸索实践,终于能稳定地推流了。

这个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 。

C#推流RTMP,摄像头、麦克风、桌面、声卡(附源码)的更多相关文章

  1. 构建ASP.NET MVC4+EF5+EasyUI+Unity2.x注入的后台管理系统(2)-easyui构建前端页面框架[附源码]

    原文:构建ASP.NET MVC4+EF5+EasyUI+Unity2.x注入的后台管理系统(2)-easyui构建前端页面框架[附源码] 开始,我们有了一系列的解决方案,我们将动手搭建新系统吧. 用 ...

  2. 为SRS流媒体服务器添加HLS加密功能(附源码)

    为SRS流媒体服务器添加HLS加密功能(附源码) 之前测试使用过nginx的HLS加密功能,会使用到一个叫做nginx-rtmp-module的插件,但此插件很久不更新了,网上搜索到一个中国制造的叫做 ...

  3. 13行代码实现:Python实时视频采集(附源码)

    一.前言 本文是<人脸识别完整项目实战>系列博文第3部分:程序设计篇(Python版),第1节<Python实时视频采集程序设计>,本章内容系统介绍:基于Python+open ...

  4. 在网站开发中很有用的8个 jQuery 效果【附源码】

    jQuery 作为最优秀 JavaScript 库之一,改变了很多人编写 JavaScript 的方式.它简化了 HTML 文档遍历,事件处理,动画和 Ajax 交互,而且有成千上万的成熟 jQuer ...

  5. Web 开发中很实用的10个效果【附源码下载】

    在工作中,我们可能会用到各种交互效果.而这些效果在平常翻看文章的时候碰到很多,但是一时半会又想不起来在哪,所以养成知识整理的习惯是很有必要的.这篇文章给大家推荐10个在 Web 开发中很有用的效果,记 ...

  6. MVC系列——MVC源码学习:打造自己的MVC框架(二:附源码)

    前言:上篇介绍了下 MVC5 的核心原理,整篇文章比较偏理论,所以相对比较枯燥.今天就来根据上篇的理论一步一步进行实践,通过自己写的一个简易MVC框架逐步理解,相信通过这一篇的实践,你会对MVC有一个 ...

  7. C#进阶系列——一步一步封装自己的HtmlHelper组件:BootstrapHelper(三:附源码)

    前言:之前的两篇封装了一些基础的表单组件,这篇继续来封装几个基于bootstrap的其他组件.和上篇不同的是,这篇的有几个组件需要某些js文件的支持. 本文原创地址:http://www.cnblog ...

  8. 轻量级通信引擎StriveEngine —— C/S通信demo(2) —— 使用二进制协议 (附源码)

    在网络上,交互的双方基于TCP或UDP进行通信,通信协议的格式通常分为两类:文本消息.二进制消息. 文本协议相对简单,通常使用一个特殊的标记符作为一个消息的结束. 二进制协议,通常是由消息头(Head ...

  9. jquery自定义插件结合baiduTemplate.js实现异步刷新(附源码)

    上一篇记录了BaiduTemplate模板引擎使用示例附源码,在此基础上对使用方法进行了封装 自定义插件jajaxrefresh.js 代码如下: //闭包限定命名空间 (function ($) { ...

随机推荐

  1. MVC联想查询绑定下拉框

    前言 在做搜索时,输入些内容时需要弹出下拉框给用户进行选择,极大的方便了用户,会给用户带来不一样的体验 Controller public ActionResult SSAC(string UserN ...

  2. C++ 智能指针(一)

    内存安全 在C++中,动态内存的管理是通过一对运算符来完成的:new,在动态内存中为对象分配空间并返回一个指向该对象的指针,我们可以选择对对象来进行初始化:delete,接收一个动态对象的指针,销毁该 ...

  3. Django (学习第一部 基础操作)

    django 1 django 文件相关信息 2 Python创建django 3 命令行创建django 4 Django 必会三板斧 5 静态文件配置 6 request对象方法 7 pychar ...

  4. 第二十七章 ansible变量介绍

    一.ansible变量介绍 1.概念 变量提供了便捷的方式来管理Ansible playbook的每一个项目中的动态值,比如nginx-1.6.3这个软件包的版本,在其它地方或许会反复使用,那么如果讲 ...

  5. web应用部署(Tomcat,springboot部署方式)

    转载自:https://www.cnblogs.com/haimishasha/p/10791454.html 核心内容 1.在Tomcat中有四种部署Web应用的方式,分别是: (1)利用Tomca ...

  6. E. Almost Regular Bracket Sequence 解析(思維)

    Codeforce 1095 E. Almost Regular Bracket Sequence 解析(思維) 今天我們來看看CF1095E 題目連結 題目 給你一個括號序列,求有幾個字元改括號方向 ...

  7. 关于nodejs中的增删改查

    1.增加 router.post('/insert',function(req,res){  var name = req.body.name;  var num = req.body.num;  v ...

  8. 时间UTC格式装换php时间格式

    date_default_timezone_get("UTC");date("Y-m-d", strtotime("2017-11-13T18:04: ...

  9. solr 文档一

    [在此处输入文章标题] 参考博客: http://blog.csdn.net/matthewei6/article/details/50620600 基础环境搭建 solr版本5.5.5: 一.sol ...

  10. nginx下配置php5和php7

    用的是lnmp 一键安装的 php5.6版本网上百度Ubuntu安装多版本PHP就行 参考文章原链接:http://blog.csdn.net/21aspnet/article/details/476 ...