首页 文章

创建我自己的MJPEG流

提问于
浏览
7

我正在尝试创建一个MJPEG流,我有一系列jpeg,我想将它们组合成一个流,以便用户只需点击一个URL并获得一个mjpeg流 . 最近几天我一直在尝试让它发挥作用,这可能是不可能的 . 我带来了空灵,并在网络上听到来自网络上的轴摄像头的数据包,并试图模仿它 . 我最初尝试使用WCF,并返回一个“流”但后来发现我需要在该流上设置内容类型,所以我尝试了WCF REST api,但是这也遇到了同样的问题 . 所以我现在只是使用一个简单的HTTPListener,并处理该事件 . 我更喜欢使用WCF,但我不确定它是否允许我返回具有正确内容类型的流 . 所以这就是我对httpListener的看法 .

在侦听器的处理程序中回调我放下以下内容 .

HttpListenerResponse response = context.Response;
        response.ProtocolVersion = new System.Version(1, 0);
        response.StatusCode = 200;
        response.StatusDescription = "OK";
        response.ContentType = "multipart/x-mixed-replace;boundary=" + BOUNDARY + "\r\n";
        System.IO.Stream output = response.OutputStream;
        Render(output);

Render方法看起来像这样

var writer = new StreamWriter(st);
        writer.Write("--" + BOUNDARY + "\r\n");
        while (true)
        {
            for (int i = 0; i < imageset.Length; i++)
            {
                var resource = Properties.Resources.ResourceManager.GetObject(imageset[i]) as Bitmap;
                var memStream = new MemoryStream();
                resource.Save(memStream,ImageFormat.Jpeg);
                byte[] imgBinaryData = memStream.ToArray();
                string s = Convert.ToBase64String(imgBinaryData);
                writer.Write("Content-type: image/jpeg\r\n");
                foreach (var s1 in imgBinaryData)
                {
                    writer.Write((char)s1);
                }
                writer.Write("\n--" + BOUNDARY + "\n");
                writer.Flush();
                Thread.Sleep(500);
            }
        }

在这一点上,我刚刚在dll上添加了几个jpeg图像作为属性,并且正在迭代它们,最终这些将是动态图像,但是现在我只想让它工作 .

根据我对MJPEG(规范)的理解,内容必须设置为multipart / x-mixed-replace和边界集 . 然后你只是通过边界消除流中的jpegs .

这似乎应该比我做的更简单,但我想知道我哪里出错了 . 如果我在IE或Firefox中加载此URL,它就会挂起 . 如果我尝试使用img标签创建一个存根html页面,其源代码是URL,那么我会得到一个损坏的图像 .

任何想法,谢谢

玩笑

2 回答

  • 7

    好吧,据我所知,这是你的问题:

    • StreamWriter 不是正确的选择 . 使用常规流写入功能很好 . 意思是,你应该用Byte数组而不是字符串来写数据 .

    • 您将图像的二进制数据转换为String64,浏览器不知道,仍然认为它是32位数据 .

    • 您的jpeg帧格式不正确 . 您还应该将 Content-Length 添加到帧头,以便接收流的应用程序知道何时停止读取而不必每次读取时检查下一个边界字符串 . 这将使读取数据的速度提高约4-5倍 . 你的新行字符也有不一致的地方,有些是"\r\n"而有些则是"\n" .

    • While循环是一个无限循环 .

    所以,这是解决方案 .

    注意:可能存在一些语法错误,但您可能会得到一般的想法 .

    private byte[] CreateHeader(int length)
    {
        string header = 
            "--" + BOUDARY + "\r\n" +
            "Content-Type:image/jpeg\r\n" +
            "Content-Length:" + length + "\r\n" +
            + "\r\n"; // there are always 2 new line character before the actual data
    
        // using ascii encoder is fine since there is no international character used in this string.
        return ASCIIEncoding.ASCII.GetBytes(header); 
    }
    
    public byte[] CreateFooter()
    {
        return ASCIIEncoding.ASCII.GetBytes("\r\n");
    }
    
    private void WriteFrame(Stream st, Bitmap image)
    {
        // prepare image data
        byte[] imageData = null;
    
        // this is to make sure memory stream is disposed after using
        using (MemoryStream ms = new MemoryStream())
        {
            image.Save(ms, ImageFormat.Jpeg);
    
            imageData = ms.ToArray();
        }
    
        // prepare header
        byte[] header = CreateHeader(imageData.Length);
        // prepare footer
        byte[] footer = CreateFooter();
    
        // Start writing data
        st.Write(header, 0, header.Length);
        st.Write(imageData, 0, imageData.Length);
        st.Write(footer, 0, footer.Length);
    }
    
    private void Render(Stream st)
    {
        for (int i = 0; i < imageset.Length; i++)
        {
            var resource = Properties.Resources.ResourceManager.GetObject(imageset[i]) as Bitmap;
            WriteFrame(st, resource);
            Thread.Sleep(500);
        }
    }
    
  • 0

    还有一个实现@ https://net7mma.codeplex.com/SourceControl/latest库可以将Http转码为Rtp兼容!

相关问题