设为首页收藏本站

LUPA开源社区

 找回密码
 注册
文章 帖子 博客
LUPA开源社区 首页 业界资讯 技术文摘 查看内容

C#开源实现MJPEG流传输

2013-8-29 11:29| 发布者: 红黑魂| 查看: 3186| 评论: 0|原作者: Dennis Gao|来自: 博客园

摘要:   目前已经实现了 UDP+RTP 方式在不同物理机之间的媒体流传输。当然,由于没有基于 .NET 的媒体流压缩实现,所以直接传输的裸图 Bitmap。不过要求不高,帧率低一些,机器性能强一些,看着也很流畅。  能在桌面客 ...

结果演示


  在可以成功发送流信息和图片信息后,就可以在浏览器上查看视频了。当然,我用的 Google Chrome 。IE10 好奇葩,它会把流当成文件不停的下载,搞不懂。


远程访问


  局域网内的无线设备,只要浏览器支持 MJPEG ,均可以查看视频。我测试了 iPad 上的 Safari 是可以的,但 Chrome 却直接解析成乱码。



  当然,如果在路由器上配置转发规则,就可以在外网访问了。


完整代码

复制代码
  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   }
复制代码

酷毙
1

雷人

鲜花

鸡蛋

漂亮

刚表态过的朋友 (1 人)

  • 快毕业了,没工作经验,
    找份工作好难啊?
    赶紧去人才芯片公司磨练吧!!

最新评论

关于LUPA|人才芯片工程|人才招聘|LUPA认证|LUPA教育|LUPA开源社区 ( 浙B2-20090187 浙公网安备 33010602006705号   

返回顶部