2009-10-20 29 views
7

Tôi đang cố gắng tạo luồng MJPEG, tôi có một loạt các jpeg mà tôi muốn kết hợp lại thành một luồng để người dùng chỉ có thể nhấn một URL và nhận luồng mjpeg. Tôi đã cố gắng trong vài ngày qua để có được điều này để làm việc, và nó chỉ có thể không được. Tôi đã mang đến sự thanh thản và lắng nghe những gói dữ liệu đến từ một máy quay trục trên mạng ở đâu đó, và cố gắng mimmick nó. Ban đầu tôi đã thử sử dụng WCF và trả về một "luồng" nhưng sau đó phát hiện ra rằng tôi sẽ cần phải đặt loại nội dung trên luồng đó, vì vậy tôi đã thử REST REST của WCF, nhưng điều đó cũng gặp vấn đề tương tự. vì vậy tôi bây giờ chỉ cần sử dụng một HTTPListener xương trần, và xử lý sự kiện này. Tôi rất muốn sử dụng WCF, nhưng tôi không chắc chắn rằng nó sẽ cho phép tôi trả về một luồng với kiểu nội dung phù hợp. vì vậy đây là những gì tôi có cho httpListener.tạo luồng MJPEG của riêng tôi

trong trình xử lý cuộc gọi của người nghe lại, tôi đặt như sau.

 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 + "\r\n"; 
     System.IO.Stream output = response.OutputStream; 
     Render(output); 

Render phương pháp trông như thế này

 var writer = new StreamWriter(st); 
     writer.Write("--" + BOUNDARY + "\r\n"); 
     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\r\n"); 
       foreach (var s1 in imgBinaryData) 
       { 
        writer.Write((char)s1); 
       } 
       writer.Write("\n--" + BOUNDARY + "\n"); 
       writer.Flush(); 
       Thread.Sleep(500); 
      } 
     } 

Tại thời điểm này tôi đã chỉ cần thêm một vài hình ảnh jpeg như tài sản trên dll, và đang lặp qua chúng, cuối cùng chúng sẽ được hình ảnh năng động , nhưng bây giờ tôi chỉ muốn có được thứ để làm việc.

Từ những gì tôi hiểu về MJPEG (spec) là nội dung phải được đặt thành multipart/x-mixed-replace và một bộ ranh giới. và sau đó bạn chỉ cần phân định các jpeg trong luồng theo ranh giới.

Điều này có vẻ đơn giản nên đơn giản hơn khi tôi đang thực hiện, nhưng tôi tự hỏi mình sẽ sai ở đâu. nếu tôi tải URL này lên trong IE hoặc Firefox, nó sẽ bị treo. nếu tôi cố gắng tạo một trang html sơ khai với một thẻ img, nguồn của nó là URL thì tôi sẽ nhận được một hình ảnh bị hỏng.

Bất kỳ ý tưởng, nhờ

Josh

Trả lời

7

Vâng, như xa như tôi có thể nói, đây là những vấn đề của bạn:

  1. Các StreamWriter không phải là một lựa chọn đúng. Sử dụng chức năng ghi dòng thông thường là tốt. Có nghĩa là, bạn nên ghi dữ liệu trong mảng Byte thay vì chuỗi.

  2. Bạn chuyển đổi dữ liệu nhị phân của hình ảnh thành String64, trình duyệt không biết điều đó, vẫn nghĩ rằng đó là dữ liệu 32 bit.

  3. Định dạng khung hình jpeg của bạn không chính xác. Bạn cũng nên thêm Content-Length vào tiêu đề khung để ứng dụng nhận luồng biết khi nào nên dừng đọc thay vì phải kiểm tra chuỗi ranh giới tiếp theo sau mỗi lần đọc. Điều này sẽ dẫn đến dữ liệu đọc nhanh hơn khoảng 4-5 lần. Và cũng có mâu thuẫn trong ký tự dòng mới của bạn, một số là "\ r \ n" trong khi một số khác là "\ n".

  4. Vòng lặp trong khi là vòng lặp vô hạn.

Vì vậy, đây là giải pháp.

Lưu ý: Có thể có một số lỗi cú pháp nhưng bạn có thể nhận được ý tưởng chung.

private byte[] CreateHeader(int length) 
{ 
    string header = 
     "--" + BOUDARY + "\r\n" + 
     "Content-Type:image/jpeg\r\n" + 
     "Content-Length:" + length + "\r\n" + 
     + "\r\n"; // 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("\r\n"); 
} 

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); 
    } 
} 
+3

Tôi nhận ra điều này đã hơn một tuổi ... nhưng vẫn vậy. Các thông số kỹ thuật nói rằng phải có một không gian duy nhất ('', ASCII 32) giữa dấu hai chấm sau tên tiêu đề 'và giá trị tiêu đề. –

Các vấn đề liên quan