实现流写入,将图像作为mjpeg写入
public class MjpegWriter : IDisposable { private static byte[] CRLF = new byte[] { 13, 10 }; private static byte[] EmptyLine = new byte[] { 13, 10, 13, 10 }; 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 " + "Content-Type: multipart/x-mixed-replace; boundary=" + this.Boundary + " " ); 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(" "); this.Stream.Flush(); } private void Write(byte[] data) { this.Stream.Write(data, 0, data.Length); } private void Write(string text) { byte[] data = BytesOf(text); this.Stream.Write(data, 0, 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, 0, data.Length); if (count != 0) return Encoding.ASCII.GetString(data, 0, 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 = 111; } 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(8080); } 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(10); 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 > 0) 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(0); 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)