¿Cómo inicializar MediaFormat para configurar un MediaCodec para decodificar datos AAC sin procesar?

Tengo un extraño problema con mi StreamPlayer y necesito cualquier ayuda que pueda obtener.

El objetivo principal que necesito lograr es StreamPlayer, que es capaz de reproducir los flujos de transporte MPEG-2 con la menor latencia posible. Para esto estoy siguiendo este enfoque:

El flujo es analizado por un analizador de TS basado en Java. He implementado un TSExtractor que es similar al MediaExtractor y que funciona bien. Puedo recibir todos los ejemplos de medios para una pista seleccionada de la misma manera que es posible usando el MediaExtractor con

extractor.readSampleData(...); extractor.advance(); 

Para decodificar los datos AAC quiero crear y configurar una instancia de MediaCodec. Usando la clase MediaExtractor esto se hace generalmente por

 MediaFormat mediaFormat = extractor.getTrackFormat(i); decoder = MediaCodec.createDecoderByType(mediaFormat.getString(MediaFormat.KEY_MIME)); decoder.configure(mediaFormat, null, null, 0); 

Como tengo que inicializar el MediaFormat en el método TSExtractor.getTrackFormat (int track) que uso

 MediaFormat mf = MediaFormat.createAudioFormat ("audio/mp4a-latm", getSampleRate(), getChannelCount()); 

Y porque todas mis muestras de AAC incluyen un ADTS que hago

 mediaFormat.setInteger(MediaFormat.KEY_IS_ADTS, 1); 

Después de leer esta publicación, finalmente agrego un marco de ESDS usando la tecla "csd-0"

 mediaFormat.setByteBuffer("csd-0", ByteBuffer.allocate(2).put(new byte[]{(byte) 0x11, (byte)0x90})); 

Donde los valores 0x11 y 0x90 se extraen del ADTS.

Cuando ahora quiero decodificar las muestras de AAC, los puestos de descodificador

 AAC decoder returned error 4097, substituting silence 

Al Registro.

Para comprobar que mi TSExtractor extrae correctamente las muestras, grabé la misma secuencia utilizando VLC remuxing a un archivo mp4 sin transcodificación para que el flujo sin procesar permanezca inalterado. Ahora puedo inicializar el MediaExtractor con el archivo mp4 grabado y comparar las muestras creadas por mi TSExtractor y el MediaExtractor. Usando rastro y error encontré un comportamiento muy extraño:

Cuando configuro el MediaCodec usando el mediaFormat creado por el MediaExtractor el MediaCodec decodifica las muestras de AAC devueltas por mi TSExtractor sin ningún problema. Comparando el MediaFormat, que básicamente envuelve un HashMap, creado por mi TSExtractor y el creado por el MediaExtractor da estas diferencias:

Creado por MediaExtractor:

MediaFormat: {max-input-size = 1212, durationUs = 77428875, is-adts = 1, channel-count = 2, mime = audio / mp4a-latm, csd-0 = java.nio.ByteArrayBuffer [position = 0, limit = 2, capacidad = 2], tasa de muestreo = 48000}

Creado por TSExtractor:

MediaFormat: {is-adts = 1, channel-count = 2, mime = audio / mp4a-latm, csd-0 = java.nio.ByteArrayBuffer [posición = 2, límite = 2, capacidad = 2] 48000}

Incluso cuando adopto el MediaFormat creado por el TSExtractor para ser similar a la creada por el MediaExtractor el decodificador da el mismo error utilizando el auto creado y decodifica sin ningún problema con el otro.

Cualquier ayuda sería realmente útil.

Realmente no sé por qué, pero resulta que la inicialización de la "csd-0" ByteBuffer de esta manera

 mediaFormat.setByteBuffer("csd-0", ByteBuffer.allocate(2).put(new byte[]{(byte) 0x11, (byte)0x90})); 

No funciona, pero lo inicializa de esta manera

 byte[] bytes = new byte[]{(byte) 0x11, (byte)0x90}; ByteBuffer bb = ByteBuffer.wrap(bytes); mediaFormat.setByteBuffer("csd-0", bb); 

hace.

BTW, comparando estos dos byteBuffers usando

 bb1.equals(bb2); 

Devuelve true.

¡Muy extraño!

En el caso de fallo u puede ser necesario llamar al método de rebobinado ByteBuffer primero. Si u mirada cuidadosamente u'll ver la posición es diferente entre el MediaExtractor y el TSExtractor:

Csd-0 = java.nio.ByteArrayBuffer [ posición = 0 , límite = 2, capacidad = 2]

Vs

Csd-0 = java.nio.ByteArrayBuffer [ posición = 2 , límite = 2, capacidad = 2]

Los iguales de ByteBuffer sólo comparan los bytes después de la posición hasta que no coincidan; En el caso de ur un búfer ya está posicionado en el extremo por lo tanto no hay desajuste.

Gracias por el código anterior para calcular CSD. Por desgracia, esto no funcionaba para mí. Mi decodificador estaba fallando con el ajuste csd anterior. Finalmente encontré el problema. De acuerdo con la documentación primero "5 bits" de CSD es el tipo de objeto (Perfil). El perfil de código arriba se agrega a sólo 4 bits. Así que cambiar el código de abajo funciona bien para mí

  int profile = (header[2] & 0xC0) >> 6; int srate = (header[2] & 0x3C) >> 2; int channel = ((header[2] & 0x01) << 2) | ((header.[3] & 0xC0) >> 6) ByteBuffer csd = ByteBuffer.allocate(2); csd.put(0, (byte)(profile << 3 | srate >> 1)); csd.put(1, (byte)((srate & 0x01) << 7 | channel << 3)); 

Los valores en csd-0 dependen del encabezado ADTS.

La longitud del encabezado ADTS es de hasta 9 bytes. Para generar csd-0 se necesita el segundo y el tercer byte del encabezado.

 int profile = (header[2] & 0xC0) >> 6; int srate = (header[2] & 0x3C) >> 2; int channel = ((header[2] & 0x01) << 2) | ((header.[3] & 0xC0) >> 6) ByteBuffer csd = ByteBuffer.allocate(2); csd.put(0, (byte)( ((profile + 1) << 3) | srate >> 1 ) ); csd.put(1, (byte)( ((srate << 7) & 0x80) | channel << 3 ) ); 

Ahora tienes csd-0 válido para esta secuencia de audio aac.

  • Cómo conectar la superficie de Android MediaCodec a Vulkan
  • Algoritmo de tasa de bits adaptativo RTMP
  • Cómo evitar java.lang.IllegalStateException generado por MediaCodec.dequeueInputBuffer
  • Cómo salvar SurfaceTexture como bitmap
  • Búsqueda precisa de video
  • Buffer de vídeo circular Android con sonido
  • Transcodifique vídeo para reducir la velocidad de bits y transmitir
  • El archivo convertido de MediaCodec de WAV a AMR no se reproduce
  • Entrada de superficie de búfer en MediaCodec
  • Cómo vivir la transmisión desde Android
  • Truncar vídeo con MediaCodec
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.