代码之家  ›  专栏  ›  技术社区  ›  Joshua

创建我自己的MJPEG流

  •  7
  • Joshua  · 技术社区  · 15 年前

    我正在尝试创建一个MJPEG流,我有一系列JPEG,我想把它们放在一个流中,这样用户就可以点击一个URL,得到一个MJPEG流。

    在侦听器回调的处理程序中,我放置了以下内容。

            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);
    

            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和边界集。然后你只需通过边界消除流中的JPEG图像。

    这看起来应该比我做的更简单,但我想知道我哪里做错了。如果我在IE或Firefox中加载此URL,它就会挂起。如果我试图创建一个带有img标记的存根html页面,其源是URL,那么我会得到一个损坏的图像。

    有什么想法吗,谢谢

    乔希

    2 回复  |  直到 15 年前
        1
  •  7
  •   Long Ngo    15 年前

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

    1. StreamWriter 这不是一个正确的选择。使用常规流写入函数是可以的。也就是说,您应该以字节数组而不是字符串形式写入数据。

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

    3. 您的jpeg帧格式不正确。您还应该添加 Content-Length 发送到帧头,以便接收流的应用程序知道何时停止读取,而不是每次读取都必须检查下一个边界字符串。这将使读取数据的速度提高约4-5倍。并且新行字符中也存在不一致性,有些是“\r\n”,有些是“\n”。

    4. 而循环是一个无限循环。

    注意:可能有一些语法错误,但您可能已经了解了大概的意思。

    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);
        }
    }
    
        2
  •  0
  •   Jay    11 年前

    https://net7mma.codeplex.com/SourceControl/latest 那里的库可以动态地将Http转换为Rtp兼容!