2013-02-11 57 views
13

SOとGoogleを検索して数日後、私はあきらめ始めているので、私はここに投稿するかもしれないと思った。Android:mjpegとしてカメラをストリーミング

私はビデオチャットのいくつかの種類を提供する必要がありますアンドロイドアプリを作成しています。これはできるだけリアルタイムに近いべきであるので、私は様々なプロトコルについて読んで、まずMJPEGを試してみることに決めました。

今、データをストリーミングすることは私にとって大きな打撃を与えています。接続が確立されると、アプリケーションはカメラプレビューフレームをストリームに書き出し始めますが、VLCもmplayerもビデオの再生を開始しません。接続を監視すると、データが到着していることがわかります。

このコードは、リスナーが成功した場合に通知された非同期タスクが実行される の接続:私のPC上で

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

私は「mplayerのhttp://tabletIP:8080」を実行し、タブレットは接続を登録する(ひいてはを開始私のストリーマーとカメラのプレビュー)。これはVLCでも動作します。

ストリーミングこれは、ストリームにヘッダを書き込みます:例外投げはありません

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

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

はその後ストリーミングがCamera.onPreviewFrame()コールバックによってトリガされます。 mHandlerはそれ自身のHandlerThreadで動作します。ちょうど私がAsyncTaskを使用しようとしたことを確かめるために、役に立たない(btw、これは良い?)。

エンコードされたフレームはAndroid側で問題なく、jpgファイルに保存して開くことができました。

私の推測では、どうにかしてデータをクラスタ化するか、ソケットなどのオプションを設定する必要があると思いますが... ....まあ、私は立ち往生しています。

TL; DR: VLCは、ストリームを再生していないが、MPlayerのは、 'キャッシュが埋めていない' と言い、おそらく最後のコードセグメントにおける問題、助けを必要と〜:)

は親切にありがとうございます!

答えて

11

私はそれを得ました。私のhttp-/content-headersのように混乱していたようです。適切なヘッダは次のようになります。もちろん

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

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

、境界線をどこに置くか、あなた自身の選択です。また、おそらくオプションのフィールド(キャッシュコントロールのほとんど)がありますが、これまでは機能していましたが、今まではそれらを取り除くのが面倒でした。重要な部分は改行(\r\nのもの)を覚えておくことです...

+1

カメラからMJPEGを取得するコードを投稿してください。 – Sourav301

+0

@SouravあなたのクラスはCamera.PreviewCallbackを実装しなければなりません。カメラを初期化した後、camera.setPreviewCallback(...)を呼び出します。 JPEGSを取得するための残りの部分はすでに私の質問です。 – Managarm

+1

境界線がどのようにすべきか疑問に思う人には、Java文字列(アルファベットで構成されていて、数字や特殊文字が機能するかどうかはわかりません)でもかまいません。 –

関連する問題