2012-09-27 10 views
6

私は外部の動画、主にMP4とFLVからサムネイルを作成しようとしています。私はFFmpegPHPを使用しています。サムネイルの生成は既にうまくいきましたが、最初にサーバーにビデオ全体をロードする必要があります。ビデオの小さな部分だけをストリームしてサムネイルを抽出することは可能でしょうか?FFmpegPHP外部URLからサムネイルを取得

ここでのコードは、私がこれまで持っています:

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'); 

誰でも提案を持っていますか?

EDIT

ブラッドは、ここでは、示唆したように更新されたコードは次のとおりです。

$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); 

答えて

3

FFMPEGが壊れストリームでの作業については非常に良いです。このため、リモートメディアの最初の数メガをダウンロードして、不完全なファイルからサムネイルを取得しようとするべきだと思います。

まず、file_get_contents()をドロップし、cURLを使用します。 CURLOPT_WRITEFUNCTIONオプションは、ディスク上の一時ファイル(チャンクでチャンク)に書き込むカスタム関数に設定できます。十分なデータを受け取ったら、関数から0を返し、cURLのダウンロードを停止します。最適なサイズが何であるかを実験する必要があります。データが少なすぎると、最も早いフレームしか使用できません。まったくフレームがありません。あまりにも遅く、帯域幅を無駄にしています。

いくつかのコンテナタイプでは、ファイル情報はファイルの最後にあります。それらについては、私はあなたのための提案を持っていません。自分のデコーダを作成し、最初から何かを使って最後に情報をスプライスするのではなく、ファイル全体をダウンロードせずにそれを行う方法はわかりません。 PHP 5でコードを実行している

+0

これまでのところ、私は全体をダウンロードすることなく、サムネイルを抽出することができます。しかし、可能であれば中間のフレームを得ることを望んでいました。何とかストリームを前進させてから、ストリームの真ん中に当たって情報を取得するまで0を書くことはできますか?また、そこから情報を取得するためにファイルをダウンロードする必要がある時間を計算する方法はありますか? – jValdron

+0

@jValdron、MPEGストリームの場合、真ん中でちょうどジャンプできます。他の多くのコーデックやコンテナでも同じことが可能です。範囲要求を使用して、必要なバイト数を指定することができます。参照:http://stackoverflow.com/a/8507991/362536ほとんどのサーバーでサポートされています。長さを取得するには、 'HEAD'リクエスト(サポートされている場合)を実行するか、' GET'して長さヘッダを受け取った後にキャンセルします。 – Brad

+0

このBradとお時間をいただきありがとうございます。さて、私はちょうど中間のフレームを取得する方法を理解する必要があります:) – jValdron

0

、クラスベースの構造とffmpegのとCURLは以下の通りです:

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; 
関連する問題