android - Use MediaCodec y MediaExtractor para decodificar y codificar video
bitmap (2)
Necesito decodificar un video en una secuencia de bitmaps, de modo que pueda modificarlos y luego comprimirlos en un archivo de video en Android.
Planeo administrar esto usando getFrameAtTime
y guardándolo en una secuencia de imágenes. Luego puedo modificar las imágenes en la secuencia y codificarla para volver a una película. Pero tengo dos problemas con esto:
- Primero, mientras lo leo,
getFrameAtTime
es para crear miniaturas y no garantiza la devolución del fotograma correcto. Esto hace que el video sea lento. - En segundo lugar, guardar las imágenes y leerlas lleva mucho tiempo.
Leí que la forma correcta de hacer la decodificación es con MediaExtractor, esto está bien, pero solo tengo ejemplos para renderizarlo directamente en un surfaceView
. ¿Hay alguna forma de convertir el outputBuffer
en un mapa de bits?
Lo necesitaría para que funcione con un nivel de API de 16 o superior.
Puede encontrar una colección de ejemplos útiles en el sitio de bigflake .
En particular, ExtractMpegFramesTest
demuestra cómo decodificar un archivo .mp4 a Bitmap
, y DecodeEditEncodeTest
decodifica y vuelve a codificar una secuencia H.264, modificando los cuadros con un sombreado GLES.
Muchos de los ejemplos usan características introducidas en API 18, como Surface
entrada de Surface
a MediaCodec
(que evita una serie de problemas de formato de color) y MediaMuxer
(que le permite convertir la corriente elemental H.264 sin formato que sale de MediaCodec
en una archivo .mp4). Algunos dispositivos le permitirán extraer video a datos YUV en ByteBuffer
, modificarlo y volver a codificarlo, pero otros dispositivos extraen formatos de color YUV patentados que pueden ser rechazados por la versión API 16 de MediaCodec
.
Recomiendo la codificación de API 18 (Android 4.3 "Jellybean" MR2) o posterior.
Hay muchas personas que dicen que el método onFrameAvailable()
nunca se llama. Bueno, el oyente debe estar en un hilo diferente al hilo principal. Para configurar el oyente haga esto: (donde este es el oyente de la clase que implementa SurfaceTexture.IOnFrameAvailableListener
):
mSurfaceTexture.SetOnFrameAvailableListener(this);