C# MJPEG 客户端简单实现方法

MJPEG协议在此不在过多描述,这里主要介绍一下使用C#中的PictureBox控件频繁刷新MJPEG传输过来的图片,高频率的图片刷新实现视频播放效果;

环境:

服务端

MJPEG服务器使用的是手机的DroidCam,很方便的一个MJPEG服务器,端口4747,打开软件就能使用,并且还附带了web端展示。

客户端

MJPEG客户端使用C# Http请求,并获取到响应MJPEG视频流,截取到图片数据部分,用PictureBox展示图片内容。

整体流程:

1. C# 向MJPEG发送请求URL,请求URL是MJPEG服务器定的,例如DroidCam,可以通过访问: {手机所在IP}:4747

图片中红框内容就是视频流的地址,使用GET请求后,服务端就会一直往这个请求的响应内容中写照片信息,直到这个GET请求断开为止(客户端、服务端其中一个主动退出)

ps: 如果使用DroidCam当服务器,建议使用手机热点、或者手机通过数据线共享链接方式链接,因为MJPEG实际是把视频的每一帧截成一张图片发送过来的,非常的占带宽,并且网速不好还有图片数据不完整情况,需要手动处理跳过.手机开WiFi热点电脑链接, 手机端IP:192.168.43.1:4747,手机数据线连接usb网络共享,手机端IP:192.168.43.129:4747;

2. C# 读响应头,找出视频流中每张图片的分隔符, 读取每张图片前Content-Length长度, 读图片;

3. 每读到一张图片,刷新一次PictureBox控件;

具体实现

//创建一个HTTP请求,只要请求不结束,MJPEG服务端会一直给请求的响应体中发送实时图片内容
HttpWebRequest hwRequest = (System.Net.HttpWebRequest)WebRequest.Create("请求URL地址");
hwRequest.Method = "GET";
HttpWebResponse hwResponse = (HttpWebResponse)hwRequest.GetResponse();
//读boundary指定的每张图片分隔符,DroidCam为:--dcmjpeg
string contentType = hwResponse.Headers["Content-Type"];
string boundryKey = "boundary=";
string boundary = contentType.Substring(contentType.IndexOf(boundryKey) + boundryKey.Length);
 
//拿到响应体流
Stream stream = hwResponse.GetResponseStream();
string headerName = "Content-Length:";
//临时存储字符串数据
StringBuilder sb = new StringBuilder();
int len = 1024;
while (true)
{
    //读取一行数据
    while (true) {
        char c = (char)stream.ReadByte();
        //Console.Write(c);
        if (c == '\n') {
            break;
        }
        sb.Append(c);
    }
    string line = sb.ToString();
    sb.Remove(0, sb.Length);
    //当前行中是否包含Content-Length:
    int i = line.IndexOf(headerName);
    if (i != -1) {
        //每张图片前有一段图片简单介绍(图片类型、长度),这里只关心长度(Content-Length:)后边的值,用于后续读取图片
        int imageFileLength = Convert.ToInt32(line.Substring(i + headerName.Length).Trim());
        //Content-Length:xxx 完后会有一个/r/n的换行符,换行符后才是真正的图片数据(不知道是DroidCam自己这样还是都这样...)
        //这里跳过/r/n
        stream.Read(new byte[2], 0, 2);
        //开始读取图片数据,imageFileLength就是读到的Content-Length:后的长度
        byte[] imageFileBytes = new byte[imageFileLength];
        stream.Read(imageFileBytes, 0, imageFileBytes.Length);
        //JPEG的文件头是: FF D8 FF ,文件尾是: FF D9,非常重要,调试时最好打印一下,便于区分读入的数据是否正好时图片的所有内容
        //Console.WriteLine("文件头:" + imageFileBytes[0].ToString("X") + " " + imageFileBytes[1].ToString("X") + " " + imageFileBytes[2].ToString("X") + " " + imageFileBytes[3].ToString("X") + " " + imageFileBytes[4].ToString("X"));
        //Console.WriteLine("文件尾:" + imageFileBytes[imageFileLength - 2].ToString("X") + " " + imageFileBytes[imageFileLength - 1].ToString("X"));
        //此处做了一个如果读入文件不全时处理,图片越大,程序循环读取速度越快,越有可能导致读取文件不全情况...,如果有好的办法解决希望前辈们指教,非常感谢!
        //文件尾是否是FF D9
        if (imageFileBytes[imageFileLength - 2].ToString("X") != "FF" && imageFileBytes[imageFileLength - 1].ToString("X") != "D9")
        {
            //读入文件内容不全,跳过次文件,让流位置跳到下次图片开始位置
            //Console.WriteLine("开始矫正...");
            char l = '0';
            while (true)
            {
                char c = (char)stream.ReadByte();
                //这里只判断了--dcmjpeg中的前两个字符--,当读到的流中连续两个字符是--时,表示流已读到下次图片开始位置
                if (l == boundary[0] && c == boundary[1])
                {
                    break;
                }
                l = c;
            }
        }
        else
        {
            //读取图片成功!
            //accessImageHandler是一个Action,用于把图片实时写到PictureBox控件中
            accessImageHandler(imageFileBytes);
        }
        //这里适当睡几十毫秒,会降低点图片读入不全情况,还未找到图片随机读取不全情况原因...
        Thread.Sleep(sleep);
    }
}
stream.Close();
hwResponse.Close();

可以先试着读一张图片,通过FileStream 写成文件,看看写成的文件是否能用Windows图片查看器查看,如果不能并且机器上有PS的话,可以试着用PS打开一下,PS对图片支持的比较好,如果文件头多写两个其他字符它是可以过滤掉的。但是最后的效果还是需要Windows图片查看器能看,只有查看器能看,PictureBox才能正常显示内容,否则在打开图片时会报内存不足异常!

多调试几遍,查看一下请求头、请求尾是否正确。

如果有兴趣,可以看下我调试例子:链接: https://pan.baidu.com/s/1oihxe8ficnCm4gcaE9SQBg 提取码: atwh ,例子内容有点乱,并且很不完善,希望对你多少有些帮助!

补充使用IP摄像头APP连接时有密码情况:

MJPEG协议中应该是没规定加密情况,这个加密(http auth)应该是IP摄像头APP规定的。

在使用IP摄像头App读MJPEG流时发现需要密码,使用浏览器直接访问会弹出输入账号密码框,通过解析请求发现其实就是在请求头中添加了一个请求头Authorization:

YWRtaW46YWRtaW4=是我在APP中设置的 用户名(admin):密码(admin) 拼接起来后转成Base64的字符串,  admin:admin  转成base64为: YWRtaW46YWRtaW4=

所以在修改一下请求头就可以了:

hwRequest.Headers.Add("Authorization", "Basic " + Convert.ToBase64String(Encoding.UTF8.GetBytes(user + ":" + pass)));

这里hwRequest就是HttpWebRequest

user是用户名,pass 是密码

以上就是C# MJPEG 客户端简单实现方法的详细内容,更多关于C# MJPEG 客户端简单实现的资料请关注我们其它相关文章!

(0)

相关推荐

  • c#获取客户端IP地址(考虑代理)

    说明:本文中的内容是我综合博客园上的博文和MSDN讨论区的资料,再通过自己的实际测试而得来,属于自己原创的内容说实话很少,写这一篇是为了记录自己在项目中做过的事情,同时也想抛砖引玉.参考的博文及其作者在下文均有提及.待到自己以后对HTTP.TCP/IP等知识学深入了,一定再来这里深入讨论这个内容. 一.名词 首先说一下接下来要讲到的一些名词. 在Web开发中,我们大多都习惯使用HTTP请求头中的某些属性来获取客户端的IP地址,常见的属性是REMOTE_ADDR.HTTP_VIA和HTTP_X_F

  • 详细分析c# 客户端内存优化

    背景概述 C# 开发客户端系统的时候,.net 框架本身就比较消耗内存资源,特别是xp 这种老爷机内存配置不是很高的电脑上运行,所以就需要进行内存上的优化,才能流畅的在哪些低端电脑上运行. 想要对C# 开发的客户端内存优化需要了解以下几个概念. 虚拟内存 这里引用百度百科的概念:虚拟内存是计算机系统内存管理的一种技术.它使得应用程序认为它拥有连续的可用的内存(一个连续完整的地址空间),而实际上,它通常是被分隔成多个物理内存碎片,还有部分暂时存储在外部磁盘存储器上,在需要时进行数据交换.目前,大多

  • C#实现WebSocket协议客户端和服务器websocket sharp组件实例解析

    看到这篇文章的题目,估计很多人都会问,这个组件是不是有些显的无聊了,说到web通信,很多人都会想到ASP.NET SignalR,或者Nodejs等等,实现web的网络实时通讯.有关于web实时通信的相关概念问题,在这里就不再做具体的介绍了,有兴趣的可以自行百度. 下面我们介绍一款WebSocket组件websocket-sharp的相关内容. 一.websocket-sharp组件概述 websocket-sharp是一个C#实现websocket协议客户端和服务端,websocket-sha

  • C#实现FTP客户端的案例

    本文是利用C# 实现FTP客户端的小例子,主要实现上传,下载,删除等功能,以供学习分享使用. 思路: 通过读取FTP站点的目录信息,列出对应的文件及文件夹. 双击目录,则显示子目录,如果是文件,则点击右键,进行下载和删除操作. 通过读取本地电脑的目录,以树状结构展示,选择本地文件,右键进行上传操作. 涉及知识点: FtpWebRequest[实现文件传输协议 (FTP) 客户端] / FtpWebResponse[封装文件传输协议 (FTP) 服务器对请求的响应]Ftp的操作主要集中在两个类中.

  • C#客户端程序Visual Studio远程调试的方法详解

    一,需求来源 在开发过程中,可能会要使用Win7 ,Win8 ,Win10等不同版本的系统去做兼容性调试,也有时候会去针对特别的显卡,无线网卡等等硬件设备的机器做优化,有一种较优的方案,那就是使用Visual Studio的远程调试功能,可以直接将测试机作为调试目标,直接跟踪断点和异常,可以像在本机调试一样,迅速的找到错误的地方.,而不需要在测试机安装VS环境. >传统桌面客户端的远程调试相比UWP,ASP等项目来说,配置比较麻烦,因为它是非部署的应用程序,原理是复制编译的文件到远程计算机,通过

  • C#客户端程序调用外部程序的3种实现方法

    简介 大家都知道,当我们用C#来开发客户端程序的时候,总会不可避免的需要调用外部程序或者访问网站,本篇博客介绍了三种调用外部应用的方法,供参考,下面话不多说了,来一起看看详细的介绍吧. 实现 第一种是利用shell32.dll,实现ShellExecute方法,该方法可同时打开本地程序.文件夹或者访问网站,只要直接输入路径字符串即可, 如C:\Users\Desktop\xx.exe或者https://cn.bing.com/,可以根据返回值判断是否调用成功 (成功0x00000002a , 失

  • 详解C# Socket简单例子(服务器与客户端通信)

    这个例子只是简单实现了如何使用 Socket 类实现面向连接的通信. 注意:此例子的目的只是为了说明用套接字写程序的大概思路,而不是实际项目中的使用程序.在这个例子中,实际上还有很多问题没有解决,如消息边界问题.端口号是否被占用.消息命令的解析问题等.. 下面是两个程序的代码,(两个程序均为控制台程序) 先发服务端的(Server)完整代码如下: 引入命名空间: using System.Net.Sockets; using SystemNet; using SystemThreading; 完

  • C#使用Socket实现服务器与多个客户端通信(简单的聊天系统)

    扩展: 由于server端是存储了所有server与client的连接对象,因此我们是可以基于此demo的基础上实现聊天系统: * 每当一个与用户发言时,是由server接收到的某个用户的发言信息的,此时服务器端可以通过循环发送该用户发送的信息给每个已经连接连接的用户(排除发送者). Server端代码: class Program { //创建一个和客户端通信的套接字 static Socket SocketWatch = null; //定义一个集合,存储客户端信息 static Dicti

  • C#编程获取客户端计算机硬件及系统信息功能示例

    本文实例讲述了C#编程获取客户端计算机硬件及系统信息功能.分享给大家供大家参考,具体如下: 这里使用C#获取客户端计算机硬件及系统信息 ,包括CPU.硬盘.IP.MAC地址.操作系统等. 1.项目引用System.Management库. 2.创建HardwareHandler.cs类文件 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Manag

  • C# 实现FTP客户端的小例子

    本文是利用C# 实现FTP客户端的小例子,主要实现上传,下载,删除等功能,以供学习分享使用. 思路: 通过读取FTP站点的目录信息,列出对应的文件及文件夹. 双击目录,则显示子目录,如果是文件,则点击右键,进行下载和删除操作. 通过读取本地电脑的目录,以树状结构展示,选择本地文件,右键进行上传操作. 涉及知识点: FtpWebRequest[实现文件传输协议 (FTP) 客户端] / FtpWebResponse[封装文件传输协议 (FTP) 服务器对请求的响应]Ftp的操作主要集中在两个类中.

  • C# 获取客户端IPv4地址的示例代码

    网上找了一些获取客户端IP的方法,但本地测试时,返回的是IPv6的表示方法"::1": Host文件里面:#    ::1             localhost 后来找了获取IPv4的方法就可以了,比较好用: public static string GetClientIPv4Address() { string ipv4 = String.Empty; foreach (IPAddress ip in Dns.GetHostAddresses(GetClientIP())) {

随机推荐