2016-08-25 2 views
0

Je souhaite décoder un fichier mp4 et envoyer la sortie décodée à un encodeur, puis l'enregistrer en tant que nouveau fichier mp4. Cela peut sembler quelque chose de non désiré/bizarre. Cela peut également être fait en utilisant la surface d'entrée du codeur comme surface de sortie du décodeur. Mais je veux faire quelques modifications à cela pour obtenir quelque chose de différent (en modifiant l'ordre des images) une fois que je l'ai fait fonctionner (en utilisant ByteBuffer). Mais quand j'essaye cela, j'obtiens l'erreur ci-dessous quand Encoder.dequeueOutputBuffer(bufferInfo, TIME_OUT_US) est appelée.Impossible de transmettre la sortie du décodeur à l'entrée du codeur à l'aide de MediaCodec

frameworks/av/media/libstagefright/ACodec.cpp:4886 CHECK_EQ(mCodec->mOMX->emptyBuffer(mCodec->mNode, bufferID, 0, buffer->size(), flags, timeUs),(status_t)OK) failed: -2147483648 vs. 0 
A/libc: Fatal signal 6 (SIGABRT), code -6 in tid 31543 (CodecLooper) 

Préparation codeur

// parameters for the encoder 
private static final String MIME_TYPE = "video/avc"; // H.264 Advanced Video Coding 
private static final int FRAME_RATE = 15;    // 15fps 
private static final int IFRAME_INTERVAL = 10; 
private int mBitRate = 2000000; 

private void prepareEncoder() throws IOException { 

    MediaFormat format = MediaFormat.createVideoFormat(MIME_TYPE, mVideoWidth, mVideoHeight); 

    // Set some properties. Failing to specify some of these can cause the MediaCodec 
    // configure() call to throw an unhelpful exception. 
    format.setInteger(MediaFormat.KEY_COLOR_FORMAT, 
      MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface); 
    format.setInteger(MediaFormat.KEY_BIT_RATE, mBitRate); 
    format.setInteger(MediaFormat.KEY_FRAME_RATE, FRAME_RATE); 
    format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, IFRAME_INTERVAL); 
    Log.d(TAG, "format: " + format); 

    mEncoder = MediaCodec.createEncoderByType(MIME_TYPE); 
    mEncoder.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE); 

//  mEncoderInputSurface = mEncoder.createInputSurface(); 

    mEncoder.start(); 

    Log.d(TAG, "prepareEncoder: Done"); 

} 

manutention sortie du décodeur

Il fondamentalement copie les données du tampon de sortie à une liste de tableaux qui fonctionne comme une file d'attente pour une utilisation ultérieure par le codeur

private boolean doDecoderOutput(MediaCodec.BufferInfo bufferInfo) { 

    int decoderStatus = mDecoder.dequeueOutputBuffer(bufferInfo, TIME_OUT_US); 

    if (decoderStatus == MediaCodec.INFO_TRY_AGAIN_LATER) { 
     //Output buffer not available will try later 
     return false; 
    } else if (decoderStatus == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) { 
     //Output buffer has changed 
     //TODO this is deprecated 
     mDecoderOutputBuffers = mDecoder.getOutputBuffers(); 
     return false; 
    } else if (decoderStatus == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) { 
     //TODO what? 
     return false; 
    } else if (decoderStatus < 0) { 
     //Unknown status 
    } else { 
     //decoderStatus > 0 

     boolean endOfStream = (bufferInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0; 

     ByteBuffer decoderOutputBuffer = mDecoderOutputBuffers[decoderStatus]; 

     if (!endOfStream) { 
      if((bufferInfo.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) == 0) { 
       /*decoderOutputBuffer.position(bufferInfo.offset); 
       decoderOutputBuffer.limit(bufferInfo.offset + bufferInfo.size);*/ 
       mEncoderInputQueue.add(new VideoChunk(decoderOutputBuffer, bufferInfo.flags, bufferInfo.presentationTimeUs)); 
       Log.d(TAG, "doDecoderOutput: " + "no config"); 
      }else{ 
       Log.d("ReverseTask", "doDecoderOutput : found config"); 
      } 
     } else { 
      mEncoderInputQueue.add(null);//This informs encoder that EOS has reached 
     } 

     Log.d(TAG, "doDecoderOutput: " + mDecoderOutputCount); 
     mDecoderOutputCount++; 

     mDecoder.releaseOutputBuffer(decoderStatus, true); 

     if (endOfStream) { 
      //End of output stream 
      Log.d(TAG, "doDecoderOutput: End of stream. Frame no :" + mDecoderOutputCount); 
      return true; 
     } 
    } 
    return false; 
} 

codeur de manutention d'entrée

private boolean doEncoderInput() { 
    if (mEncoderInputQueue.isEmpty()) { 
     //No frames queued for encode 
     return false; 
    } 
    int inputBufferIndex = mEncoder.dequeueInputBuffer(TIME_OUT_US); 

    if (inputBufferIndex < 0) { 
     //Input buffer not available. Try again later. 
     return false; 
    } 

    Log.d(TAG, "doEncoderInput: " + mEncoderInputCount); 
    mEncoderInputCount++; 

    ByteBuffer encoderInputBuffer = mEncoderInputBuffers[inputBufferIndex]; 

    VideoChunk videoChunk = mEncoderInputQueue.remove(0); 
    if (videoChunk == null) { 
     //End of stream 
     Log.d(TAG, "doEncoderInput: End of stream. Frame no " + mEncoderInputCount); 
     mEncoder.queueInputBuffer(inputBufferIndex, 0, 0, 0L, MediaCodec.BUFFER_FLAG_END_OF_STREAM); 
    } else { 

     Log.d(TAG, "doEncoderInput: chunk length : " + videoChunk.getLength() + " buffer capacity : " + encoderInputBuffer.capacity()); 
     videoChunk.copyTo(encoderInputBuffer); 

     mEncoder.queueInputBuffer(inputBufferIndex, 0, videoChunk.getLength(), videoChunk.getPresentationTimeUs(), 0);//videoChunk.getFlags()); 
     videoChunk.release(); 
     Log.d(TAG, "doEncoderInput: sent encoder input"); 
    } 
    return true; 
} 

Manipulation sortie du codeur.

Finalement, je devrais utiliser un Muxer pour enregistrer le flux dans un fichier. Ici, j'ignore la sortie de l'encodeur jusqu'à ce que je reçoive ce tas d'erreurs de code.

private boolean doEncoderOutput(MediaCodec.BufferInfo bufferInfo) { 

    Log.d("ReverseTask", "doEncoderOutput : start"); 
    int encoderStatus = mEncoder.dequeueOutputBuffer(bufferInfo, TIME_OUT_US); 

    Log.d("ReverseTask", "doEncoderOutput : encoder status " + encoderStatus); 
    if (encoderStatus == MediaCodec.INFO_TRY_AGAIN_LATER) { 
     //Output buffer not available will try later 
     return false; 
    } else if (encoderStatus == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) { 
     //Output buffer has changed 
     //TODO this is deprecated 
     mEncoderOutputBuffers = mEncoder.getOutputBuffers(); 
     return false; 
    } else if (encoderStatus == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) { 
     //TODO what? 
     return false; 
    } else if (encoderStatus < 0) { 
     //Unknown status 
    } else { 
     //encoderStatus > 0 

     Log.d(TAG, "doEncoderOutput: " + mEncoderOutputCount); 
     mEncoderOutputCount++; 

     ByteBuffer encoderOutputBuffer = mEncoderOutputBuffers[encoderStatus]; 


     Log.d(TAG, "doEncoderOutput: releasing output buffer"); 
     mEncoder.releaseOutputBuffer(encoderStatus, false); 

     if ((bufferInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) { 
      //End of output stream 
      Log.d(TAG, "doEncoderOutput: End of stream. Frame no :" + mEncoderOutputCount); 
      return true; 
     } 
    } 
    return false; 
} 

J'ai appris à utiliser les API MediaCodec pour les 1-2 dernières semaines. Ont atteint ce loin de nulle part. Mais vraiment coincé ici. Toute aide à ce sujet est très appréciée.

Répondre

0
A/libc: Fatal signal 6 (SIGABRT) 

Il est courant d'obtenir cette erreur si vous passez BufferInfo-dequeueOutputBuffer(...) non initialisée. Donc, s'il vous plaît, assurez-vous que vous avez appelé bufferInfo = new MediaCodec.BufferInfo() avant qu'il ne soit utilisé.