我有一个应用程序从相机(MJPEG)读取流并在表格上实时显示(在图片框中)。这很有效。当用户点击“开始”按钮时,该流读取开始。
我想要做的是当用户点击“停止”按钮时,“开始”和“停止”按钮之间的流将作为.mpg保存在磁盘上。
现在,它在磁盘上写了一些内容,但我无法在Windows Media Player中打开它。
以下是编写流
的代码private void ReadWriteStream(byte[] buffer, int start, int lenght, Stream writeStream)
{
Stream readStream = new MemoryStream(buffer, start, lenght);
int bytesRead = readStream.Read(buffer, 0, m_readSize);
// write the required bytes
while (bytesRead > 0 && !m_bStopLecture)
{
writeStream.Write(buffer, 0, bytesRead);
bytesRead = readStream.Read(buffer, 0, m_readSize);
}
readStream.Close();
}
这是调用该函数的地方。这是一个循环,正如我所说,视频正在PictureBox中播放。
// image at stop
Stream towrite = new MemoryStream(buffer, start, stop - start);
Image img = Image.FromStream(towrite);
imgSnapshot.Image = img;
// write to the stream
ReadWriteStream(buffer, start, stop - start, writeStream);
非常感谢!
答案 0 :(得分:1)
您需要在流上设置内容类型,并包含帧边界数据。我首先要看问题MJPG VLC and HTTP Streaming。
答案 1 :(得分:1)
@ https://net7mma.codeplex.com/SourceControl/latest具体实施https://net7mma.codeplex.com/SourceControl/latest#Rtsp/Server/Streams/MJPEGSourceStream.cs
这样的事情:
{
// buffer to read stream
byte[] buffer = new byte[bufSize];
// JPEG magic number
byte[] jpegMagic = new byte[] { 0xFF, 0xD8, 0xFF };
int jpegMagicLength = 3;
ASCIIEncoding encoding = new ASCIIEncoding();
while (!stopEvent.WaitOne(0, false))
{
// reset reload event
reloadEvent.Reset();
// HTTP web request
HttpWebRequest request = null;
// web responce
WebResponse response = null;
// stream for MJPEG downloading
Stream stream = null;
// boundary betweeen images (string and binary versions)
byte[] boundary = null;
string boudaryStr = null;
// length of boundary
int boundaryLen;
// flag signaling if boundary was checked or not
bool boundaryIsChecked = false;
// read amounts and positions
int read, todo = 0, total = 0, pos = 0, align = 1;
int start = 0, stop = 0;
// align
// 1 = searching for image start
// 2 = searching for image end
try
{
// create request
request = (HttpWebRequest)WebRequest.Create(m_Source);
// set user agent
if (userAgent != null)
{
request.UserAgent = userAgent;
}
// set proxy
if (proxy != null)
{
request.Proxy = proxy;
}
// set timeout value for the request
request.Timeout = requestTimeout;
// set login and password
if ((login != null) && (password != null) && (login != string.Empty))
request.Credentials = new NetworkCredential(login, password);
// set connection group name
if (useSeparateConnectionGroup)
request.ConnectionGroupName = GetHashCode().ToString();
// force basic authentication through extra headers if required
if (forceBasicAuthentication)
{
string authInfo = string.Format("{0}:{1}", login, password);
authInfo = Convert.ToBase64String(Encoding.Default.GetBytes(authInfo));
request.Headers["Authorization"] = "Basic " + authInfo;
}
// get response
response = request.GetResponse();
// check content type
string contentType = response.ContentType;
string[] contentTypeArray = contentType.Split('/');
// "application/octet-stream"
if ((contentTypeArray[0] == "application") && (contentTypeArray[1] == "octet-stream"))
{
boundaryLen = 0;
boundary = new byte[0];
}
else if ((contentTypeArray[0] == "multipart") && (contentType.Contains("mixed")))
{
// get boundary
int boundaryIndex = contentType.IndexOf("boundary", 0);
if (boundaryIndex != -1)
{
boundaryIndex = contentType.IndexOf("=", boundaryIndex + 8);
}
if (boundaryIndex == -1)
{
// try same scenario as with octet-stream, i.e. without boundaries
boundaryLen = 0;
boundary = new byte[0];
}
else
{
boudaryStr = contentType.Substring(boundaryIndex + 1);
// remove spaces and double quotes, which may be added by some IP cameras
boudaryStr = boudaryStr.Trim(' ', '"');
boundary = encoding.GetBytes(boudaryStr);
boundaryLen = boundary.Length;
boundaryIsChecked = false;
}
}
else
{
throw new Exception("Invalid content type.");
}
// get response stream
stream = response.GetResponseStream();
stream.ReadTimeout = requestTimeout;
// loop
while ((!stopEvent.WaitOne(0, false)) && (!reloadEvent.WaitOne(0, false)))
{
// check total read
if (total > bufSize - readSize)
{
total = pos = todo = 0;
}
// read next portion from stream
if ((read = stream.Read(buffer, total, readSize)) == 0)
throw new ApplicationException();
total += read;
todo += read;
// increment received bytes counter
bytesReceived += read;
// do we need to check boundary ?
if ((boundaryLen != 0) && (!boundaryIsChecked))
{
// some IP cameras, like AirLink, claim that boundary is "myboundary",
// when it is really "--myboundary". this needs to be corrected.
pos = Utility.ContainsBytes(buffer, ref start, ref read, boundary, 0, boundary.Length);
// continue reading if boudary was not found
if (pos == -1)
continue;
for (int i = pos - 1; i >= 0; i--)
{
byte ch = buffer[i];
if ((ch == (byte)'\n') || (ch == (byte)'\r'))
{
break;
}
boudaryStr = (char)ch + boudaryStr;
}
boundary = encoding.GetBytes(boudaryStr);
boundaryLen = boundary.Length;
boundaryIsChecked = true;
}
// search for image start
if ((align == 1) && (todo >= jpegMagicLength))
{
start = Utility.ContainsBytes(buffer, ref pos, ref todo, jpegMagic, 0, jpegMagicLength);
if (start != -1)
{
// found JPEG start
pos = start + jpegMagicLength;
todo = total - pos;
align = 2;
}
else
{
// delimiter not found
todo = jpegMagicLength - 1;
pos = total - todo;
}
}
// search for image end ( boundaryLen can be 0, so need extra check )
while ((align == 2) && (todo != 0) && (todo >= boundaryLen))
{
stop = Utility.ContainsBytes(buffer, ref start, ref read,
(boundaryLen != 0) ? boundary : jpegMagic,
pos, todo);
if (stop != -1)
{
pos = stop;
todo = total - pos;
// increment frames counter
framesReceived++;
// image at stop
using (Bitmap bitmap = (Bitmap)Bitmap.FromStream(new MemoryStream(buffer, start, stop - start)))
{
// notify client
Packetize(bitmap);
}
// shift array
pos = stop + boundaryLen;
todo = total - pos;
Array.Copy(buffer, pos, buffer, 0, todo);
total = todo;
pos = 0;
align = 1;
}
else
{
// boundary not found
if (boundaryLen != 0)
{
todo = boundaryLen - 1;
pos = total - todo;
}
else
{
todo = 0;
pos = total;
}
}
}
}
}
catch (ApplicationException)
{
// do nothing for Application Exception, which we raised on our own
// wait for a while before the next try
Thread.Sleep(250);
}
catch (ThreadAbortException)
{
break;
}
catch (Exception exception)
{
// wait for a while before the next try
Thread.Sleep(250);
}
finally
{
// abort request
if (request != null)
{
request.Abort();
request = null;
}
// close response stream
if (stream != null)
{
stream.Close();
stream = null;
}
// close response
if (response != null)
{
response.Close();
response = null;
}
}
// need to stop ?
if (stopEvent.WaitOne(0, false))
break;
}
}
}