http - 创建我自己的 MJPEG 流

标签 http video streaming jpeg mjpeg

我正在尝试创建一个 MJPEG 流,我有一系列 jpeg,我想将它们放在一个流中,这样用户只需点击一个 URL 就可以获得一个 mjpeg 流。 在过去的几天里,我一直在努力让它发挥作用,但这可能是不可能的。我提出了 ethereal 并听取了来自网络某处的轴相机的数据包,并试图模仿它。我最初尝试使用 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 和边界集。然后您只需按边界删除流中的 jpeg。

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

任何想法,谢谢

乔希

最佳答案

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

  1. StreamWriter 不是正确的选择。使用常规的流写入功能就可以了。也就是说,您应该将数据写入字节数组而不是字符串。

  2. 你把图片的Binary数据转成String64,浏览器不知道,还以为是32位数据。

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

  4. 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);
    }
}

关于http - 创建我自己的 MJPEG 流,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1595945/

相关文章:

Cordova 地理定位插件 getCurrentPosition 已弃用

java - 压缩 Http header

HTML5 视频在 FireFox 浏览器中显示 "No Video With Supported format and MIME type Found"

mysql - 如何在我的 HTML5 应用程序中嵌入视频?

android - 录像中的 "time lapse mode"是什么?

java - 获取直播电视视频流(像素)

.htaccess - htaccess RewriteEngine 适用于 HTTP 但不适用于 HTTPS

android - 当所有异步 Http 请求完成时执行函数

PHP 流媒体视频处理程序

在 VLC 中使用多个字幕流对视频进行编码以进行流式传输