Android MediaCodec: Reduce el tamaño del video mp4
Estoy buscando una manera de "comprimir" un video mp4. Para lograr esto, quiero reducir la resolución del video y / o reducir FPS.
Después de una larga investigación, creo que la forma de hacerlo es usar MediaCodec y las API relacionadas como sigue:
- Cómo incluir funciones FFMPEG en el código android
- Cómo tomar imágenes de vídeo o imágenes fijas desde el mismo botón utilizando Android Camera Intent
- Cómo comprimir un archivo de vídeo en android?
- Reproducción de vídeos de youtube en la brecha telefónica
- La cámara Motorola Android 2.2 ignora el parámetro EXTRA_OUTPUT
-> MediaExtractor para extraer datos de medios codificados de un archivo mp4. -> MediaCodec (decodificador): Decodificar cada fotograma para un procesamiento posterior. -> MediaCodec (Encoder): En este punto, supongo que es donde deberíamos establecer los parámetros de MediaFormat como la resolución de vídeo, que debería ayudarnos a reducir el tamaño final del archivo mp4. -> MediaMuxer para generar archivos mp4 (MinSDK 18, esto podría ser un problema, pero por ahora … ok).
No quiero usar un SurfaceView / TextureView. En cuanto al audio, no quiero procesarlo para reducir la calidad.
He estado viendo todos los ejemplos aquí: http://bigflake.com/mediacodec/
También he visto CTS módulos de código fuente.
Y he estado viendo varios proyectos como estos: https://github.com/vecio/MediaCodecDemo/blob/master/src/io/vec/demo/mediacodec/DecodeActivity.java
Y por supuesto he leído decenas de mensajes en stackoverflow.
El problema es que todavía no he encontrado ningún ejemplo de código que funcione bien para este porpuse. Traté de tomar varias piezas de código y ponerlas juntas en un proyecto, pero realmente no funciona.
Gracias.
- ¿Cómo las aplicaciones de Media Player para Android como MXPlayer y MoboPlayer reproducen formatos de archivo no soportados como MKV?
- ¿Hay una manera de hacer que VideoView siga jugando en segundo plano en la aplicación para Android?
- Recomponer Disposición de actividad para reproducir vídeo en pantalla completa cuando se gira la pantalla
- Android MediaRecorder para grabar una superficie (no la cámara)
- Obtener flujo de vídeo IP Cam en Android (MJEPG)
- ¿Cómo puedo resolver la rotación de 90 grados de video al jugar en android?
- MediaStore.EXTRA_DURATION_LIMIT ¿No funciona Nexus Devices?
- Reproducción de vídeo en pantalla completa
Lo más parecido a lo que quieres es probablemente el DecodeEditEncodeTest en bigflake. No necesitas SurfaceView
o TextureView
, ya que no estás intentando mostrar el video, pero necesitarás usar SurfaceTexture
.
El código de prueba genera un video, luego decodifica / edita / codifica, y luego prueba la salida codificada. Desea la parte decodificar-editar-codificar. Al crear el codificador, dale el tamaño que quieras. La superficie de entrada que cree tendrá un tamaño adecuado. La escala se realiza mediante la GPU, ya que transforma la textura GL (desde SurfaceTexture
) en la superficie de entrada del codificador. Tendrá que decidir si el filtrado lineal de GLES proporciona el nivel de calidad que necesita.
(Puedes ver algo similar en ExtractMpegFramesTest , que escala todo a 640×480 como lo está haciendo la extracción.En este caso, es la conversión de los fotogramas a PNG en lugar de alimentarlos en un codificador, por lo que no es aplicable a su situación.
Soltar cuadros es teóricamente fácil: simplemente no lo envíe al codificador. En la práctica es un poco más difícil si la entrada tiene cuadros espaciados de forma irregular. Si la entrada es "frame1 frame2 … pause … frame4 frame5", y dejas caer frame2, terminarás pausado en frame1, lo que podría parecer extraño. Puede usar los sellos de tiempo de presentación para determinar el momento.
La entrada de superficie y MediaMuxer
(necesarios para guardar H.264 como .mp4) requieren API 18+. Para versiones anteriores de Android es probable que desee utilizar una biblioteca de terceros como ffmpeg .
- Cómo rotar la vista del mapa sin problemas con el rodamiento en android
- No se puede realizar la sincronización (onPerformSync no se llama)