2016-10-12 77 views
1

もう一度Androids MediaCodecクラスに関する私の質問。私は生のh264コンテンツをデコードし、その結果を2つのTextureViewに表示することに成功しました。 h264ストリームは、OpenGLシーンを実行しているサーバーからのものです。シーンにはカメラがあり、ユーザの入力に反応します。サーバー上の入力とスマートフォンでの実際の結果との間のレイテンシをさらに減らすために、私はMediaCodecs非同期モードを使用することを考えていました。ここで は、同期および非同期、私は両方のバリアントを設定する方法である:Android MediaCodecは非同期モードでは同期モードよりも遅いですか?

非同期:

//decoderCodec is "video/avc" 
MediaFormat fmt = MediaFormat.createVideoFormat(decoderCodec, 1280,720); 
codec.setCallback(new MediaCodec.Callback() { 

    @Override 
    public void onInputBufferAvailable(MediaCodec codec, int index) { 
     byte[] frameData; 
     try { 
      frameData = frameQueue.take(); //this call is blocking 
     } catch (InterruptedException e) { 
      return; 
     } 

     ByteBuffer inputData = codec.getInputBuffer(index); 
     inputData.clear(); 
     inputData.put(frameData); 

     codec.queueInputBuffer(index, 0, frameData.length, 0, 0); 
    } 

    @Override 
    public void onOutputBufferAvailable(MediaCodec codec, int index, MediaCodec.BufferInfo info) { 
     codec.releaseOutputBuffer(index, true); 
    } 

    //The two other methods are left blank at the moment. 

}); 


codec.configure(fmt, surface, null, 0); 
codec.start(); 

同期:codec.setCallback(...)一部を除いて、非同期のように設定され、両方の変異体が中に存在するクラスがあります。 Runnableを。

public void run() { 

    while(!Thread.interrupted()) 
    { 
     if(!IS_ASYNC) { 
      byte[] frameData; 
      try { 
       frameData = frameQueue.take(); //this call is blocking 
      } catch (InterruptedException e) { 
       break; 
      } 

      int inIndex = codec.dequeueInputBuffer(BUFFER_TIMEOUT); 

      if (inIndex >= 0) { 
       ByteBuffer input = codec.getInputBuffer(inIndex); 
       input.clear(); 
       input.put(frameData); 
       codec.queueInputBuffer(inIndex, 0, frameData.length, 0, 0); 
      } 

      MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo(); 
      int outIndex = codec.dequeueOutputBuffer(bufferInfo, BUFFER_TIMEOUT); 

      if(outIndex >= 0) 
       codec.releaseOutputBuffer(outIndex, true); 
     } 
     else sleep(3000); //Just for testing, if we are in Async, this thread has nothing to do actually... 
    } 
} 

の両方が仕事に近づくが、私は、同期モードでプレイ動画がはるかにsmootheであることを観察していますrとレイテンシも低くなります。

frameQueueLinkedBlockingDequeであると私は思った、新しいフレームデータが到着するのを同期デコーダが長すぎる待機している場合、デコード出力はすでに利用可能かもしれないがために表示されていないので、私は非同期モードを使用してのアイデアを思い付きましたキューのブロック性質の一方、私は忙しい待って、キュー、inputBuffersとoutputBuffersすべての時間をポーリングするような何かをしたいと思っていません。

私はコールバックを使用してAsyncModeを試しましたが、結果は同期モードより悪くなっています。皆さんへの質問は、今、なぜですか?私は非同期モードを誤用するのですか、それとも別のものですか?

フィードバックありがとうございます。

クリストフ

答えて

3

onInputBufferAvailableでのブロッキング呼び出しが犯人である場合、私は驚かないだろう。同じスレッド内でonInputBufferAvailableonOutputBufferAvailableの両方が呼び出される可能性があり、一方をブロックするともう一方のスレッドは実行を停止します。

私はonInputBufferAvailableのバッファインデックスをいくつかのキューにプッシュし、別のスレッドに現在利用可能な別のスレッドがあることを通知してから、この2番目のスレッドがキューからバッファを待ち、入力データのフェッチをブロックします。

+0

あなたは正しいです。同じスレッドから呼び出されたようです。私は作業コードで質問を更新します。 – Christoph

+0

元の質問を新しい固定コードで更新しないでください。後で誰かがこの問題を読んで(まあまあです!)、全く固定されたコードで質問を読んでも意味がありません。固定コードを共有する場合は、固定コードを追加します。質問の終わりに別のセクションとして明示的に編集としてマークし、これが固定バージョンであるとのコメントを表示します。 – mstorsjo

関連する問題