如何将MJPEG流保存到磁盘(C#.NET)?

时间:2010-12-07 16:21:08

标签: c# .net save mjpeg

我有一个应用程序从相机(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);

非常感谢!

2 个答案:

答案 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;
        }
    }
}