
1 public class MJpegStreamingServer
2 {
3 private static string _contentLengthString = "__PayloadHeaderContentLength__";
4 private AsyncTcpServer _server;
5 private ConcurrentDictionary<string, TcpClient> _clients;
6
7 public MJpegStreamingServer(int listenPort)
8 : this(listenPort, "--dennisgao")
9 {
10 }
11
12 public MJpegStreamingServer(int listenPort, string boundary)
13 {
14 Port = listenPort;
15 Boundary = boundary;
16
17 _server = new AsyncTcpServer(Port);
18 _server.Encoding = Encoding.ASCII;
19 _clients = new ConcurrentDictionary<string, TcpClient>();
20 }
21
22 /// <summary>
23 /// 监听的端口
24 /// </summary>
25 public int Port { get; private set; }
26
27 /// <summary>
28 /// 分隔符
29 /// </summary>
30 public string Boundary { get; private set; }
31
32 /// <summary>
33 /// 流头部
34 /// </summary>
35 public string StreamHeader
36 {
37 get
38 {
39 return "HTTP/1.1 200 OK" +
40 "\r\n" +
41 "Content-Type: multipart/x-mixed-replace; boundary=" + this.Boundary +
42 "\r\n";
43 }
44 }
45
46 /// <summary>
47 /// 图片头部
48 /// </summary>
49 public string PayloadHeader
50 {
51 get
52 {
53 return "\r\n" +
54 this.Boundary +
55 "\r\n" +
56 "Content-Type: image/jpeg" +
57 "\r\n" +
58 "Content-Length: " + _contentLengthString +
59 "\r\n\r\n";
60 }
61 }
62
63 public void Start()
64 {
65 _server.Start(10);
66 _server.ClientConnected += new EventHandler<TcpClientConnectedEventArgs>(OnClientConnected);
67 _server.ClientDisconnected += new EventHandler<TcpClientDisconnectedEventArgs>(OnClientDisconnected);
68 }
69
70 public void Stop()
71 {
72 _server.Stop();
73 _server.ClientConnected -= new EventHandler<TcpClientConnectedEventArgs>(OnClientConnected);
74 _server.ClientDisconnected -= new EventHandler<TcpClientDisconnectedEventArgs>(OnClientDisconnected);
75 }
76
77 private void OnClientConnected(object sender, TcpClientConnectedEventArgs e)
78 {
79 _clients.AddOrUpdate(e.TcpClient.Client.RemoteEndPoint.ToString(), e.TcpClient, (n, o) => { return e.TcpClient; });
80 }
81
82 private void OnClientDisconnected(object sender, TcpClientDisconnectedEventArgs e)
83 {
84 TcpClient clientToBeThrowAway;
85 _clients.TryRemove(e.TcpClient.Client.RemoteEndPoint.ToString(), out clientToBeThrowAway);
86 }
87
88 public void Write(Image image)
89 {
90 if (_server.IsRunning)
91 {
92 byte[] payload = BytesOf(image);
93
94 WriteStreamHeader();
95 WritePayload(payload);
96 }
97 }
98
99 private void WriteStreamHeader()
100 {
101 if (_clients.Count > 0)
102 {
103 foreach (var item in _clients)
104 {
105 Logger.Debug(string.Format(CultureInfo.InvariantCulture,
106 "Writing stream header, {0}, {1}{2}", item.Key, Environment.NewLine, StreamHeader));
107
108 _server.SyncSend(item.Value, StreamHeader);
109
110 TcpClient clientToBeThrowAway;
111 _clients.TryRemove(item.Key, out clientToBeThrowAway);
112 }
113 }
114 }
115
116 private void WritePayload(byte[] payload)
117 {
118 string payloadHeader = this.PayloadHeader.Replace(_contentLengthString, payload.Length.ToString());
119 string payloadTail = "\r\n";
120
121 Logger.Debug(string.Format(CultureInfo.InvariantCulture,
122 "Writing payload header, {0}{1}", Environment.NewLine, payloadHeader));
123
124 byte[] payloadHeaderBytes = _server.Encoding.GetBytes(payloadHeader);
125 byte[] payloadTailBytes = _server.Encoding.GetBytes(payloadTail);
126 byte[] packet = new byte[payloadHeaderBytes.Length + payload.Length + payloadTail.Length];
127 Buffer.BlockCopy(payloadHeaderBytes, 0, packet, 0, payloadHeaderBytes.Length);
128 Buffer.BlockCopy(payload, 0, packet, payloadHeaderBytes.Length, payload.Length);
129 Buffer.BlockCopy(payloadTailBytes, 0, packet, payloadHeaderBytes.Length + payload.Length, payloadTailBytes.Length);
130
131 _server.SendToAll(packet);
132 }
133
134 private byte[] BytesOf(Image image)
135 {
136 MemoryStream ms = new MemoryStream();
137 image.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
138
139 byte[] payload = ms.ToArray();
140
141 return payload;
142 }
143 }
