El codificador MediaCodec H264 no funciona en los dispositivos Snapdragon 800

He escrito un codificador de la corriente de H264 usando la API de MediaCodec de Androide. Lo probé en unos diez dispositivos diferentes con diferentes procesadores y funcionó en todos ellos, excepto en Snapdragon 800 powered (Google Nexus 5 y Sony Xperia Z1). En esos dispositivos obtengo el SPS y el PPS y el primer Keyframe, pero después de eso mEncoder.dequeueOutputBuffer (mBufferInfo, 0) sólo devuelve MediaCodec.INFO_TRY_AGAIN_LATER. Ya he experimentado con diferentes tiempos de espera, bitrates, resoluciones y otras opciones de configuración, sin éxito. El resultado es siempre el mismo.

Utilizo el código siguiente para inicializar el codificador:

mBufferInfo = new MediaCodec.BufferInfo(); encoder = MediaCodec.createEncoderByType("video/avc"); MediaFormat mediaFormat = MediaFormat.createVideoFormat("video/avc", 640, 480); mediaFormat.setInteger(MediaFormat.KEY_BIT_RATE, 768000); mediaFormat.setInteger(MediaFormat.KEY_FRAME_RATE, 30); mediaFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT, mEncoderColorFormat); mediaFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 10); encoder.configure(mediaFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE); 

Donde el formato de color seleccionado es:

 MediaCodecInfo.CodecCapabilities capabilities = mCodecInfo.getCapabilitiesForType(MIME_TYPE); for (int i = 0; i < capabilities.colorFormats.length && selectedColorFormat == 0; i++) { int format = capabilities.colorFormats[i]; switch (format) { case MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Planar: case MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420PackedPlanar: case MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420SemiPlanar: case MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420PackedSemiPlanar: case MediaCodecInfo.CodecCapabilities.COLOR_TI_FormatYUV420PackedSemiPlanar: case MediaCodecInfo.CodecCapabilities.COLOR_QCOM_FormatYUV420SemiPlanar: selectedColorFormat = format; break; default: LogHandler.e(LOG_TAG, "Unsupported color format " + format); break; } } 

Y obtengo los datos haciendo

  ByteBuffer[] inputBuffers = mEncoder.getInputBuffers(); ByteBuffer[] outputBuffers = mEncoder.getOutputBuffers(); int inputBufferIndex = mEncoder.dequeueInputBuffer(-1); if (inputBufferIndex >= 0) { // fill inputBuffers[inputBufferIndex] with valid data ByteBuffer inputBuffer = inputBuffers[inputBufferIndex]; inputBuffer.clear(); inputBuffer.put(rawFrame); mEncoder.queueInputBuffer(inputBufferIndex, 0, rawFrame.length, 0, 0); LogHandler.e(LOG_TAG, "Queue Buffer in " + inputBufferIndex); } while(true) { int outputBufferIndex = mEncoder.dequeueOutputBuffer(mBufferInfo, 0); if (outputBufferIndex >= 0) { Log.d(LOG_TAG, "Queue Buffer out " + outputBufferIndex); ByteBuffer buffer = outputBuffers[outputBufferIndex]; if ((mBufferInfo.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) != 0) { // Config Bytes means SPS and PPS Log.d(LOG_TAG, "Got config bytes"); } if ((mBufferInfo.flags & MediaCodec.BUFFER_FLAG_SYNC_FRAME) != 0) { // Marks a Keyframe Log.d(LOG_TAG, "Got Sync Frame"); } if (mBufferInfo.size != 0) { // adjust the ByteBuffer values to match BufferInfo (not needed?) buffer.position(mBufferInfo.offset); buffer.limit(mBufferInfo.offset + mBufferInfo.size); int nalUnitLength = 0; while((nalUnitLength = parseNextNalUnit(buffer)) != 0) { switch(mVideoData[0] & 0x0f) { // SPS case 0x07: { Log.d(LOG_TAG, "Got SPS"); break; } // PPS case 0x08: { Log.d(LOG_TAG, "Got PPS"); break; } // Key Frame case 0x05: { Log.d(LOG_TAG, "Got Keyframe"); } //$FALL-THROUGH$ default: { // Process Data break; } } } } mEncoder.releaseOutputBuffer(outputBufferIndex, false); if ((mBufferInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) { // Stream is marked as done, // break out of while Log.d(LOG_TAG, "Marked EOS"); break; } } else if(outputBufferIndex == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) { outputBuffers = mEncoder.getOutputBuffers(); Log.d(LOG_TAG, "Output Buffer changed " + outputBuffers); } else if(outputBufferIndex == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) { MediaFormat newFormat = mEncoder.getOutputFormat(); Log.d(LOG_TAG, "Media Format Changed " + newFormat); } else if(outputBufferIndex == MediaCodec.INFO_TRY_AGAIN_LATER) { // No Data, break out break; } else { // Unexpected State, ignore it Log.d(LOG_TAG, "Unexpected State " + outputBufferIndex); } } 

¡Gracias por tu ayuda!

Debe establecer el parámetro presentationTimeUs en su llamada a queueInputBuffer. La mayoría de los codificadores ignoran esto y se puede codificar para streaming sin problemas. El codificador utilizado para los dispositivos Snapdragon 800 no.

Este parámetro representa el tiempo de grabación de su fotograma y necesita, por lo tanto, aumentar el número de nosotros entre el fotograma que desea codificar y el fotograma anterior.

Si el conjunto de parámetros es el mismo valor que en la trama anterior, el codificador lo deja caer. Si el parámetro se establece en un valor demasiado pequeño (por ejemplo, 100000 en una grabación de 30 FPS) la calidad de los fotogramas codificados cae.

EncodeCodec.queueInputBuffer (inputBufferIndex, 0, input.length, (System.currentTimeMillis () – startMs) * 1000, 0);

  • El método onFrameAvailable () de SurfaceTexture siempre se llama demasiado tarde
  • ¿Cómo usar MediaCodec para decodificar datos del servidor RTSP?
  • ¿Qué significa el código de error -1010 en Android MediaCodec?
  • Error en el codificador OMX.qcom aleatorio
  • Cómo utilizar MediaCodec sin MediaExtractor para H264
  • Cómo establecer media + tasa de bits máxima para MediaCodec para codificar vídeo H.264?
  • MediaCodec createInputSurface
  • Android: Encontrando audio y video usando MediaCodec
  • ¿Cuáles son los requisitos oficiales para que MediaMuxer pueda fusionar videos
  • Comprimir vídeos usando android MediaCodec api
  • Cómo y dónde especificar omx decoder apoya el tunelaje
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.