Corregir archivo 3GP después de la transmisión desde Android Media Recorder
Estoy tratando de transmitir vídeo desde la cámara de Android a través de unix local socket y escribir archivo de corriente a sdcard. Todo funciona bien, excepto que el archivo no se puede reproducir con ningún reproductor. Es porque Android no llena algunas lagunas en el archivo porque socket no es buscable. Según tengo entendido, necesito hacer algunas modificaciones después de que la secuencia de video haya terminado. He leído varios artículos aquí , aquí y aquí , pero ninguno de ellos me ayudó. Estoy jugando con el editor hexadecimal para aprender a hacerlo manualmente, así que después será trivial hacer lo mismo en el código de Android.
Aquí está un ejemplo de archivo que se guardó de la secuencia: https://dl.dropbox.com/u/17510473/sample_not_playable.3gp
- ¿Tiene el navegador Android 2.1 de soporte HTML 5 y qué formato de vídeo se reproduce?
- Marcos omitidos. La aplicación puede estar haciendo demasiado trabajo en su hilo principal "error en android 4.3 nexus 7
- Transmisión en directo del reproductor RTMP / RTSP sin utilizar la visualización web (servidor WOWZA) en Android
- Reproduce vídeos HTML5 almacenados localmente en Android
- Android MediaPlayer parpadea al reproducir vídeos en Android 4.2.2
¿Puede alguien arreglar para que sea jugable y decir cómo lo hizo?
EDIT: borro el encabezado del archivo 3gp y escribo uno nuevo como sigue:
00 00 00 18 66 74 79 70 33 67 70 34 00 00 03 00 33 67 70 34 33 67 70 36 00 00 00 00
Luego encuentro la ubicación inicial de los átomos mdat y moov con el siguiente comando:
grep -aobE "ftyp|mdat|moov" sample_not_playable.3gp
Y me da la siguiente salida:
4:ftyp 28:mdat 1414676:moov
A continuación, haga 1414676 - 28 = 1,414,648 = 0x1595F8
Entonces escribo 0x1595F8 como 25-28 bytes, justo antes del átomo de mdat. Así que mi encabezado ahora se ve así:
00 00 00 18 66 74 79 70 33 67 70 34 00 00 03 00 33 67 70 34 33 67 70 36 00 15 95 F8
Y cuando intento jugarlo con mplayer consigo algún vídeo y salida audio dañados. He aquí una parte de la salida de mplayer:
[amrwb @ 0x7f72ad652380]Frame too small (33 bytes). Truncated file? [amrwb @ 0x7f72ad652380]Encountered a bad or corrupted frame [amrwb @ 0x7f72ad652380]Encountered a bad or corrupted frame [amrwb @ 0x7f72ad652380]Frame too small (33 bytes). Truncated file? [amrwb @ 0x7f72ad652380]Encountered a bad or corrupted frame [amrwb @ 0x7f72ad652380]Encountered a bad or corrupted frame [amrwb @ 0x7f72ad652380]Encountered a bad or corrupted frame A: 11.0 V: 1.4 AV: 9.650 ct: 0.023 0/ 0 10% 1% 1.6% 0 0 [mov,mp4,m4a,3gp,3g2,mj2 @ 0x7f72adeafc40]stream 1, offset 0x15e62b: partial file [h263 @ 0x7f72ad652380]Bad picture start code [h263 @ 0x7f72ad652380]header damaged Error while decoding frame! [h263 @ 0x7f72ad652380]Bad picture start code [h263 @ 0x7f72ad652380]header damaged Error while decoding frame! [h263 @ 0x7f72ad652380]Bad picture start code [h263 @ 0x7f72ad652380]header damaged Error while decoding frame! A: 11.1 V: 1.5 AV: 9.558 ct: 0.027 0/ 0 9% 1% 1.4% 0 0 [h263 @ 0x7f72ad652380]Bad picture start code [h263 @ 0x7f72ad652380]header damaged Error while decoding frame!
¿Que estoy haciendo mal?
- Reproducir audio de un video musical usando la API de Youtube en android, cuando mi aplicación está minimizada
- Intención de tomar video en android
- Se ha abandonado BufferQueue: Al reproducir vídeo con TextureView
- Subtítulos / Soporte de subtítulos en Android
- Cordova 3.6.3 Plugin de archivos - obtenga archivos de video locales en android
- Android: Transmitir datos de la cámara y escribirlos en el servidor
- Android TextureView vs rendimiento de VideoView
- Biblioteca para apoyar H.264 AVC. Mp4 en Android 2.2, 2.3?
Lo que usted necesita entender es que mp4 no es un formato streamable en vivo . Por lo tanto no hay manera que usted será capaz de cortar de todos modos alrededor para que sea en directo streamable. La cabecera [moov atom] se escribe al final. Android crea una tabla en memoria de tamaños de trama y otros parámetros que luego escribe al principio del archivo al final de la grabación debido a que necesita la capacidad de búsqueda del manejador de archivo. [Que un socket no es]
Si está escribiendo contenido cifrado en el disco y desea hacerlo para que nadie pueda reproducir el archivo no tiene que cifrar todo el archivo. Sólo tiene que cifrar el encabezado y el archivo entero no puede reproducirse.
Si necesitas desesperadamente la codificación completa de archivos porque no estás convencido de mi anterior parámetro, entonces usa algo como ffmpeg para hacer la codificación. Modifíquelo le da salida cifrada sí mismo y la ahorra al disco duro otra vez – quita la pieza del zócalo otra vez.
No hay manera de que pueda hacer streaming en vivo de archivos mp4 en android. He visto toneladas de gente tratando en vano y si entiendes video / formatos no hay forma de que puedas hacerlo. Mp4 no está diseñado para transmisión en vivo. A menos que conozca los tamaños de su marco de antemano [que no lo hace] y la longitud exacta de la codificación [que probablemente no;] no se puede pre-crear el encabezado.
PD. Mp4 y 3gp son primos por lo que se aplica lo mismo.
Muchas personas confunden la transmisión en vivo con http pd y pseudo streaming. Live streaming significa que no tengo todo el archivo, que se está creando y también se está transmitiendo sobre la marcha. Http pd y pseudo streaming tienen lugar con archivos que están totalmente disponibles.
EDITAR:
Si su objetivo es cifrar el archivo grabado antes de almacenar en sdcard necesita soporte de codificador. Esto implica tener su propio codificador allí. Tome ffmpeg, recopilar cruzarlo a android. Escribe una pequeña interfaz JNI para tu aplicación. Consiga esto primero sin cifrado. Una vez hecho, donde ffmpeg escribe el flujo, agregue su módulo de cifrado. Lo mismo durante la decodificación. Y3ng creación. Esta es la manera más limpia de hacerlo.
EDIT 2: Vea spydroid para obtener algunas de las características para usted. Hay similares por ahí.
EDIT 3: Para mejorar la calidad de la respuesta estoy explicando una solución imperfecta también dada por otras respuestas:
Uno todavía puede transmitir el AV analizando el mp4 a medida que se genera y el envío de los flujos elementales por separado sobre un socket. El único problema que tendrá que afrontar es que no obtendrá una sincronización AV perfecta, ya que no conoce las marcas horarias exactas de la muestra AV. Sólo android sabe eso y escribe que en la cabecera mp4 al final. Así que no es bueno para ti. Usted tiene que estar haciendo una suposición sobre la tasa de muestreo perfecto de marcos de video y su audio tendrá que ser AMR para asumir 20ms paquetes. En otros casos de audio, empezarás a ver la deriva en largas tiradas [especialmente donde empiezas a tener escenas de alto movimiento]. Esto se debe a que cada paquete de audio generado no corresponde a una duración de tiempo fija [excepto para amr y otros codecs de voz]
En primer lugar, no es muy claro lo que está tratando de hacer.
¿Desea guardar un vídeo mediante programación en un archivo reproducible? Si es así, sólo tiene que usar descriptor de archivo en lugar de socket unix. Esta API de MediaRecord fue diseñada para trabajar con un archivo (no socket unix), precisamente por la razón de acceso aleatorio. Por lo tanto, mi primer consejo sería utilizar descriptor de archivo y obtendrá el archivo correcto al final de la grabación.
Puedes obtener ejemplos aquí: ¿Cómo puedo capturar una grabación de vídeo en Android?
En el caso, si usted está tratando de escribir una aplicación que transmite vídeo desde el dispositivo, tendrá que analizar el flujo en un realime, dividirlo por marcos y enviar marcos por separado. Y la parte más compleja es analizar el flujo (algunos códecs de vídeo, como el ejemplo H263 pueden ser analizados y otros no pueden ser, especialmente si los datos están entrelazados con el audio).
Creo que uno de estos dos proyectos implementa esta funcionalidad: http://sipdroid.org/ http://code.google.com/p/imsdroid/
- Cómo almacenar los datos de la aplicación de Android en la tarjeta SIM con NFC?
- Campo BitmapFactory.Options.inTempStorage