0

I have an application that read the stream from a camera (MJPEG) and show it on the form in real time (in a picture box). This is working. This stream reading start when the user click on the button "Start".

What I want to do is that when the user click on a button "Stop", the stream between the button "Start" and "Stop" would be save on disk as a .mpg.

Right now, it write something on the disk, but I can't open it in Windows Media Player.

Here is the code to write the stream

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();

    }

Here is the place that call the function. This is in a loop and as I said, the video is playing in the 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);

Thanks a lot!

Jean-François Côté
  • 4,200
  • 11
  • 52
  • 88
  • Might be because you are not saving the file in the correct format. All files have file formats which include headers and data that describes the file. If you are only saving one section of the stream in bytes you might be messing up the file format and might be missing important data when you save it to disk. That would be my guess. – Mike Webb Dec 07 '10 at 16:32
  • I tried to copy the entire stream from the camera to file and the same things happend. Any other ideas? – Jean-François Côté Dec 07 '10 at 17:21
  • 1
    MJPEG is not the same as mpeg (or mpg). Two different codecs. Unless you want to transcode (==loose quality) to mpeg, try to keep is as mjpeg. If you need to contain it, you are better off using Quicktime or AVI than Mpeg. – BlueVoodoo Dec 07 '10 at 20:01

2 Answers2

1

There is an implementation @ https://net7mma.codeplex.com/SourceControl/latest specifically https://net7mma.codeplex.com/SourceControl/latest#Rtsp/Server/Streams/MJPEGSourceStream.cs

Something like this:

{
        // 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;
        }
    }
}
Jay
  • 3,276
  • 1
  • 28
  • 38
1

You need to set the content type on the stream, and include the frame boundry data. I would start by looking at the question MJPG VLC and HTTP Streaming.

Community
  • 1
  • 1
Greg Buehler
  • 3,897
  • 3
  • 32
  • 39