2016-04-26 15 views
1

В настоящее время я пытаюсь проанализировать данные H264 из потока RTP и отправить его в MediaCodec для рендеринга в SurfaceView для Android.Декодирование потока RTP с данными H264 на Android Использование MediaCodec

Однако, я не уверен, как:

  • построить H264 ломтиков правильно из пакетов RTP
  • отправить H264 ломтиков в кодеке медиа, когда они собираются на ломтики

Я не видел каких-либо примеров этого в ясной и сжатой форме, и я не нашел документы MediaCodec вообще полезными.

У кого-нибудь есть опыт работы в этом домене?

void videoCodec(ByteBuffer input, int flags) { 

    bufferInfo.set(0, 0, 0, flags); 

    int inputBufferId = codec.dequeueInputBuffer(10000); 

    if (inputBufferId >= 0) { 

     //put data 
     ByteBuffer inputData = inputBuffers[inputBufferId]; 

     inputData.clear(); 
     inputData.put(input); 

     //queue it up 
     codec.queueInputBuffer(inputBufferId, 0, input.limit(), 0, flags); 
    } 

    int outputBufferId = codec.dequeueOutputBuffer(bufferInfo, 10000); 

    if (outputBufferId >= 0) { 
     // outputBuffers[outputBufferId] is ready to be processed or rendered. 
     Timber.e("Rendering Data with Index of: %s", outputBufferId); 
     codec.releaseOutputBuffer(outputBufferId, true); 

    } else if (outputBufferId == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) { 
     outputBuffers = codec.getOutputBuffers(); 
    } else if (outputBufferId == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) { 
     // Subsequent data will conform to new format. 
     //format = codec.getOutputFormat(); 
    } 
} 

MediaFormat format = MediaFormat.createVideoFormat(MediaFormat.MIMETYPE_VIDEO_AVC, 1920, 1080); 
        codec = MediaCodec.createDecoderByType(MediaFormat.MIMETYPE_VIDEO_AVC); 
        codec.configure(format, surfaceVideo.getHolder().getSurface(), null, 0); 
        codec.start(); 


        inputBuffers = codec.getInputBuffers(); 
        outputBuffers = codec.getOutputBuffers(); 

     while (streaming) { 

      //receive RTP Packet 
      h264Parser(rtpPacket.getPayload()); 

     } 

И h264Parser выглядит примерно так:

void h264Parser(byte[] payload) { 

    int packetType = (byte) payload[0] & (byte) 0x1F; 
    boolean startBit = (payload[1] & 0x80) != 0; 
    boolean endBit = (payload[1] & 0x40) != 0; 
    int flags = 0; 

    switch (packetType) { 
     case 7: 
      pps = new ByteArrayOutputStream(); 
      pps.write(prefix); 
      pps.write(payload); 
      break; 
     case 8: 
      if (pps.size() > 0) { 
       pps.write(payload); 
       hasPps = true; 
       flags = MediaCodec.BUFFER_FLAG_CODEC_CONFIG; 
       payload = pps.toByteArray(); 
       //Send packet to decoder 
       videoCodec(ByteBuffer.wrap(payload), flags); 
      break; 
     case 28: 

      if (hasPps) { 
       if (startBit) { 
        baos = new ByteArrayOutputStream(); 
        baos.write(prefix); 
        baos.write(payload); 
       } else if (endBit) { 
         if(baos != null) { 
          baos.write(payload); 
          flags = MediaCodec.BUFFER_FLAG_KEY_FRAME; 
          payload = baos.toByteArray(); 
          //Send packet to decoder 
          videoCodec(ByteBuffer.wrap(payload), flags); 
          hasPps = false; 
       } else { 
         if(baos != null) { 
          baos.write(payload); 
         } 
       } 
      } 

      break; 
     case 1: 
      break; 
     default: 
    } 
+0

вы можете использовать некоторые библиотеки для воспроизведения Live-видео. Я работал с Vitamio и очень прост в использовании: https://www.vitamio.org/en/ – WannaBeGeek

+0

Я не автор этой библиотеки, но, выполняя некоторые подобные исследования, я нашел это: [AndroidStreamingClient] (https: //github.com/ekumenlabs/AndroidStreamingClient). В частности, см. код здесь: https://github.com/ekumenlabs/AndroidStreamingClient/blob/master/android_streaming_client/src/main/java/com/c77/androidstreamingclient/lib/rtp /RtpMediaExtractor.java Что, кажется, делает то, что вы ищете. –

ответ

1

Насколько я помню MediaCodec использует полные блоки Асесс, а не только ломтики (кто-то исправить мне я не прав)

Итак, вам нужно собрать полную форму модуля RTP и подать его в декодер (к сожалению, у меня нет опыта работы с RTP и вы не можете помочь вам с его построением).

Вы отправляете единицы доступа к декодеру следующим образом:

Dequeue в InputBuffer

int inputBufferIndex = decoder.dequeueInputBuffer(TIMEOUT_USEC); ByteBuffer inputBuffer = videoDecoderInputBuffers[videoInputBufIndex];

Заполните его с устройством доступа

inputBuffer.put(acessUnit); inputBuffer.flip();

Queue буфер для декодирование

decoder.queueInputBuffer(inputBufferIndex,0,inputBuffer.limit(), 0, FLAGS); 

Я надеюсь, что это помогает немного

+0

Спасибо, Крис! Это полезно. Сейчас я копаю. – androidDeving

+0

Я продолжаю получать outputBufferId из -1. Я подозреваю, что нет свободных выходных буферов для удаления. Есть предположения? – androidDeving

+0

Точно так же это происходит, если вы подаете вход mediacodec, который не может быть обработан. Имейте в виду, что вы должны подавать SPS и PPS в декодер. Вы можете сделать это через MediaFormat, который вы передаете декодеру ('format.setByteBuffer (« csd-0 », ByteBuffer.wrap (header_sps)); format.setByteBuffer (« csd-1 », ByteBuffer.wrap (header_pps)) ; ') или путем отправки их в качестве первого буфера с использованием флага' BUFFER_FLAG_CODEC_CONFIG' – chris