2014-01-17 3 views
8

Я использую Android MediaCodec API для декодирования кадров h264. Я мог бы декодировать и визуализировать рамки на представлении. Моя проблема заключается в том, что декодер пропускает множество кадров, особенно первые несколько кадров. DecodeMediaCodec.dequeueOutputBuffer() return -1. aAbout 150 кадров h264, только декодированные 43 кадра. Я не могу найти, где проблема. Вот мои коды.Android MediaCodec декодирует h264 необработанный кадр

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

После начального декодирования я начну декодировать нить.

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

Кто-нибудь знает, почему? Я надеюсь, что ваш help.My андроид устройство нексус 7.

ответ

5

Получение -1 назад от MediaCodec#dequeueOutputBuffer() нормально. Это просто означает, что у него пока нет готового выхода.

Это не тот случай, когда вы передаете буфер закодированных данных и немедленно получаете декодированный буфер обратно. Вы передаете ему буфер данных, который отправляется на процесс mediaserver, который передает его в аппаратный декодер AVC, который все еще может быть инициализирован или, может быть, просто нравится сидеть на нескольких кадрах. Когда процесс декодирования завершается, декодированные данные передаются обратно через mediaserver в ваш процесс приложения.

Уловка, звонок queueInputBuffer() немедленно возвращается. При нормальной работе входная сторона декодера будет запускать несколько кадров перед выходной стороной. Когда вы закончите подавать ввод, вы установите флаг конца потока, и когда вы увидите, что EOS установлен на выходе, вы знаете, что достигли конца.

Вы можете найти различные рабочие примеры на bigflake и в Grafika. Примеры DecodeEditEncodeTest и EncodeDecodeTest работают исключительно с необработанным H.264, остальные используют MediaExtractor и MediaMuxer для обработки обложек файлов MP4.

+0

Я просматриваю ваши данные, и у меня есть некоторые вопросы об этом. ** 1) Есть ли способ заставить декодер быстро декодировать кадр ** ** 2) Следует ли добавить cds-0, который является первым кодированным фреймом в формат декодера? ** ** 3) Является ли PresentationTime необходимо? ** –

+0

(1) Вы можете сэкономить некоторое время, предварительно запустив и запустив декодер. Я не экспериментировал с этим. Сколько задержки вы видите? (2) Вы можете добавить CSD в «MediaFormat» или отправить его в качестве первого кадра с установленным флагом 'CODEC_CONFIG'. Не делай того и другого. (3) Я не думаю, что кодек обращает внимание на PTS при декодировании. (Это * * важно при кодировании.) Если вы получаете отметки времени от источника, рекомендуется сохранить их, например. в случае, если ваш источник видео не предоставляет кадры с постоянной скоростью. – fadden

+1

Задержка на моем Nexus 7 составляет около 19 кадров и 6 кадров на моем Samsung s3. Далай относительно стабилен. Кажется, у нас есть отношение к аппаратным средствам, но я не уверен. –

Смежные вопросы