2012-09-27 69 views
6

Estoy tratando de crear miniaturas de videos externos, principalmente MP4 y FLV. Estoy usando FFmpegPHP. Ya tengo la generación de miniaturas funcionando bien, sin embargo, primero necesito cargar el video completamente en mi servidor. ¿Sería posible transmitir solo una pequeña parte del video y luego extraer la miniatura de eso?FFmpegPHP obtener una miniatura de la URL externa

Aquí está el código que tengo hasta ahora:

require_once PRIV . 'Vendor/FFmpegPHP/FFmpegAutoloader.php'; 

// Download the whole video. 
$video = file_get_contents($_PUT['video']); 
$file = 'path_to_cache'; 
file_put_contents($file, $video); 

$movie = new FFmpegMovie($file); 

// Generate the thumbnail. 
$thumb = $movie->getFrame($movie->getFrameCount()/2); 
$thumb->resize(320, 240); 
imagejpeg($thumb->toGDImage(), 'path_to_thumb'); 

Cualquier persona tiene una sugerencia?

EDITAR

Como sugirió Brad, aquí es el código de actualización:

$file = CACHE . 'moodboard_video_' . rand(); 
$fh = fopen($file, 'w'); 
$size = 0; 

curl_setopt($ch, CURLOPT_URL, $_PUT['video']); 
curl_setopt($ch, CURLOPT_HEADER, 0); 
curl_setopt($ch, CURLOPT_WRITEFUNCTION, function($ch, $data) use($fh, &$size){ 
    $length = fwrite($fh, $data); 

    if($length === FALSE) { 
     return 0; 
    } else { 
     $size += $length; 
    } 

    // Downloads 1MB. 
    return $size < 1024 * 1024 * XXXXXX ? $length : 0; 
}); 

curl_exec($ch); 

fclose($fh); 
curl_close($ch); 

// Create the thumbnail. 
$thumb = $movie->getFrame(XXXXXX); 
$thumb->resize(static::DEFAULT_THUMBNAIL_WIDTH, $thumb->getHeight()/$thumb->getWidth() * static::DEFAULT_THUMBNAIL_WIDTH); 
$image = $thumb->toGDImage(); 
imagejpeg($image, PRIV . static::THUMBNAILS_PATH . $item->getLastInsertIdentifier() . '_' . static::DEFAULT_THUMBNAIL_WIDTH); 

Respuesta

3

FFMPEG es muy bueno de trabajar con corrientes rotos. Debido a esto, creo que deberías intentar descargar los primeros megas de ese medio remoto e intentar obtener una miniatura del archivo incompleto.

Primero, suelte file_get_contents() y use cURL. Puede establecer la opción CURLOPT_WRITEFUNCTION en una función personalizada suya que se escribe en un archivo temporal en disco, fragmento por fragmento. Cuando haya recibido suficientes datos, devuelva 0 de su función y cURL dejará de descargar. Tendrás que experimentar para ver cuál es el tamaño óptimo. Si obtiene muy pocos datos, solo tendrá los marcos más antiguos para trabajar o no tendrá marcos. Demasiado tarde, y está desperdiciando ancho de banda.

Para algunos tipos de contenedores, la información del archivo se encuentra al final del archivo. Para aquellos, no tengo una sugerencia para ti. Después de escribir su propio decodificador y empalmar la información al final con algo desde el principio, no sé de qué manera hacerlo sin descargar todo el archivo.

+0

Hasta el momento, se puede extraer una imagen en miniatura sin tener que descargar todo el asunto. Sin embargo, esperaba obtener el marco intermedio (ish) si es posible. ¿Puedo simplemente avanzar mi flujo de alguna manera y luego escribir 0 hasta que llegue a la mitad de la secuencia y obtener información sobre eso? Además, ¿hay alguna manera de calcular cuánto tiempo necesito descargar un archivo para obtener información de él? – jValdron

+0

@jValdron, para las transmisiones MPEG, a menudo puede simplemente saltar justo en el medio. Muchos otros códecs y contenedores permiten lo mismo. Puede usar una solicitud de rango para especificar qué bytes quiere. Ver también: http://stackoverflow.com/a/8507991/362536 La mayoría de los servidores lo admiten. Para obtener la longitud, puede hacer una solicitud 'HEAD' (donde sea compatible), o' GET' y luego cancelar después de recibir el encabezado de longitud. – Brad

+0

Gracias por su tiempo con este Brad. Ahora, solo necesito averiguar cómo obtener el marco medio :) – jValdron

0

la ejecución de código con PHP 5, ffmpeg y el rizo con una estructura basada en categorías según se indica a continuación:

require_once 'PHP_CURFN/ffmpeg-php-master/FFmpegFrame.php'; 
    require_once 'PHP_CURFN/ffmpeg-php-master/FFmpegAutoloader.php'; 

class MyVideoTest{ 

private $fh=""; 
private $size=0; 
private $ch=""; 

public function __construct(){ 

       $video = 'http://[hosturl]/video/41a669911fd635167475d7530bffcc9f.mp4'; 
       $file = 'PHP_CURFN/cache/tmp_video_' . rand(); 


       $this->ch = curl_init(); 
       $this->fh = fopen ($file, 'w+'); 
       $this->ch = curl_init($video); 

       $this->size = 0; 
       curl_setopt($this->ch, CURLOPT_URL, $video); 
       curl_setopt($this->ch, CURLOPT_HEADER, 0); 


       curl_setopt($this->ch, CURLOPT_WRITEFUNCTION, array($this, "myfunction")); 

       curl_exec($this->ch); 

       fclose($this->fh); 
       curl_close($this->ch); 
       $movie = new FFmpegMovie($file); 
       // Create the thumbnail. 

       $thumb = $movie->getFrame(2); 
       $thumb->resize(320, 240); 
       $image = $thumb->toGDImage(); 
       imagejpeg($image, 'PHP_CURFN/cache' . $item->getLastInsertIdentifier() . '_' . 320); 

} 
function myfunction($ch, $data)  { 
     $length = fwrite($this->fh, $data); 
     $size=&$this->size; 

     if($length === FALSE) { 
      return 0; 
     } else { 
      $size += $length; 
     } 

     // Downloads 1MB. 

     return $size < 1024 * 1024 *1 ? $length : 0; 
} } 


$MyVideoTest= new MyVideoTest(); 
pr($MyVideoTest); 
exit; 
Cuestiones relacionadas