Cómo eliminar las franjas negras de los vídeos

Introducción

En el mundo del desarrollo web, a veces tenemos que lidiar con otros temas que no están directamente relacionados con la programación o el diseño web en sí. En este caso vamos a hablar del cropping en FFmpeg y de cómo utilizarlo para eliminar las franjas negras de los vídeos. Gracias a esto podremos generar *thumbnailsŝ* (vistas previas) de nuestros vídeos para utilizarlos en nuestros proyectos web (como por ejemplo, un clon de Youtube).

A modo de ejemplo veamos la siguiente captura realizada a un vídeo:

Captura de un fotograma de vídeo mostrando las franjas negras

Imaginemos que esta captura se ha realizado automáticamente con una aplicación del lado del servidor (FFmpeg también puede hacer esto). A continuación vamos a utilizar FFmpeg para auto-detectar y eliminar las franjas negras.

Obteniendo los valores de corte automáticamente

El primer paso es utilizar el filtro de vídeo cropdetect para obtener los valores automáticamente. El parámetro de FFmpeg es: -vf "cropdetect=24:16:0".

Los parámetros de cropdetect siguen el formato cropdetect=limit:round:reset.

Este parámetro puede contener hasta tres opciones extra. Para nuestro ejemplo no vamos a utilizar ninguno, pero aún asi, una breve explicación:

  • limit: Establece el umbral de intensidad del color negro, que puede ser especificado desde nada (0) hasta todo (255). Por defecto es 24. Esto ayudará cuando nos elimine partes oscuras que no son franjas negras. O viceversa, cuando no esté detectando las franjas porque no son tan negras.
  • round: Asegura que la resolución de salida es divisible por el valor especificado. Por defecto es 16, el mejor valor para la mayoría de los códecs de vídeo.
  • reset: Determina después de cuántos fotogramas cropdetect restablecerá el área de vídeo más grande detectada anteriormente y empezará a contar de nuevo para detectar el área de recorte óptima. Esto es útil cuando hay logotipos o animaciones al inicio de un vídeo. Por defecto es 0, no hay reset.

Ejecutamos el siguiente comando y dado que estamos utilizando 2>&1 el resultado se imprimirá en pantalla.

ffmpeg -i video.mp4 -vf cropdetect -f null - 2>&1
[Parsed_cropdetect_0 @ 000000000268d400] x1:0 x2:719 y1:74 y2:501 w:720 h:416 x:0 y:80 pts:1814400 t:20.160000 crop=720:416:0:80

[Parsed_cropdetect_0 @ 000000000268d400] x1:0 x2:719 y1:74 y2:501 w:720 h:416 x:0 y:80 pts:1814400 t:20.160000 crop=720:416:0:80

Como podemos ver al final del resultado, ya tenemos nuestros valores de corte.

Utilizando los valores de corte

El siguiente paso es utilizar esos valores de la siguiente manera:

ffmpeg -i video.mp4 -vf "crop=720:416:0:80"

Los parámetros de crop siguen el formato crop=w:h:x:y. Donde W y H se refieren al tamaño (width y height), y X e Y se refieren a las coordenadas donde empezará el resultado. Un X e Y de 20 indican que se ignorarán 20px por la izquierda y 20px por arriba.

En este ejemplo, horizontalmente no se quita nada puesto que no hay franjas negras horizontales. Verticalmente, el resultado eliminará 80px en la parte superior mediante el parámetro Y. La parte inferior se calcula de una manera distinta. Nuestro vídeo tiene 576px de altura por lo que después de saltar 80px en la parte superior mediante Y, FFmpeg nos dará un H de 416 (576 - 80 - 80). O lo que es lo mismo, se eliminarán 80px tanto de arriba como de abajo.

Este resultado se puede utilizar en nuestra aplicación de servidor. Por ejemplo, si nuestra aplicación está escrita en PHP podemos utilizar algo parecido a esto:

  • PHP
$cropDetect = shell_exec('ffmpeg -ss 150 -i video.mp4 -vframes 1 -vf cropdetect -f null - 2>&1');
preg_match('/.*crop=([0-9:]+).*/', $cropDetect, $matches);

/*
Esto nos serviría por si queremos hacer algo con los datos de cropdetect
antes de cortar las franjas negras, como por ejemplo, cortar más aún para mantener una relación de aspecto.

$parts = explode(':', $matches[1]);

$output = array();
$output['width'] = (int) $parts[0];
$output['height'] = (int) $parts[1];
$output['x'] = (int) $parts[2];
$output['y'] = (int) $parts[3];
*/

exec('ffmpeg -ss 150 -i video.mp4 -vframes 1 -vf "crop='.$matches[1].'" thumbnail.jpg 2>&1');

Para no recibir una inmensa cantidad de resultados de cropping, hemos utilizado el parámetro -vframes 1, que limita nuestro comando a un solo fotograma. Además, como el primer fotograma es muy probable que sea todo de color negro, saltaremos los primeros 150 segundos mediante el parámetro -ss 150. Estos valores dependerán del tipo de vídeos a los que vayamos a hacer cropping, no es lo mismo un anuncio de 40 segundos que una película de 120 minutos.

El resultado, el siguiente:

Captura de un fotograma de vídeo tras eliminar las franjas negras

Si queremos una consistencia en nuestras vistas previas, en vez de que cada uno tenga un aspecto distinto, este es el paso a seguir.

Recuerda que esto genera imágenes al mismo tamaño que el vídeo original. Si queremos thumbnails más pequeños tenemos que añadir el proceso de redimensionado para hacer las imágenes más pequeñas.

Puedes apoyarme para que pueda dedicar aún más tiempo a escribir artículos y tener recursos para crear nuevos proyectos. ¡Gracias!