C#FFmpeg视频采集与推送RTMP服务器代码思路整理
来源:互联网 发布:mac tengine 安装配置 编辑:程序博客网 时间:2024/05/29 11:31
C#视频采集与推送RTMP服务器代码思路整理:在看过FFmpeg后是否认为写C#的视频流采集和推送还是一头雾水啊?深有此感。领导是C#的高手,说可以通过C或C++的代码直接复制粘贴到C#工程然后进行适配代码就可以了,因为C#使用ffmpeg的类名和变量、方法等都与C保持高度一致的,经领导这么一说C#里面只需要参考C或C++的实现就可以完成相关的操作了,这样就更容易理解了(涉及到指针问题,C#也支持)。本文旨在分析实现思路,而不提供源代码,敬请谅解!
服务端和客户端的职能
客户端负责视频采集,服务端负责视频转发或播放
整体设计视频传输架构
说明:视频数据发送H264数据包给服务端,服务端获取到数据包进行编解码转成FLV格式的流,而RTMP只支持FLV格式的流。
原理:socket视频数据采集,socket 数据包发送,编解码处理,推流。
视频直播推流效果展示
启动顺序:程序客户端和服务端是两个项目需要分别启动,先启动服务端,再启动客户端,允许多个实例存在。
第一幕:启动视频编解码服务端
第二幕:启动视频采集摄像头客户端
点击开始连接到服务端。
第三幕:服务端处理要连接的客户端并建立数据传输
选择客户端,并开始传输视频,此时会弹出摄像头访问窗口。
第四幕:验证直播是否进行
访问RTMP服务器状态监控地址,如:http://172.16.20.10:1990/stat
第五幕:使用ffplay进行直播流播放
cmd进入ffmpeg的路径执行:ffplay rtmp://172.16.20.10:1935/live/S013333333333
以上就是所有架构实现的效果了。
摄像头视频采集客户端
客户端窗体变量:
// socket数据包封装对象JTData jtdata = new JTData();// 数据分包对象SplitData splitData = new SplitData();// TCP通信通道Network.TCPChannel channel;// 标识用户手机号string SimKey = "013333333333";// 线程对象Thread thVideo;// Socket实例对象private Socket send_sock;private Queue<Bitmap> mQueues = new Queue<Bitmap>();// 摄像头处理H264对象Cam2H264 cam2H264 = new Cam2H264();private Setting setting;IPEndPoint iPEndPoint;客户端窗体开始录像按钮处理:
private void btnStart_Click(object sender, EventArgs e) { channel = new Network.TCPChannel(txtServer.Text.Trim(), Convert.ToInt32(txtPort.Text.Trim()));//实例化TCP连接通道 channel.DataReceive = Receive; channel.DataSend = DataSend; channel.ChannelConnect += new EventChannelConnect(channel_ChannelConnect);// 设置通道连接事件 channel.Connect(); //channel.StartReceiveAsync(); btnStart.Enabled = false; btnStop.Enabled = true; }
客户端窗体TCP通道回调函数:
void channel_ChannelConnect(object sender, ChannelConnectArg arg) { Console.WriteLine(arg.SocketError.ToString()); SendHeart(); } private void SendHeart() { var lst = jtdata.Package(0x0002, SimKey); SendAnswer(lst); } #region 链路 public void Receive(object sender, ChannelReceiveArg arg) { splitData.SplitDataBy7E(arg.Data, ((byte[] bGps) => { if (bGps.Length > 11 && CheckHelper.CheckXOR(bGps, 0, bGps.Length - 1) == bGps[bGps.Length - 1])//效验通过 { var head = JTHeader.NewEntity(bGps); JXData(bGps, head); } })); } public void JXData(byte[] bGps, JTHeader head) { switch (head.MsgId) { case 0x8001://通用应答 break; case 0x8B00://4.1.1 实时音视频传输请求 if (thVideo != null && thVideo.IsAlive) { Console.WriteLine("已经在传输"); } else { BaseLineTime = DateTime.Now; SerialNumber = 0; LastIFrameTime = DateTime.MinValue; LastFrameTime = DateTime.MinValue; var req = JTRealVideoTransferRequest.NewEntity(bGps, head.HeadLen); thVideo = new Thread(StartVideo); thVideo.IsBackground = true; iPEndPoint = new IPEndPoint(IPAddress.Parse(req.IPAddress), req.UdpPort); thVideo.Start(iPEndPoint); } break; default: break; } } public void DataSend(object sender, ChannelSendArg arg) { } public bool SendAnswer(JTPData data) { foreach (var item in data) { channel.Send(item.Data.ToArray()); //return true; } return true; }客户端窗体线程处理视频数据:
unsafe void StartVideo(object ep) { try { send_sock = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); send_sock.SendBufferSize = 1000000; cam2H264.Run(setting.VideoDevice, SendToServer, 0); } catch (Exception ex) { } }
具体264的处理基本上可以参考FFmpeg的C实现方式来做,下面是步骤:
请参考:https://github.com/FFmpeg/FFmpeg
视频数据包转发服务端
注:实际服务端未做转码处理,已在客户端线程中处理。
服务端窗体常量:
// 开启本机TCP连接Network.TCPServer ser = new Network.TCPServer("0.0.0.0", 9700);// RTP服务端RTPServer rtServer;// 连接到的客户端列表List<VideoClient> lstTCPChannel = new List<VideoClient>();// 数据包拆分对象JX.SplitData splitData = new JX.SplitData();
服务端窗体事件绑定与客户端连接自动发现:
#region 窗体事件 private void frmServer_FormClosing(object sender, FormClosingEventArgs e) { try { ser.Stop(); } catch { } try { rtServer.Dispose(); } catch { } } private void btnStart_Click(object sender, EventArgs e) { var vc = lstTCPChannel[lstBoxTcp.SelectedIndex]; //rtServer.AddClient(vc.SimKey, "rtmp://localhost:32768/rtmplive/S" + vc.SimKey); rtServer.AddClient(vc.SimKey, "rtmp://172.16.20.10:1935/live/S" + vc.SimKey);// 添加直播客户端---RTMP推流服务器地址和流名称 vc.SendVideoCtrl(new JTRealVideoTransferRequest { IPAddress = "127.0.0.1", UdpPort = 9700, Channel = 0, DataType = 1, StreamType = StreamType.SubStream }); } private void frmServer_Load(object sender, EventArgs e) { rtServer = new RTPServer(9700, pictureBox1);//RTP服务端图像传输对象 rtServer.Start(); ser.ChannelConnect += new Network.EventChannelConnect(ser_ChannelConnect);// 通道连接事件 ser.ChannelDispose += new Network.EventChannelDispose(ser_ChannelDispose);// 通道连接断开事件 ser.Start(); Network.Utils.Setup(10); } #endregion
服务端窗体客户端连接列表控制:
#region 列表控制 VideoClient AddToList(Channel channel) { var item = new VideoClient(channel, splitData); channel.Tag = item; lstTCPChannel.Add(item); //rtServer.AddClient(item.SimKey, "rtmp://localhost:32768/rtmplive/S" + item.SimKey); rtServer.AddClient(item.SimKey, "rtmp://172.16.20.10:1935/live/S" + item.SimKey);// 添加直播客户端---RTMP推流服务器地址和流名称 lstBoxTcp.BeginInvoke(new MethodInvoker(() => { lstBoxTcp.Items.Add(channel.RemoteHost + ":" + channel.RemotePort); })); return item; } void RemoveList(Channel channel) { var item = (VideoClient)channel.Tag; lstTCPChannel.Remove(item); rtServer.RemoveClient(item.SimKey); lstBoxTcp.Invoke(new MethodInvoker(() => { lstBoxTcp.Items.Remove(channel.RemoteHost + ":" + channel.RemotePort); })); } #endregion服务端窗体通信链路事件方法:
#region 链路相关 void ser_ChannelDispose(object sender, Network.ChannelDisposeArg arg) { RemoveList(arg.Channel); } void ser_ChannelConnect(object sender, Network.ChannelConnectArg arg) { var item = AddToList(arg.Channel); arg.Channel.DataReceive = item.Receive; arg.Channel.DataSend = item.DataSend; arg.Channel.StartReceiveAsync(); } #endregion
大致代码的思路都在此了。
需要思考的问题
想达到这样的目的:视频能够一边下载一边播放。如何编程实现服务器端的视频流信息向客户端的发送? 客服端又如何接收并播放视频?
使用System.Net的NetStream和使用System.IO的FileStream、MediaPlayer播放插件。
(1)在服务端建立一个Socket服务,将文件分段放入缓冲区。
(2)在客户端建立一个Socket客户端,读取服务端的缓冲区内容。
(3)将读到的部分发送给MediaPlayer进行播放。
上面的客户端和服务端的情况就是按照这种思路来写的,后续需要加入视频预览、播放的功能。实际上就是将H264流数据转成YUV/RGB->Bitmap前端进行展示,然后加入音频数据传输的线程等进行处理同步播放。
上图是服务器端获取到的H264->YUV播放示例。
- C#FFmpeg视频采集与推送RTMP服务器代码思路整理
- 使用ffmpeg推送视频流至流媒体服务器(c语言)
- ffmpeg推本地视频到rtmp服务器
- FFMPEG 抓RTSP流,推送RTMP至FMS服务器
- 树莓派+FFmpeg——推送摄像头数据到RTMP服务器
- FFMPEG推送rtmp流实例
- FFMPEG推送rtmp流实例
- OpenCV摄像头视频数据采集与RTSP和RTMP直播
- RTMP推送直播H264/AAC编码的音视频采集数据
- 使用ffmpeg循环推流(循环读取视频文件)推送EasyDSS RTMP流媒体服务器的方法
- 手机Android音视频采集与直播推送
- EasyRTMP安卓Android手机直播之AAC采集、编码与RTMP推送
- FFMPEG推流到RTMP服务器命令
- ffmpeg 教程之 rtmp 推送器
- ffmpeg 推送、保存rtmp 流命令
- h264视频流,aac音频流(g711a转码)推送至rtmp服务器
- iOS直播-基于RTMP的视频推送
- Nginx与Nginx-rtmp-module搭建RTMP视频直播和点播服务器
- angular $resource模块
- 画页面遇到的坑
- GMIS 2017 大会杨琼演讲:人工智能+医疗——噱头,还是未来?
- 如何使用Matrix对bitmap的旋转与镜像水平垂直翻转
- FatFS f_open()函数详解
- C#FFmpeg视频采集与推送RTMP服务器代码思路整理
- Java使用HttpClient发送Get请求和Post请求
- 自定义加载View
- HTML笔记(HTML5 File API)
- QQ状态同步究竟是推还是拉?
- 公众号编辑器开发,jquery实现文章样式排版页面
- 消息“时序”与“一致性”为何这么难?
- 小学奥数思维训练题(十六)
- 在线表格编辑器发布V11版本,新增对图表和纯前端PDF导出支持