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:
- La resolución de la vista previa no coincide con la resolución del códec
- Transcodifique vídeo para reducir la velocidad de bits y transmitir
- PCM -> AAC (Encoder) -> PCM (Decodificador) en tiempo real con optimización correcta
- Error de codificación de vídeo que utiliza datos OnAudioFilterRead
- Codificador AAC de Android MediaCodec
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!
- Mp3 a conversión wav android
- Implementación Color_FormatSurface
- Android cambia el tamaño de VirtualDisplay
- Excepción de estado ilegal al llamar a MediaCodec.configure ()
- Tiempo de muestra / tiempo de presentación incoherente durante la descodificación de vídeo
- ¿Cómo inicializar MediaFormat para configurar un MediaCodec para decodificar datos AAC sin procesar?
- Decodificador de vídeo acelerado por hardware para H264
- MediaCodec con entrada de superficie: Grabación en segundo plano
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);
- Error Phonegap android sdk build.xml: 950: nulo devuelto: 1
- Elementos de menú de la bandeja de navegación seleccionados dentro de diferentes grupos