Crear Miniaturas de Videos con FFmpeg en PHP

3 de Octubre - en PHP

FFmpeg es un conjunto de librerías de código abierto para la codificación y de codificación de video, además de contener múltiples herramientas. Utilizaremos esta librería para crear una cuadricula de miniaturas de un video.

Crear miniatura de video con FFmpeg en PHP

Capturando un cuadro de un video

Para ejecutar FFmpeg utilizaremos la función exec de PHP para ejecutar comandos. En este ejemplo capturaremos un cuadro del video ‘video.mp4’ en el segundo 10.

//Capturando el un cuadro del archivo 'video.mp4' en el segundo 4
exec('ffmpeg -i video.mp4 -ss 00:00:14.000 -vframes 1 captura.jpg 2>&1');

Donde:

  • -i video.m4: Archivo de entrada
  •  -ss 00:00:14.000: tiempo exacto para realizar la captura, expresado en Horas Minutos Segundos Milisegundos
  • -vframes 1 captura.jpg: Archivo de salida

Capturando cuadros de un video por intervalo

Otra forma útil de utilizar FFmpeg, es realizar capturas de videos por intervalos de tiempo, se tomaran capturas del video cada 10 segundos:

exec('ffmpeg -i '.$video.' -vf fps=1/10 image%d.jpg');

Crear Miniaturas de Videos

Para crear la miniatura de un video utilizaremos el ejemplo anterior para realizar la captura de un cierto número de cuadros de un video y posteriormente unirlos en una sola imagen para crear la cuadricula utilizando la librería GD de PHP.  El video de ejemplo utilizado tiene las siguientes características:

  1. Título: Caminandes: Llamigos (Blender Foundation)
  2. Duración: 2:30 m
  3. Resolución: 1280x720p

Comenzaremos definiendo las variables de configuración, como lo son la url del video, el número de capturas verticales y horizontales, además del tamaño de las capturas.

// Variables de configuración
$video = 'video.mp4';//Url del video    
$ch = 4;//Numero de capturas horizontales
$cv = 4;//Numero de capturas verticales            
$w = 320;//Ancho de las capturas finales
$h = 180;//Alto de las capturas finales
       
//Numero de capturas totales
$nc = $ch*$cv;

Utilizaremos FFprobe una librería conjunta de FFmpeg, la cual nos proporcionara información acerca del video, la información devuelta estará en formato json, la decodificaremos y extraeremos los datos que nos interesan, los cuales son la duración total del video y su resolución.

//Utilizando ffprobe para extraer la información del video en formato json
//La variable $out devuelve el array de datos
//la variable $res devuelve 0: error, 1: correcto
//Se utilizan las banderas -show_format -show_streams -hide_banner, para filtrar la información devuelta
exec('ffprobe -i '.$video.' -v quiet -print_format json -show_format -show_streams -hide_banner', $out, $res);
               
//Veficar si ocurrio un error
if($res==1){ echo 'Error al leer informacion del video'; exit;}
              
//Decodificando la informacion en json
$info = json_decode(implode($out));

//Datos a extraer
$time = $info->format->duration;//Duración total en segundos
$vw = $info->streams[0]->width;//Ancho del video
$vh = $info->streams[0]->height;//Alto del video

La duración total esta expresada en segundos, por lo cual para calcular el intervalo de captura solo tendríamos que dividir el tiempo total entre el número de capturas a realizar (menos 1 debido a que se realizar una captura inicial y final). Utilizaremos FFmpeg para realizar las capturas, las cuales se guardaran en la carpeta tem.

//Calculando el intervalo de captura
$intervalo = ($time/($nc-1));
              
//Capturando los fotogramas según el intervalo calculado
//Las capturas se guardaran en la carpeta "tem" en formato .jpg
exec('ffmpeg -i '.$video.' -vf fps=1/'.$intervalo.' tem/i%d.jpg', $out, $res);
              
//Verificar si ocurrió un error
if($res==1){ echo 'Error al realizar capturas del video'; exit;}

Una vez realizadas la capturas, crearemos las miniatura uniendo todas las imágenes, pero antes es necesario escalarlas al tamaño indicado (esto podría haberse realizado directamente desde FFmpeg indicando el tamaño de las imágenes a guardar, pero se realizara un escalado de las capturas con GD, sin perder las proporciones), utilizando GD y la función imagecopyresampled, la cual se encargara de ajustar las capturas sin perder la proporción.             

//Creando la miniatura con el tamaño total
$miniatura = @imagecreatetruecolor($w*$ch, $h*$cv);
              
//Variables para controlar la posicion de las capturas
$pv = 0;
$ph = 0;
              
//Imagen temporal para ajustar las capturas al tamaño indicado
$tem = @imagecreatetruecolor($w, $h);

for($i=1; $i<=$nc; $i++){                              
     //Cargando la captura No. $i
     $src=imagecreatefromjpeg('tem/i'.$i.'.jpg');

     //Calculando la proporcion para escalar las capturas
     if($vw>$vh)                      
          $p=$w/$vw;//Para videos horizontales
     else
          $p=$h/$vh;//Para videos verticales                      

     //Obteniendo nuevo ancho y alto
     $nw=round($vw*$p);
     $nh=round($vh*$p);

     //Calculando la posicion para ajustar
     $x=round(($w/2)-($nw/2));
     $y=round(($h/2)-($nh/2));

                              
     //Copiando y ajustando la captura a la imagen temporal
     imagecopyresampled($tem, $src, $x, $y, 0, 0, $nw, $nh, $vw, $vh);

     //Calculando la posicion en miniatura e incrementando valores $ph y $pv
     $px = $w*$ph;
     $py = $h*$pv;                  
     $ph++;
     if($ph>=$ch){
        $ph=0;
        $pv++;
     }

     //Copiando la captura ajustada a la miniatura final
     imagecopy($miniatura , $tem, $px, $py, 0, 0, $w, $h);                  
}
                             
//Guardando miniatura en formato .jpg con 80% de calidad
imagejpeg($miniatura, 'miniatura.jpg', 80);

imagedestroy($tem);
imagedestroy($src);     
imagedestroy($miniatura);

Resultado final:

Miniaturas de videos con FFmpeg en PHP

Ejemplo

Descargar
Etiquetas
PHP ffmpegvideo
Compartir