2

是否有人熟悉通过 HTTP 协议发送的 MJPEG 文件中提取标头的方法?我在 C# 中遇到过 HttpClient 类,但我对它缺乏经验,而且我还没有看到任何有关 MJPEG 流的示例。我感谢您的帮助。

4

2 回答 2

2

我不是专家,但我认为 MJPEG 流是包含在两个字节中的单个 JPEG 图片流:FFD8 和 FFD9。

使用优化的裸 C# 模块(如数组、测试和循环),您可以解析调用 HttpClient 返回的流以剥离其 JPEG 帧。

这是显示流的快速、简单和愚蠢的东西。唯一的幻想是使用 HttpClient 及其异步函数:

async static Task Start(string url, Action<byte[]> action, int bufSize = 1024, CancellationToken? tk = null) {

    var myTk = tk.HasValue ? tk.Value : CancellationToken.None;

    using(var cli = new HttpClient()) {

        var streamBuffer = new byte[bufSize];

        // Give it the maximum size in bytes of your picture
        var frameBuffer = new List<byte>(1024 * 1024);

        var ff = false;
        var inPic = false;

        using(var stream = await cli.GetStreamAsync(url).ConfigureAwait(false)) {

            while(!myTk.IsCancellationRequested) {

                var l = await stream.ReadAsync(streamBuffer, 0, bufSize).ConfigureAwait(false);
                var idx = 0;

                while(idx < l) {
                    var c = streamBuffer[idx++];

                    // We have found a FF
                    if(c == 0xff) {
                        ff = true;
                    }
                    // We found a JPEG picture start
                    else if(ff && c == 0xd8) {
                        frameBuffer.Clear();
                        frameBuffer.Add(0xff);
                        frameBuffer.Add(0xd8);
                        if(inPic) {
                            Console.WriteLine("Skipped frame : end expected");
                        }
                        ff = false;
                        inPic = true;
                    }
                    // We found a JPEG picture end
                    else if(ff && c == 0xd9) {
                        frameBuffer.Add(0xff);
                        frameBuffer.Add(0xd9);

                        // Send the JPEG picture as an event
                        action(frameBuffer.ToArray());

                        ff = false;
                        if(!inPic) {
                            Console.WriteLine("Skipped frame : start expected");
                        }
                        inPic = false;
                    }
                    // We are inside a JPEG picture
                    else if(inPic) {
                        if(ff) {
                            frameBuffer.Add(0xff);
                            ff = false;
                        }
                        frameBuffer.Add(c);
                    }
                }
            }
        }
    }
}

要试一试,在 Winforms 应用程序中有一个 PictureBox,然后在 button_click 中:

var s = SynchronizationContext.Current;

// assuming pb is your PictureBox

await Start("http://whateverurlthatstreamsmjpegs.com", 
    img => {
        s.Post(new SendOrPostCallback(i => {
            if(pb.Image != null)
                pb.Image.Dispose();
            pb.Image = (Image)new ImageConverter().ConvertFrom((byte[])i);
        }), img);
    }, 1024, CancellationToken.None);

这与专业的 MJPEG 解码器相去甚远,并且仍然存在一些错误,但我在 gist 中提供了一个改进得多的版本。gist 版本还包括用于观看来自某些 IP 摄像机的流的登录和密码功能。

于 2016-02-24T13:14:11.657 回答
0

在 Ch9 上试试这个 Coding4Fun 项目

http://channel9.msdn.com/coding4fun/articles/MJPEG-Decoder

于 2013-09-27T15:50:25.290 回答