Cómo utilizar ByteBuffer en el contexto de MediaCodec en android

Hasta ahora soy capaz de configurar un MediaCodec para codificar una secuencia de vídeo. El objetivo es guardar las ilustraciones generadas por el usuario en un archivo de vídeo.

Utilizo objetos de mapa de bits de android de las ilustraciones de usuario para enviar marcos a la secuencia.

Vea el fragmento de código que utilizo al final de este post (es el código completo, no se recorta nada):

MediaCodec utiliza ByteBuffer para hacer frente a flujos de vídeo / audio.

Los mapas de bits se basan en int [], que si se convierte en byte [] requerirá x4 el tamaño de la int []

Hice algunas investigaciones para averiguar qué contratos existen en el lugar para el ByteBuffer cuando se trata de flujos de vídeo / audio en MediaCodec, pero la información está casi cerca de zilch.

¿Cuáles son los contratos de uso de ByteBuffer en MediaCodec?

¿Especificar las dimensiones del marco en el MediaFormat significa automáticamente que el ByteBuffers tiene anchura * altura * capacidad de 4 bytes?

(Yo uso un objeto de mapa de bits a la vez para cada marco)

Gracias por cualquier ayuda.

(Editado, código añadido)

import java.io.ByteArrayOutputStream; import java.io.DataOutputStream; import java.io.File; import java.io.FileOutputStream; import java.nio.ByteBuffer; import android.graphics.Rect; import android.graphics.Bitmap.CompressFormat; import android.media.MediaCodec; import android.media.MediaCodec.BufferInfo; import android.media.CamcorderProfile; import android.media.MediaCodecInfo; import android.media.MediaFormat; import android.util.Log; import android.view.View; public class VideoCaptureManager { private boolean running; private long presentationTime; public void start(View rootView, String saveFilePath){ Log.e("OUT", saveFilePath); this.running = true; this.presentationTime = 0; this.capture(rootView, saveFilePath); } private void capture(final View rootView, String saveFilePath){ if(rootView != null){ rootView.setDrawingCacheEnabled(true); final Rect drawingRect = new Rect(); rootView.getDrawingRect(drawingRect); try{ final File file = new File(saveFilePath); if(file.exists()){ // File exists return return; } else { File parent = file.getParentFile(); if(!parent.exists()){ parent.mkdirs(); } } new Thread(){ public void run(){ try{ DataOutputStream dos = new DataOutputStream(new FileOutputStream(file)); MediaCodec codec = MediaCodec.createEncoderByType("video/mp4v-es"); MediaFormat mediaFormat = null; if(CamcorderProfile.hasProfile(CamcorderProfile.QUALITY_720P)){ mediaFormat = MediaFormat.createVideoFormat("video/mp4v-es", 720, 1280); } else { mediaFormat = MediaFormat.createVideoFormat("video/mp4v-es", 480, 720); } mediaFormat.setInteger(MediaFormat.KEY_BIT_RATE, 700000); mediaFormat.setInteger(MediaFormat.KEY_FRAME_RATE, 10); mediaFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT, MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Planar); mediaFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 5); codec.configure(mediaFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE); codec.start(); ByteBuffer[] inputBuffers = codec.getInputBuffers(); ByteBuffer[] outputBuffers = codec.getOutputBuffers(); while(VideoCaptureManager.this.running){ try{ int inputBufferIndex = codec.dequeueInputBuffer(-2); if(inputBufferIndex >= 0){ // Fill in the bitmap bytes // inputBuffers[inputBufferIndex]. ByteArrayOutputStream baos = new ByteArrayOutputStream(); rootView.getDrawingCache().compress(CompressFormat.JPEG, 80, baos); inputBuffers[inputBufferIndex].put(baos.toByteArray()); codec.queueInputBuffer(inputBufferIndex, 0, inputBuffers[inputBufferIndex].capacity(), presentationTime, MediaCodec.BUFFER_FLAG_CODEC_CONFIG); presentationTime += 100; } BufferInfo info = new BufferInfo(); int outputBufferIndex = codec.dequeueOutputBuffer(info, -2); if(outputBufferIndex >= 0){ // Write the bytes to file byte[] array = outputBuffers[outputBufferIndex].array(); // THIS THORWS AN EXCEPTION. WHAT IS THE CONTRACT TO DEAL WITH ByteBuffer in this code? if(array != null){ dos.write(array); } codec.releaseOutputBuffer(outputBufferIndex, false); } else if(outputBufferIndex == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED){ outputBuffers = codec.getOutputBuffers(); } else if(outputBufferIndex == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED){ // codec format is changed MediaFormat format = codec.getOutputFormat(); } Thread.sleep(100); }catch(Throwable th){ Log.e("OUT", th.getMessage(), th); } } codec.stop(); codec.release(); codec = null; dos.flush(); dos.close(); }catch(Throwable th){ Log.e("OUT", th.getMessage(), th); } } }.start(); }catch(Throwable th){ Log.e("OUT", th.getMessage(), th); } } } public void stop(){ this.running = false; } } 

La configuración exacta del ByteBuffer está determinada por el codec para el formato de entrada que ha elegido. No todos los dispositivos admiten todos los formatos de entrada posibles (por ejemplo, algunos codificadores AVC requieren 420 YUV planar, otros requieren semi-planar). Las versiones anteriores de Android (<= API 17) no proporcionaban una forma portátil de generar imágenes de video para MediaCodec .

En Android 4.3 (API 18), tiene dos opciones. En primer lugar, MediaCodec ahora acepta la entrada de una superficie, lo que significa que cualquier cosa que se puede dibujar con OpenGL ES se puede grabar como una película. Véase, por ejemplo, el ejemplo EncodeAndMuxTest .

Segundo, usted todavía tiene la opción de usar buffers YUV 420 generados por software, pero ahora es más probable que funcionen porque hay pruebas CTS que los ejercitan. Usted todavía tiene que hacer la detección de tiempo de ejecución de planar o semi-planar, pero sólo hay dos diseños. Consulte las variantes de buffer-to-buffer de EncodeDecodeTest para ver un ejemplo.

  • Cómo grabar vídeo desde el fondo de la aplicación: Android
  • ¿Hay algunos reproductores de medios de código abierto en Android?
  • Extraer mapa de bits del vídeo en android
  • Biblioteca de música en android
  • Ruta de audio a través del altavoz cuando los auriculares lo conectan
  • Cómo obtener canciones del álbum / artista en android, usando MediametadataRetriever?
  • Tema personalizado para Media Volume Controller (lo que se llame) de Android?
  • Cómo grabar un audio FM en android?
  • Android MediaMetadataRetriever devuelve valores nulos de la mayoría de las claves
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.