2010-12-07 43 views
0

我有一个应用程序,从相机(MJPEG)读取流,并实时(在图片框中)在窗体上显示它。这是行得通的。当用户点击“开始”按钮时,此流读取开始。如何将MJPEG流保存到磁盘(C#.NET)?

我想要做的是,当用户点击一个按钮“停止”时,按钮“开始”和“停止”之间的流将作为一个.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

可能是因为您没有保存在正确的格式文件。所有文件都有文件格式,包括描述文件的标题和数据。如果您只以字节保存流的一部分,则可能会弄乱文件格式,并且在将其保存到磁盘时可能会丢失重要数据。这将是我的猜测。 – 2010-12-07 16:32:36

回答

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