2013-02-11 27 views
13

SO ve google'ı aramadan birkaç gün sonra pes etmeye başlıyorum, bu yüzden burada da yayınlayabileceğimi düşündüm.Android: kamerayı mjpeg olarak aktarın

Bir tür görüntülü sohbet sunması gereken bir android uygulaması oluşturuyorum. Bu, gerçek zamana olabildiğince yakın olmalı, çeşitli protokolleri okudum ve yeni başlayanlar için MJPEG'i denemeye karar verdim (şimdilik sesle ilgili değil).

Veri akışı şu anda beni deli ediyor. Bağlantı kurulur, uygulama kamera önizleme karelerini akışa yazmaya başlar, ancak ne VLC ne de mplayer video oynatmaya başlar. Bağlantıyı izlemek verinin geldiğini ortaya çıkarır. Benim PC'de

try 
    { 
     ServerSocket server = new ServerSocket(8080); 

     socket = server.accept(); 

     server.close(); 

     Log.i(TAG, "New connection to :" + socket.getInetAddress()); 

     stream = new DataOutputStream(socket.getOutputStream()); 
     prepared = true; 
    } 
    catch (IOException e) 
    { 
     Log.e(TAG, e.getMessage(); 
    } 

Ben 'mplayer'la http://tabletIP:8080' yürütmek ve tablet bağlantı kaydeder (ve böylece başlar: Bu kod bir zaman uyumsuz görev tarafından yürütülür bağlanması

, bir dinleyici başarısı üzerine bildirilir streamer'ım ve kamera önizleme). Bu da VLC ile çalışır.

Oynatma Bu akışa başlığını yazıyor:

if (stream != null) 
{ 
    try 
    { 
     // send the header 
     stream.write(("HTTP/1.0 200 OK\r\n" + 
         "Server: iRecon\r\n" + 
         "Connection: close\r\n" + 
         "Max-Age: 0\r\n" + 
         "Expires: 0\r\n" + 
         "Cache-Control: no-cache, private\r\n" + 
         "Pragma: no-cache\r\n" + 
         "Content-Type: multipart/x-mixed-replace; " + 
         "boundary=--" + boundary + 
         "\r\n\r\n").getBytes()); 

     stream.flush(); 

     streaming = true; 
    } 
    catch (IOException e) 
    { 
     notifyOnEncoderError(this, "Error while writing header: " + e.getMessage()); 
     stop(); 
    } 
} 

Ardından Camera.onPreviewFrame() çağrı gibi aracılığıyla tetiklenir akış: atılan hiçbir istisnası vardır

@Override 
public void onPreviewFrame(byte[] data, Camera camera) 
{ 
    frame = data; 

    if (streaming) 
     mHandler.post(this); 
} 

@Override 
public void run() 
{ 
    // TODO: cache not filling? 
    try 
    { 
        // buffer is a ByteArrayOutputStream 
     buffer.reset(); 

     switch (imageFormat) 
     { 
      case ImageFormat.JPEG: 
       // nothing to do, leave it that way 
       buffer.write(frame); 
       break; 

      case ImageFormat.NV16: 
      case ImageFormat.NV21: 
      case ImageFormat.YUY2: 
      case ImageFormat.YV12: 
       new YuvImage(frame, imageFormat, w, h, null).compressToJpeg(area, 100, buffer); 
       break; 

      default: 
       throw new IOException("Error while encoding: unsupported image format"); 
     } 

     buffer.flush(); 

     // write the content header 
     stream.write(("--" + boundary + "\r\n" + 
         "Content-type: image/jpg\r\n" + 
         "Content-Length: " + buffer.size() + 
         "\r\n\r\n").getBytes()); 

     // Should omit the array copy 
     buffer.writeTo(stream); 

     stream.write("\r\n\r\n".getBytes()); 
     stream.flush(); 
    } 
    catch (IOException e) 
    { 
     stop(); 
     notifyOnEncoderError(this, e.getMessage()); 
    } 
} 

olduğunu. MHandler kendi HandlerThread içinde çalışır. Sadece bir AsyncTask kullanmayı denedim emin olmak için, boşuna (btw, bu daha iyi?).

Kodlanmış kareler android tarafında iyi, jpg dosyalarına kaydettim ve açabildim.

Tahminimce, verileri bir şekilde kümelemek zorundayım ya da soket ya da başka bir şey için bazı seçenekler belirlemem gerekiyor, ama .... iyi, takılıyorum.

tl; dr: VLC akışı oynamadığı, mplayer 'önbellek dolmuyor' diyor, muhtemelen son kod segmentinde sorun, ~ :)

iyisin yardımınıza ihtiyacımız var!

cevap

11

Anladım. Görünüşe göre, http/içerik başlıklarım berbattı. Uygun Başlıklar şöyle olmalıdır: sınır koymak

stream.write(("HTTP/1.0 200 OK\r\n" + 
          "Server: iRecon\r\n" + 
          "Connection: close\r\n" + 
          "Max-Age: 0\r\n" + 
          "Expires: 0\r\n" + 
          "Cache-Control: no-store, no-cache, must-revalidate, pre-check=0, post-check=0, max-age=0\r\n" + 
          "Pragma: no-cache\r\n" + 
          "Content-Type: multipart/x-mixed-replace; " + 
          "boundary=" + boundary + "\r\n" + 
          "\r\n" + 
          "--" + boundary + "\r\n").getBytes()); 

ve Tabii

stream.write(("Content-type: image/jpeg\r\n" + 
         "Content-Length: " + buffer.size() + "\r\n" + 
         "X-Timestamp:" + timestamp + "\r\n" + 
         "\r\n").getBytes()); 

buffer.writeTo(stream); 
stream.write(("\r\n--" + boundary + "\r\n").getBytes()); 

, kendi seçimdir. Ayrıca muhtemelen isteğe bağlı bazı alanlar (örneğin, Cache-Control'de en çok) vardır, fakat bu çalışır ve şu ana kadar onları soymak için çok tembelim. Önemli olan linebreaks ( \r\n şeyleri) ...

+1

Kodunu hatırlamak için lütfen Kameradan MJPEG'i gönderebilirsiniz. – Sourav301

+0

@Sourav Sınıfınız Camera.PreviewCallback uygulamasını uygulamak zorunda. Kamera çağrısı kameranızı başlattıktan sonra camera.setPreviewCallback (...). JPEGS'i geri almak için kalan soru zaten benim sorum var. – Managarm

+1

Sınırın ne olabileceğini merak edenler için, herhangi bir java dizgisi olabilir (alfabe, sayı ve özel karakterlerin çalışıp çalışmadığından emin değil). –

İlgili konular