问题描述
我正在尝试创建一个 MJPEG 流,我有一系列 jpeg,我想将它们放在一个流中,以便用户只需点击一个 URL 即可获得一个 mjpeg 流.过去几天我一直在努力让它发挥作用,但这可能是不可能的.我已经提出了空灵并聆听了来自网络某处的轴摄像头的数据包,并试图模仿它.我最初尝试使用 WCF,并返回一个流",但后来发现我需要在该流上设置内容类型,因此我尝试了 WCF REST api,但遇到了同样的问题.所以我现在只是使用一个简单的 HTTPListener,并处理事件.我更喜欢使用 WCF,但我不确定它是否允许我返回具有正确内容类型的流.所以这就是我对 httpListener 的看法.
I'm trying to create an MJPEG stream, I have a series of jpegs that I want to put together into a stream so that a user can just hit a URL and get an mjpeg stream.I've been trying for the last few days to get this to work, and it may just not be possible. I've brought up ethereal and listened to the packets coming from an axis camera on the net somewhere, and tried to mimmick it. I originally tried using WCF, and returning a "stream" but then later found out that I would need to set the content type on that stream, so I then tried the WCF REST api, but that suffers from the same problem. so I am now just using a bare bones HTTPListener, and handling the event. I would greatly prefer to use WCF, but I'm not sure that it will allow me to return a stream with the right content type.so here's what I have for the httpListener .
在侦听器回调的处理程序中,我放置了以下内容.
in the handler of the listener call back I put the following.
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 + "
";
System.IO.Stream output = response.OutputStream;
Render(output);
Render 方法看起来像这样
the Render method looks like this
var writer = new StreamWriter(st);
writer.Write("--" + BOUNDARY + "
");
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
");
foreach (var s1 in imgBinaryData)
{
writer.Write((char)s1);
}
writer.Write("
--" + BOUNDARY + "
");
writer.Flush();
Thread.Sleep(500);
}
}
此时我刚刚在 dll 上添加了一些 jpeg 图像作为属性,并且正在对它们进行迭代,最终这些将是动态图像,但现在我只想让它工作.
At this point I've just added a few jpeg images as properties on the dll, and am iterating over them, eventually these will be dynamic images, but for now I just want to get the thing to work.
根据我对 MJPEG(规范)的理解,内容必须设置为 multipart/x-mixed-replace 和边界集.然后您只需通过边界分隔流内的 jpeg.
From what I understand about the MJPEG (spec) is that the content must be set to multipart/x-mixed-replace and a boundary set. and then you just deliminate the jpegs within the stream by the boundary.
这看起来应该比我做的更简单,但我想知道我哪里出错了.如果我在 IE 或 Firefox 中加载这个 URL,它就会挂起.如果我尝试使用 img 标签制作一个存根 html 页面,其来源是 URL,那么我会得到一个损坏的图像.
This seems like it should be simpler then I'm making it, but I'm wondering where I'm going wrong. if I load this URL up in IE or Firefox, it just hangs. if I try to make a stub html page with an img tag, whose source is the URL then I get a broken image.
任何想法,谢谢
乔希
推荐答案
好吧,据我所知,这里是您的问题:
Well, as far as I can tell, here are your issues:
StreamWriter
不是一个正确的选择.使用常规的流写入功能很好.这意味着,您应该将数据写入字节数组而不是字符串.
The
StreamWriter
is not a correct choice. Use a regular stream write function is fine. Meaning, you should write data in Byte array instead of string.
你把图片的二进制数据转成String64,浏览器不知道,还以为是32位数据.
You convert the Binary data of the image to String64, the browser does not known that, still thinking it is 32bit data.
您的 jpeg 帧格式不正确.您还应该将 Content-Length
添加到帧头,以便接收流的应用程序知道何时停止读取,而不必在每次读取时检查下一个边界字符串.这将导致读取数据的速度提高约 4-5 倍.而且你的换行符也有不一致的地方,有些是",有些是".
Your jpeg frame format is not correct. You should also add Content-Length
to the frame header so that the application that receive the stream know when to stop reading rather than having to check for the next boundary string every read. This will result in about 4-5 times faster in reading data. And there are also inconsistency in your new line character, some are "" while some others are "".
虽然循环是无限循环.
所以,这是解决方案.
注意:可能存在一些语法错误,但您可能已经大致了解了.
Note: There might be some syntax errors but you probably get the general idea.
private byte[] CreateHeader(int length)
{
string header =
"--" + BOUDARY + "
" +
"Content-Type:image/jpeg
" +
"Content-Length:" + length + "
" +
+ "
"; // 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("
");
}
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);
}
}
这篇关于创建我自己的 MJPEG 流的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!