2014-01-17 9 views
8

Ich benutze Android MediaCodec API, um h264 Frames zu decodieren. Ich konnte die Frames in der Ansicht decodieren und rendern. Mein Problem ist, dass der Decoder viele Frames verpasst, besonders die ersten Frames. DecodeMediaCodec.dequeueOutputBuffer() Rückgabe -1. aÜber 150 h264 Bilder, gerade entschlüsselt 43 Bilder. Ich kann nicht finden, wo das Problem ist. Hier sind meine Codes.Android MediaCodec entschlüsseln h264 rohe frame

/** 
* init decoder 
*/ 
private void initDecodeMediaCodec() 
{ 
    mDecodeMediaCodec = MediaCodec.createDecoderByType(MIME_TYPE); 
    MediaFormat format = MediaFormat.createVideoFormat(MIME_TYPE, 
      VIDEO_WIDTH_640, 
      VIDEO_HEIGHT_480); 

    mDecodeMediaCodec.configure(format, 
      new Surface(mRemoteVideoView.getSurfaceTexture()), 
      null, 
      0); 
    mDecodeMediaCodec.start(); 
    mDecodeInputBuffers = mDecodeMediaCodec.getInputBuffers(); 
    System.out.println("decode-----" 
      + mDecodeMediaCodec.getCodecInfo().getName()); 
} 

Nach Decoder initial, ich werde Decoder-Thread starten.

/** 
* 
* @param frameData 
*/ 
private void decode() 
{ 
    new Thread(new Runnable() 
    { 
     @Override 
     public void run() 
     { 
      while (true) 
      { 
       ByteBuffer decodeDataBuffer = null; 
       try 
       { 
        //take h264 frame from cache queue 
        decodeDataBuffer = decodeDataQuene.take(); 
       } 
       catch (InterruptedException e) 
       { 
        e.printStackTrace(); 
       } 


       BufferInfo info = new BufferInfo(); 
       int inputBufferIndex = mDecodeMediaCodec.dequeueInputBuffer(-1); 
       System.out.println("inputBufferIndex: " + inputBufferIndex); 
       if (inputBufferIndex >= 0) 
       { 
        ByteBuffer buffer = mDecodeInputBuffers[inputBufferIndex]; 
        buffer.clear(); 
        buffer.put(decodeDataBuffer.array()); 
        mDecodeMediaCodec.queueInputBuffer(inputBufferIndex, 
          0, 
          decodeDataBuffer.array().length, 
          0, 
          0); 
        decodeDataBuffer.clear(); 
        decodeDataBuffer = null; 
       } 

       int outputBufferIndex = mDecodeMediaCodec.dequeueOutputBuffer(info, 
         1000); 
       System.out.println("outputBufferIndex: " 
         + outputBufferIndex); 
       do 
       { 

        if (outputBufferIndex == MediaCodec.INFO_TRY_AGAIN_LATER) 
        { 
         //no output available yet 
        } 
        else if (outputBufferIndex == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) 
        { 
         //encodeOutputBuffers = mDecodeMediaCodec.getOutputBuffers(); 
        } 
        else if (outputBufferIndex == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) 
        { 
         MediaFormat formats = mDecodeMediaCodec.getOutputFormat(); 
         //mediaformat changed 
        } 
        else if (outputBufferIndex < 0) 
        { 
         //unexpected result from encoder.dequeueOutputBuffer 
        } 
        else 
        { 
         mDecodeMediaCodec.releaseOutputBuffer(outputBufferIndex, 
           true); 

         outputBufferIndex = mDecodeMediaCodec.dequeueOutputBuffer(info, 
           0); 
         System.out.println("inner outputBufferIndex: " 
           + outputBufferIndex); 
        } 
       } while (outputBufferIndex > 0); 
      } 
     } 
    }).start(); 
} 

Jeder weiß, warum? Ich habe Ihre help.My Android-Gerät Nexus hoffen ist 7.

Antwort

5

Erste -1 zurück von MediaCodec#dequeueOutputBuffer() ist normal. Es bedeutet nur, dass es noch keine Ausgabe bereit hat.

Es ist nicht der Fall, dass Sie MediaCodec einen Puffer codierter Daten übergeben und sofort einen decodierten Puffer zurückbekommen. Sie übergeben ihm einen Datenpuffer, der an den Prozess mediaserver gesendet wird, der ihn in den Hardware-AVC-Decoder einspeist, der vielleicht noch initialisiert wird oder vielleicht nur auf ein paar Frames sitzt. Wenn der Decodiervorgang abgeschlossen ist, werden die decodierten Daten über den Prozess mediaserver an Ihren App-Prozess zurückgegeben.

Der Trick ist, die queueInputBuffer() Aufruf sofort zurückgibt. Im Normalbetrieb läuft die Eingangsseite des Decoders einige Frames vor der Ausgangsseite. Wenn Sie mit der Eingabe fertig sind, legen Sie das Flag für das Ende des Streams fest. Wenn Sie EOS auf der Ausgabe sehen, wissen Sie, dass Sie das Ende erreicht haben.

Sie können verschiedene Arbeitsbeispiele unter bigflake und in Grafika finden. Die Beispiele DecodeEditEncodeTest und EncodeDecodeTest arbeiten ausschließlich mit Raw H.264, die anderen verwenden MediaExtractor und MediaMuxer, um mit MP4-Dateiwrappern umzugehen.

+0

Ich habe Ihre gegebenen Ressourcen nachgeschlagen, und ich habe einige Fragen dazu. ** 1) Gibt es irgendwelche Möglichkeiten, den Decoder dazu zu bringen, den Rahmen schnell zu decodieren? ** ** 2) Sollte ich das cds-0, welches der erste codierte Rahmen ist, dem Decoderformat hinzufügen? ** ** 3) Ist PresentationTime ist erforderlich? ** –

+0

(1) Sie können möglicherweise etwas Zeit sparen, indem Sie den Decoder im Voraus konfigurieren und starten. Ich habe nicht damit experimentiert. Wie viel Verzögerung siehst du? (2) Sie können die CSD entweder zum 'MediaFormat' hinzufügen oder als erstes Bild mit dem gesetzten 'CODEC_CONFIG'-Flag übergeben. Tu beides nicht. (3) Ich denke nicht, dass der Codec beim Dekodieren dem PTS Aufmerksamkeit schenkt. (Es ist * jedoch wichtig, wenn es kodiert wird.) Wenn Sie die Zeitstempel von der Quelle bekommen, ist es eine gute Idee, sie zu behalten - z. falls Ihre Videoquelle keine Frames mit einer konstanten Rate liefert. – fadden

+1

Die Verzögerung auf meinem Nexus 7 beträgt etwa 19 Bilder und 6 Bilder auf meinem Samsung S3. Der Dalai ist relativ stabil. Es scheint eine Beziehung mit der Hardware zu haben, aber ich bin mir nicht sicher. –