Saltar al contenido
rodolfo.gg
Regresar

Cómo abrir y compartir los videos .h264 de una cámara Easytao

… CC BY-NC-ND 4.0
Rodolfo González González
en es

Cómo abrir y compartir los videos .h264 de una cámara Easytao

Introducción

Hace un año compré una cámara de vigilancia económica de la marca Easytao, listada en Amazon como modelo Q25. Estas cámaras son poco menos que genéricas, aunque tienen un desempeño decente. No se comparan con otras opciones económicas como las de marca Imou, pero son relativamente más baratas y descartables si son dañadas o robadas.

Cámara Easytao Q25 con panel solar, antenas y soporte de pared.

Recientemente tuve la necesidad de revisar los videos grabados en la tarjeta microSD de la cámara y luego compartirlos por WhatsApp. Extraje la tarjeta y la conecté a mi computadora (Debian Sid), pero VLC no reproducía los archivos con extensión .h264. El comando file tampoco los reconocía y sólo respondía data. Esto me llevó a investigar qué formato tenían en realidad y cómo convertirlos a un contenedor MP4 compatible con WhatsApp. Claro, con la ayuda de “Claudio” y FFmpeg.


Tabla de contenido

Tabla de contenido

Los archivos

Las cámaras de vigilancia económicas, como las de la marca Easytao, guardan sus grabaciones en una tarjeta microSD con nombres como este:

17.37.43-17.37.48[R][@0][0].h264

El nombre contiene la hora de inicio y de fin del clip. La letra entre corchetes parece indicar el tipo de grabación: la mayoría de los clips llevan R y algunos llevan A, probablemente por una alarma de movimiento. La extensión promete un video H.264, pero VLC no lo reproduce y el comando file sólo responde data.

En este artículo analizarás el contenido del archivo byte por byte y descubrirás qué formato tiene en realidad. Luego lo convertirás a MP4 sin perder calidad y lo recodificarás para compartirlo por WhatsApp. Al final tendrás un script de Bash que detecta el formato de entrada por sí mismo, sin confiar en la extensión.

Qué hay dentro del archivo

Un archivo sin contenedor no tiene metadatos que lo identifiquen, así que hay que leer sus primeros bytes. od viene instalado en cualquier sistema Linux:

Terminal window
od -A x -t x1 -N 48 '23.40.19-23.40.24[R][@0][0].h264'
000000 00 00 01 fc 13 0c 40 b4 13 7a 6f 6a ce e0 00 00
000010 00 00 00 01 40 01 0c 01 ff ff 01 60 00 00 03 00
000020 b0 00 00 03 00 00 03 00 99 ac 09 00 00 00 01 42

Los videos H.264 y H.265 (HEVC) sin contenedor usan el formato Annex B: una secuencia de unidades NAL (Network Abstraction Layer), cada una precedida por el código de inicio 00 00 01 o 00 00 00 01. El byte que sigue al código de inicio es el encabezado de la unidad y codifica su tipo.

Aquí conviven dos cosas distintas:

  1. Un bloque propietario de 16 bytes que empieza con 00 00 01 FC. No pertenece a ningún estándar de video y su estructura no está documentada. Algunos de sus campos cambian de un archivo a otro, así que probablemente guardan una marca de tiempo o un contador del fabricante.
  2. El video en sí, a partir del offset 0x10, donde aparece el código de inicio 00 00 00 01 seguido del byte 40.

H.264 y HEVC calculan el tipo de NAL de forma distinta

El mismo byte significa cosas diferentes en cada estándar:

Si aplicas las dos fórmulas a los bytes que siguen a cada código de inicio del archivo, obtienes esta tabla:

ByteComo HEVCComo H.264
4032: VPS (Video Parameter Set)0: sin especificar
4233: SPS2: partición A de un slice
4434: PPS4: partición C de un slice
4E39: SEI14: prefijo de NAL (extensión SVC)
2619: cuadro IDR (keyframe)6: SEI

Leído como HEVC, el archivo tiene la secuencia de arranque canónica: VPS, SPS, PPS, SEI y un keyframe. Leído como H.264 no tiene sentido: no aparecen ni SPS ni PPS, y el keyframe se confunde con un mensaje SEI. La pareja XX 01 después de cada código de inicio delata también el encabezado de dos bytes de HEVC.

Conclusión: el archivo es HEVC crudo en formato Annex B, con un bloque propietario al inicio, aunque su extensión diga .h264. Las cámaras baratas suelen grabar en H.265 para ahorrar espacio en la tarjeta, y su firmware conserva la extensión de los modelos anteriores.

Por qué VLC y la autodetección de FFmpeg fallan

Un stream Annex B carece de “número mágico” propio: el código de inicio es igual en H.264 y en HEVC. Los reproductores tienen que adivinar, y adivinan mal por dos razones:

Puedes comprobarlo con ffprobe. La opción -count_frames obliga a decodificar el stream completo y a contar los cuadros que realmente salen:

Terminal window
f='23.40.19-23.40.24[R][@0][0].h264'
ffprobe -v quiet -select_streams v:0 -count_frames \
-show_entries stream=codec_name,width,height,nb_read_frames -of csv=p=0 "$f"
ffprobe -v quiet -f hevc -select_streams v:0 -count_frames \
-show_entries stream=codec_name,width,height,nb_read_frames -of csv=p=0 "$f"
h264,0,0,N/A
hevc,2560,1440,65

Con la autodetección, FFmpeg no obtiene ni la resolución. Al forzar el formato con -f hevc, aparecen la resolución de 2560×1440 y los 65 cuadros del clip.

Recuperar el video sin recodificar

Ya que sabes el formato, basta con pasar el stream a un contenedor MP4. -c copy copia los datos comprimidos tal cual, así que la conversión es instantánea y no pierde calidad:

Terminal window
ffmpeg -f hevc -framerate 12.5 -i '17.37.43-17.37.48[R][@0][0].h264' \
-c copy salida.mp4

Un stream crudo no guarda marcas de tiempo, así que el contenedor no sabe a qué velocidad reproducir los cuadros. Por eso hace falta -framerate. Para calcular el valor, divide los cuadros del clip entre su duración, que sale del nombre del archivo: 65 cuadros entre 17:37:43 y 17:37:48 dan unos 12.5 cuadros por segundo. Si el resultado se ve acelerado o en cámara lenta, prueba con 15 o 25, que son frecuencias habituales en estas cámaras.

Para convertir una carpeta completa:

Terminal window
for f in *.h264; do
ffmpeg -nostdin -v error -f hevc -framerate 12.5 -i "$f" -c copy "${f%.h264}.mp4"
done

El MP4 resultante se reproduce en VLC y en la mayoría de los reproductores de escritorio, pero sigue siendo HEVC por dentro.

Convertir para WhatsApp

WhatsApp no garantiza la reproducción de HEVC en todos los teléfonos: según el dispositivo, rechaza el archivo o lo envía como documento en lugar de video. La combinación más compatible es H.264 con audio AAC dentro de un MP4, así que esta vez sí hay que recodificar:

Terminal window
ffmpeg -nostdin -f hevc -framerate 12.5 -i '10.04.47-10.04.58[A][@0][0].h264' \
-vf "scale=-2:1080:out_range=tv,format=yuv420p,fps=25" \
-c:v libx264 -preset medium -crf 23 -profile:v high -level 4.0 \
-movflags +faststart salidcam2whatsapp.mp4

Cada opción resuelve un problema concreto:

OpciónMotivo
-c:v libx264 -profile:v high -level 4.0H.264 High, nivel 4.0: cualquier teléfono de la última década lo decodifica por hardware en 1080p.
scale=-2:1080Reduce 2560×1440 a 1920×1080. WhatsApp vuelve a comprimir el video de todos modos, así que enviar 1440p sólo gasta datos. -2 calcula un ancho par que respeta la proporción.
out_range=tv,format=yuv420pLa cámara graba en rango de color completo (yuvj420p). Algunos reproductores lo muestran deslavado o no lo reproducen; el rango limitado es el estándar para video.
fps=25Duplica cuadros hasta una frecuencia constante de 25 fps. Algunos reproductores móviles se atoran con frecuencias poco comunes como 12.5.
-crf 23 -preset mediumCalidad visual constante con un tamaño razonable: unos 2.8 MB por cada 10 segundos de este video.
-movflags +faststartColoca el índice del MP4 al principio del archivo, para que la reproducción empiece antes de terminar la descarga.

Sin format=yuv420p, FFmpeg conserva el formato yuvj420p de la cámara aunque indiques -pix_fmt yuv420p. Compruébalo en el archivo de salida:

Terminal window
ffprobe -v error -show_entries stream=codec_name,profile,pix_fmt,color_range \
salidcam2whatsapp.mp4
[STREAM]
codec_name=h264
profile=High
pix_fmt=yuv420p
color_range=tv
[/STREAM]

Si necesitas archivos más pequeños, usa scale=-2:720 o sube el valor a -crf 26. Cualquiera de los dos cambios reduce el tamaño a la mitad, aproximadamente.

Detectar el formato de forma genérica

El comando anterior depende de saber de antemano que el archivo es HEVC. Si mezclas grabaciones de varias cámaras, o si un firmware nuevo cambia el códec, necesitas detectar el formato automáticamente.

Como ya viste, ni la extensión, ni file, ni la autodetección de FFmpeg sirven con estos archivos. La estrategia robusta es empírica: probar varios formatos candidatos y quedarse con el que decodifique más cuadros. La autodetección entra como un candidato más, y así los MP4, MKV o AVI normales se procesan con su contenedor.

Contar cuadros descarta los falsos positivos de forma natural: el demuxer de H.264 “abre” el archivo HEVC sin error, pero produce 0 cuadros, así que pierde frente a -f hevc. El costo es bajo: decodificar un clip de 10 segundos toma menos de un segundo.

El script completo

Guarda el script como cam2whatsapp.sh. Recibe una lista de archivos, detecta el formato de cada uno y escribe los resultados en una carpeta whatsapp/:

cam2whatsapp.sh
#!/usr/bin/env bash
# Convierte videos (con contenedor o streams crudos de cámara) a MP4 compatible con WhatsApp.
# Uso: ./cam2whatsapp.sh archivo... ; salida en ./whatsapp/
# FPS para streams crudos sin timestamps (la cámara graba ~12.5).
FPS_CRUDO=${FPS_CRUDO:-12.5}
# Devuelve cuántos cuadros se decodifican con el formato dado ("" = autodetección).
cuadros() {
local fmt=$1 f=$2
ffprobe -v quiet ${fmt:+-f $fmt} -select_streams v:0 -count_frames \
-show_entries stream=nb_read_frames -of csv=p=0 "$f" | tr -dc 0-9
}
mkdir -p whatsapp
for f in "$@"; do
mejor= max=0
# Lista fija de candidatos; agrega mjpeg o mpeg4 si tu cámara usa otro códec.
for fmt in "" hevc h264; do
n=$(cuadros "$fmt" "$f"); n=${n:-0}
(( n > max )) && max=$n mejor=${fmt:-auto}
done
if (( max == 0 )); then echo "✗ $f: formato no reconocido"; continue; fi
echo "→ $f: $mejor ($max cuadros)"
entrada=(-i "$f")
[[ $mejor != auto ]] && entrada=(-f "$mejor" -framerate "$FPS_CRUDO" -i "$f")
ffmpeg -nostdin -v error -y "${entrada[@]}" -map 0:v:0 -map '0:a:0?' \
-vf "scale=-2:'min(1080,ih)':out_range=tv,format=yuv420p,fps=25" \
-c:v libx264 -preset medium -crf 23 -profile:v high -level 4.0 \
-c:a aac -b:a 128k -movflags +faststart \
"whatsapp/$(basename "${f%.*}").mp4" 2>&1 | grep -v -e NALU -e PPS
done

Algunos detalles de la implementación:

Uso

Asumamos que los archivos de video de la cámara están en el directorio videos.

Dale al script permisos de ejecución y pásale los archivos que quieras convertir:

Terminal window
chmod +x cam2whatsapp.sh
cd videos
../cam2whatsapp.sh *.h264

El script informa qué formato eligió para cada archivo:

→ 23.40.19-23.40.24[R][@0][0].h264: hevc (65 cuadros)
→ copia-sin-extension: hevc (65 cuadros)
→ otro-video.mkv: auto (50 cuadros)

La segunda línea corresponde al mismo archivo sin extensión, y la tercera a un MKV normal con video HEVC y audio MP3. En los tres casos, el resultado es H.264 con yuv420p, más AAC cuando el original trae audio.

Si el video de otra cámara se ve acelerado o lento, cambia la frecuencia supuesta para los streams crudos:

Terminal window
FPS_CRUDO=15 ../cam2whatsapp.sh *.h264

Resolución de problemas

ProblemaComprobación y solución
✗ formato no reconocidoRevisa los primeros bytes con od -A x -t x1 -N 64. Si no aparecen códigos de inicio 00 00 01, el archivo no es Annex B; prueba ffmpeg -formats y agrega el formato adecuado a la lista de candidatos.
El video se reproduce demasiado rápido o lentoCuenta los cuadros con ffprobe -f hevc -count_frames y divídelos entre la duración que indica el nombre del archivo. Usa ese valor en FPS_CRUDO.
Aparecen PPS id out of range o Failed to parse headerSon los bloques propietarios de la cámara, que el decodificador descarta. Confirma que el número de cuadros de la salida coincide con el de -count_frames.
WhatsApp envía el video como documentoComprueba con ffprobe que la salida sea h264 con yuv420p. Si el archivo es muy grande, reduce la resolución a 720p o sube el valor de -crf.
Los colores se ven deslavados en el teléfonoFalta la conversión de rango. Verifica que el filtro incluya out_range=tv,format=yuv420p y que ffprobe reporte color_range=tv.
El bucle se salta archivosFalta -nostdin en alguna llamada a ffmpeg dentro del bucle.

Fuentes


Lee la licencia del contenido original

El contenido no original se incluye o referencia bajo uso justo.


Artículo anterior
Tocando la luz
Artículo siguiente
Análisis exploratorio de datos con Python para aprendizaje automático.

Licencia del contenido original: CC BY-NC-ND 4.0

El contenido no original se incluye o referencia bajo uso justo.

Cargando licencia…