实现流写入,将图像作为mjpeg写入

 public class MjpegWriter : IDisposable
{ private static byte[] CRLF = new byte[] { , };
private static byte[] EmptyLine = new byte[] { , , , }; private string _Boundary; public MjpegWriter(Stream stream)
: this(stream, "--boundary")
{ } public MjpegWriter(Stream stream, string boundary)
{ this.Stream = stream;
this.Boundary = boundary;
} public string Boundary { get; private set; }
public Stream Stream { get; private set; } public void WriteHeader()
{ Write(
"HTTP/1.1 200 OK\r\n" +
"Content-Type: multipart/x-mixed-replace; boundary=" +
this.Boundary +
"\r\n"
); this.Stream.Flush();
} public void Write(Image image)
{
MemoryStream ms = BytesOf(image);
this.Write(ms);
} public void Write(MemoryStream imageStream)
{ StringBuilder sb = new StringBuilder(); sb.AppendLine();
sb.AppendLine(this.Boundary);
sb.AppendLine("Content-Type: image/jpeg");
sb.AppendLine("Content-Length: " + imageStream.Length.ToString());
sb.AppendLine(); Write(sb.ToString());
imageStream.WriteTo(this.Stream);
Write("\r\n"); this.Stream.Flush(); } private void Write(byte[] data)
{
this.Stream.Write(data, , data.Length);
} private void Write(string text)
{
byte[] data = BytesOf(text);
this.Stream.Write(data, , data.Length);
} private static byte[] BytesOf(string text)
{
return Encoding.ASCII.GetBytes(text);
} private static MemoryStream BytesOf(Image image)
{
MemoryStream ms = new MemoryStream();
image.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
return ms;
} public string ReadRequest(int length)
{ byte[] data = new byte[length];
int count = this.Stream.Read(data, , data.Length); if (count != )
return Encoding.ASCII.GetString(data, , count); return null;
} #region IDisposable Members public void Dispose()
{ try
{ if (this.Stream != null)
this.Stream.Dispose(); }
finally
{
this.Stream = null;
}
} #endregion
}

服务器实现:

 public class ImageStreamingServer : IDisposable
{ private List<Socket> _Clients;
private Thread _Thread; public ImageStreamingServer() : this(IRImg.Snapshots())
{ } public ImageStreamingServer(IEnumerable<Image> imagesSource)
{ _Clients = new List<Socket>();
_Thread = null; this.ImagesSource = imagesSource;
this.Interval = ; } public IEnumerable<Image> ImagesSource { get; set; } public int Interval { get; set; } public IEnumerable<Socket> Clients { get { return _Clients; } } public bool IsRunning { get { return (_Thread != null && _Thread.IsAlive); } } public void Start(int port)
{ lock (this)
{
_Thread = new Thread(new ParameterizedThreadStart(ServerThread));
_Thread.IsBackground = true;
_Thread.Start(port);
} } public void Start()
{
this.Start();
} public void Stop()
{ if (this.IsRunning)
{
try
{
_Thread.Join();
_Thread.Abort();
}
finally
{ lock (_Clients)
{ foreach (var s in _Clients)
{
try
{
s.Close();
}
catch { }
}
_Clients.Clear(); } _Thread = null;
}
}
} private void ServerThread(object state)
{ try
{
Socket Server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); Server.Bind(new IPEndPoint(IPAddress.Any, (int)state));
Server.Listen(); System.Diagnostics.Debug.WriteLine(string.Format("Server started on port {0}.", state)); foreach (Socket client in Server.IncommingConnectoins())
ThreadPool.QueueUserWorkItem(new WaitCallback(ClientThread), client); }
catch { } this.Stop();
} private void ClientThread(object client)
{ Socket socket = (Socket)client;
lock (_Clients)
_Clients.Add(socket); try
{
using (MjpegWriter wr = new MjpegWriter(new NetworkStream(socket, true)))
{
wr.WriteHeader();
foreach (var imgStream in IRImg.Streams(this.ImagesSource))
{
if (this.Interval > )
Thread.Sleep(this.Interval); wr.Write(imgStream);
} }
}
catch { }
finally
{
lock (_Clients)
_Clients.Remove(socket);
}
} public void Dispose()
{
this.Stop();
}
} static class SocketExtensions
{ public static IEnumerable<Socket> IncommingConnectoins(this Socket server)
{
while (true)
yield return server.Accept();
} } static class IRImg
{
public static IEnumerable<Image> Snapshots()
{
while (true)
{
yield return IRCommon.Instance.GetBitmap();
}
} internal static IEnumerable<MemoryStream> Streams(this IEnumerable<Image> source)
{
MemoryStream ms = new MemoryStream(); foreach (var img in source)
{
ms.SetLength();
img.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
yield return ms;
} ms.Close();
ms = null; yield break;
} }

将上面代码中的这行 IRCommon.Instance.GetBitmap();改为自己的bitmap来源即可实现mjpeg图像传输

浏览器可直接输入 127.0.0.1:8080访问,chrome没问题,但是ie下,会一直下载图片

C#客户端可以用afroge实现浏览,具体可参考:在WPF中使用AForge控件

本项目来源:Motion JPEG Streaming Server   (codeproject)

C#实现MJPEG服务器的更多相关文章

  1. 适用于Windows和Linux的Yolo-v3和Yolo-v2(上)

    适用于Windows和Linux的Yolo-v3和Yolo-v2(上) https://github.com/eric-erki/darknetAB (用于对象检测的神经网络)-Tensor Core ...

  2. C#开源实现MJPEG流传输

    本文为 Dennis Gao 原创技术文章,发表于博客园博客,未经作者本人允许禁止任何形式的转载. 许久以前写了篇文章<基于.NET打造IP智能网络视频监控系统>,记录和介绍了自己几年来积 ...

  3. Web服务器部署浅析

    企业内网站 中小型企业一般将企业宣传网站外包给第三方进行统一设计.部署和运维.大型企业因为访问量和数据量有所增加,部分网站可能具备在线咨询或订单的功能,此类Web服务器采用最通用的IU机架式服务器以降 ...

  4. 基于mjpg_streamer视频服务器移植【转】

    本文转载自:http://blog.csdn.net/wavemcu/article/details/7539560 MJPG简介: MJPG是MJPEG的缩写,但是MJPEG还可以表示文件格式扩展名 ...

  5. M-JPEG和MPEG-4的区别 M-JPEG VS MPEG

    http://blog.sina.com.cn/s/blog_4b357b300100gre9.html M-JPEG VS MPEG http://blog.csdn.net/bluesky_sun ...

  6. 网络摄像头Androi端显示(mjpeg)源码分析

    main.xml <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:and ...

  7. M-JPEG、MPEG4、H.264都有何区别

    压缩方式是网络视频服务器和网络摄像机的核心技术,压缩方式很大程度上决定着图像的质量.压缩比.传输效率.传输速度等性能,它是评价网络视频服务器和网络摄像机性能优劣的重要一环.随着多媒体技术的发展,相继推 ...

  8. arm开发板6410/2440上mjpg-streamer网络视频服务器移植

    摄像头移植 一.环境 主机环境 :ubuntu 10.10         目标板 :FS-S5PC100 主机工具链 :gcc-4.4.5         交叉工具链 :arm-unknown-li ...

  9. 基于mjpg-streamer网络视频服务器移植

    MJPG简介: MJPG是MJPEG的缩写,但是MJPEG还可以表示文件格式扩展名. MJPEG 全名为 "Motion Joint Photographic Experts Group&q ...

随机推荐

  1. Lab2 Report

    1.安装SeleniumIDE插件 a)安装Firefox 17.0 - 56.*版本的firefox,下载地址为:http://ftp.mozilla.org/pub/firefox/release ...

  2. CAFFE(FAQ.1):Ubuntu 配置caffe 框架之数据库读取错误:ImportError: No module named lmdb解决办法

    Z: 在安装了caffe框架后需要读取大量的数据进行学习训练.比如在MNIST识别训练中,一般直接读图片会比较耗时,我们一般将图片转存为数据库中.目前主流的数据库有以下两种选择: LevelDB Lm ...

  3. day_02比特币的转账机制及其7个名词

    一:比特币的转账机制: 类似于普通转账:登录钱包--->选择转出(入)币的钱包地址--->填入转出数额及其手续费--->比特币签名--->提交比特币网络--->进行矿工打 ...

  4. mysql中的分区

    第18章:分区 目录 18.1. MySQL中的分区概述 18.2. 分区类型 18.2.1. RANGE分区 18.2.2. LIST分区 18.2.3. HASH分区 18.2.4. KEY分区 ...

  5. 通过JDBC驱动加载深刻理解线程上下文类加载器机制

    关于线程上下文类加载器已经在之前学得比较透了,作为一个收尾,这里用平常J2EE开发时JDBC连接Mysql数据库常见的一段代码通过分析它的底层进一步加深对线程上下文类加载器的理解,所以先来将连接应用代 ...

  6. ftp上传文件和下载文件

    public class FtpService { #region Fields and attributes private readonly int BufLen = 2048; /// < ...

  7. mpvue打小程序预览码

    喂,快给我打一个小程序预览码 前端大全 昨天 (点击上方公众号,可快速关注) 来源:写Bug segmentfault.com/a/1190000015336845 需求 开发小程序的朋友们随时都会听 ...

  8. 【转载】解决繁体、日文游戏乱码的五种方法 转载自:http://tieba.baidu.com/p/488627981

    方法1:转换区域 开始——设置——控制面板——区域和语言选项——分别选择“高级”和“区域选项”标签——在其下拉框中都选择“日语”(或“日本”)(选项有点多,慢慢找)——重启后即可生效. *某影注:日语 ...

  9. redis geo操作

    package club.newtech.qbike.trip.domain.service; import club.newtech.qbike.trip.domain.core.Status;im ...

  10. Java8-Stream-No.03

    import java.util.ArrayList; import java.util.List; import java.util.UUID; import java.util.concurren ...