相关文章推荐
独立的凉面  ·  聊一聊微软Copilot的两个重磅更新!微软 ...·  6 月前    · 
考研的西红柿  ·  2020级浙江大学工程专业学位研究生(硕士) ...·  7 月前    · 
有腹肌的黄花菜  ·  开了VIP,想投屏还得多花一笔钱!优酷投屏收 ...·  11 月前    · 
踢足球的香蕉  ·  造车二十载,缪雪中的初心与蓝海_搜狐汽车_搜狐网·  1 年前    · 
快乐的领结  ·  特斯拉电子电气架构的演变 - 知乎·  1 年前    · 
Code  ›  udp 视频传输_webrtc视频流传输开发者社区
slice num udp webrtc
https://cloud.tencent.com/developer/article/2157166
玩命的吐司
1 年前
全栈程序员站长
0 篇文章

udp 视频传输_webrtc视频流传输

前往专栏
腾讯云
开发者社区
文档 意见反馈 控制台
首页
学习
活动
专区
工具
TVP
最新优惠活动
文章/答案/技术大牛
发布
首页
学习
活动
专区
工具
TVP 最新优惠活动
返回腾讯云官网
全栈程序员站长
首页
学习
活动
专区
工具
TVP 最新优惠活动
返回腾讯云官网
社区首页 > 专栏 > 全栈程序员必看 > udp 视频传输_webrtc视频流传输

udp 视频传输_webrtc视频流传输

作者头像
全栈程序员站长
发布 于 2022-11-09 17:18:19
1.4K 0
发布 于 2022-11-09 17:18:19
举报

在 UDP实时图像传输 一文中,介绍了如何使用UDP来实现图像的实时传输,并使用C#进行了发送端和接收端的搭建。但是文中的方法是对整张图片进行JPEG压缩,并通过UDP一次性地发送到接收端,由于一个UDP数据包只能发送64k字节的数据,所以该方法的图片传输大小是有限制的,实测只能发送480P 视频 中的图像。

所以本文将继续采取逐帧发送的形式,以1080P的视频为例,实现更高清晰度( 1080 × 1920 × 3 1080\times 1920\times 3 1080×1920×3)的图像实时传输。

基本流程

本文中的高清晰度图像传输就是在前文方法的基础上,在发送端添加了切片压缩传输以及并行加速的步骤,而接收端则相应地使用多线程进行数据接收,分别接收压缩后的切片数据,再拼接起来进行显示。流程如下

系统框图
系统框图

实验环境

  • VS2019 / .NET4.7.1 / C#(开发环境)
  • EmguCV 4.1(用于读取、压缩图像,使用方法见 上一篇文章 )
  • PC(测试环境)

发送端

在发送端我们需要达到的效果如下,左边用来显示原始图像,右上角用来显示各个切片,右下角用来处理接收端的连接请求。

在这里插入图片描述
在这里插入图片描述

首先设置一些参数

// 实例化一个VideoCapture,选择从本地文件读取视频
private VideoCapture capture = new VideoCapture("../../video/04.mp4");
// 设置读取的图片宽度
const int WIDTH = 1920;  
// 设置读取的图片高度
const int HEIGHT = 1080; 
// 切片数量
const int NUM_SLICE = 24; 

然后进行图像的显示以及切片。初始化一组显示控件,用来显示切片后的结果:

private void Form1_Load(object sender, EventArgs e)
// 设置图像大小
capture.SetCaptureProperty(Emgu.CV.CvEnum.CapProp.FrameWidth, WIDTH);
capture.SetCaptureProperty(Emgu.CV.CvEnum.CapProp.FrameHeight, HEIGHT);
// 获取面板控件的大小
int w = panel_imgs.Width;
int h = panel_imgs.Height;
// 在面板panel_imgs上添加显示控件,用于显示每个切片
for (int i = 0; i < NUM_SLICE; i++)
ImageBox imgb = new ImageBox();
imgb.Left = 0;
imgb.Top = i * h / NUM_SLICE;
imgb.Width = w;
imgb.Height = h / NUM_SLICE - 1;
imgb.SizeMode = PictureBoxSizeMode.StretchImage;
imgb.Visible = true;
imgbox[i] = imgb;
panel_imgs.Controls.Add(imgbox[i]);
// 在下拉文本框cbb_localIP中显示该计算机中的IPv4地址
cbb_localIP.Text = GetLocalIPv4Address().ToString();
}

最后就是图像的读取、切片、压缩、发送等处理函数,这处理过程中,使用了 Parallel.For 并行加速功能,相对于串行的 for 循环,并行速度提高了一倍左右(不知道为啥我四核八线程的处理器只能降低一半的运行时间)

private void ProcessFram() // 图像读取、切片、发送
DateTime startDT = System.DateTime.Now;
while (true)
// 计算两次循环间的间隔,并显示在左上角
DateTime stopDT = System.DateTime.Now;
TimeSpan ts = stopDT.Subtract(startDT);
this.Text = "图片处理耗时:" + ts.TotalMilliseconds + "ms";
startDT = System.DateTime.Now;
// 读取一张图片
Mat currentImage = capture.QueryFrame();
// 显示摄像头/视频流的图像
imageBox0.Image = currentImage;
int N = HEIGHT / NUM_SLICE;
// 对图像进行切片,并将切片压缩后发送到接收端 
Parallel.For(0, NUM_SLICE, i => // Parallel并行加速
// 从原图中切割,输入参数:原始图片 行范围row 列范围col
img[i] = new Mat(currentImage, new Range(i * N, (i + 1) * N - 1), new Range(0, WIDTH));
// 显示
imgbox[i].Image = img[i];
// 转换格式
Image<Rgb, Byte> img_trans = img[i].ToImage<Rgb, Byte>();
// JPEG压缩
byte[] bytes = img_trans.ToJpegData(95);
// UDP配置
UdpClient udpClient = new UdpClient();
//IPAddress ipaddress = IPAddress.Parse("192.168.0.105");
IPAddress ipaddress = remoteIP;
IPEndPoint endpoint = new IPEndPoint(ipaddress, 8000 + 10 * i);
// UDP发送
udpClient.Send(bytes, bytes.Length, endpoint);
udpClient.Close();
}

在初始化函数中添加以下程序就可以执行包含切片、压缩、发送等操作的线程

Thread transFrames = new Thread(ProcessFram);
transFrames.Start();

接收端

接收端比较简单,实现效果如下,因为在接收端没有对图片进行更进一步的处理,所以本文只在接收端添加了若干个显示控件,用来显示每个切片,但是从观感上每个切片依次连接,形成了一张完整的图片。

在这里插入图片描述
在这里插入图片描述

首先进行参数设置

 // 切片数量,与发送端保持一致
const int NUM_SLICE = 24; 
// 为每一个切片创建一个显示控件
PictureBox[] imgbox = new PictureBox[NUM_SLICE];
// 为每一个切片创建一个UDP套接字
Socket[] udpServer = new Socket[NUM_SLICE];

在初始化过程中添加显示控件,与发送端类似

int w = panel_imgs.Width;
int h = panel_imgs.Height;
// 在面板panel_imgs上添加显示接收到的图片的控件
for (int i = 0; i < NUM_SLICE; i++)
// 设置PictureBox的位置、大小等参数
PictureBox imgb = new PictureBox();
imgb.Left = 0;
imgb.Top = i * h / NUM_SLICE;
imgb.Width = w;
imgb.Height = h / NUM_SLICE + 1;
imgb.SizeMode = PictureBoxSizeMode.StretchImage;
imgb.Visible = true;
// 添加到面板panel_imgs上
imgbox[i] = imgb;                
panel_imgs.Controls.Add(imgbox[i]);
}

接下来需要为每个切片创建一个接收线程

for (int i = 0; i < NUM_SLICE; i++)
new Thread(new ParameterizedThreadStart(ImgReceive))
IsBackground = true
}.Start(8000 + i * 10); // 输入参数为端口号,依次增加
}

最后就是接收线程的入口函数 ImgReceive 的内容

private void ImgReceive(object arg)
// 网络端口号
int port = (int)arg;
int index = port % 8000 / 10;
// 创建套接字
udpServer[index] = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
// 绑定IP和端口
udpServer[index].Bind(new IPEndPoint(IPAddress.Parse(cbb_remoteIP.Text), port));
// 开启数据接收线程
while (true)
EndPoint remoteEndPoint = new IPEndPoint(IPAddress.Any, 0);
// 设置一个64k的字节数组作为缓存
byte[] data = new byte[65536];
int length = udpServer[index].ReceiveFrom(data, ref remoteEndPoint);//此方法把数据来源ip、port放到第二个参数中
MemoryStream ms = new MemoryStream(data, 0, length);
// 将图像显示到对应的PictureBox控件上
Image img = Image.FromStream(ms);
 
推荐文章
独立的凉面  ·  聊一聊微软Copilot的两个重磅更新!微软Copilot企业版已开放中国市场!_copilot免费版-CSDN博客
6 月前
考研的西红柿  ·  2020级浙江大学工程专业学位研究生(硕士)“移动智慧物联网”项目校内导师及信息一览表
7 月前
有腹肌的黄花菜  ·  开了VIP,想投屏还得多花一笔钱!优酷投屏收费引争议,回应来了_手机新浪网
11 月前
踢足球的香蕉  ·  造车二十载,缪雪中的初心与蓝海_搜狐汽车_搜狐网
1 年前
快乐的领结  ·  特斯拉电子电气架构的演变 - 知乎
1 年前
今天看啥   ·   Py中国   ·   codingpro   ·   小百科   ·   link之家   ·   卧龙AI搜索
删除内容请联系邮箱 2879853325@qq.com
Code - 代码工具平台
© 2024 ~ 沪ICP备11025650号