2016-08-25 45 views
0

我想解碼mp4文件並將解碼輸出饋送到編碼器並將其保存爲新的mp4文件。這聽起來有些不必要/奇怪。這也可以使用編碼器輸入表面作爲解碼器輸出表面來完成。但是,我想對此做一些修改,以便實現某些不同(通過改變幀的順序),一旦我得到這個工作(使用ByteBuffer)。無法使用MediaCodec將解碼器輸出饋送到編碼器輸入

但是,當我嘗試這個時,我得到下面的錯誤,當Encoder.dequeueOutputBuffer(bufferInfo, TIME_OUT_US)被調用。

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) 

準備編碼器

// 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"); 

} 

處理的解碼器輸出

它基本上覆制輸出緩衝器中的數據,其由編碼器工作原理,供以後使用一個隊列一個ArrayList

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

處理編碼器輸入

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

處理編碼器輸出。

最終我應該使用Muxer將流保存到文件中。在這裏,我只是忽略了編碼器的輸出,直到我得到這一堆的代碼錯誤免費。

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

我一直在學習在過去的1-2周內使用MediaCodec APIs。已經遠遠地達到了這個目標。但是真的停留在這裏。任何幫助,這是高度讚賞。

回答

0
A/libc: Fatal signal 6 (SIGABRT) 

這是常見的,如果你是路過初始化BufferInfodequeueOutputBuffer(...)得到這個錯誤。所以,請確保您在使用之前調用了bufferInfo = new MediaCodec.BufferInfo()

相關問題