web-dev-qa-db-ja.com

ビデオから特定のフレームを抽出する最速の方法(PHP / ffmpeg / anything)

Webページがありますが、(特に)ユーザーがアップロードしたビデオから特定のフレームを抽出する必要があります。ユーザーはプレーヤーの.mp4の特定の部分をシークし、ボタンをクリックすると、ajax呼び出しが.mp4とビデオからの正確な時間を取得するphpスクリプトに送信され、それを使用して抽出します「サムネイル」フレーム。

私の現在のソリューションは、php execコマンドを使用しています。

exec("ffmpeg -i $videoPath -ss $timeOffset -vframes 1 $jpgOutputPath");

...これは糖蜜と同じくらい遅いことを除いて、非常にうまく機能します。私の推測では、ffmpegは仕事には少し多すぎるので、基礎となるライブラリーなどを利用することでより良い結果が得られる可能性があります...しかし、その方法はわかりません。

理想的には、本当の「インストールプロセス」を必要とするものをインストールする必要はありません...つまり、実行可能ファイルをWebアプリでフォルダーにドロップすることは問題ありませんが、実際にインストーラーを実行する必要はありません。また、ソリューションはMac、Linux、およびWindowsで実行できる必要があります(Linuxが最優先事項です)。

このプロセスを高速化するにはどうすればよいですか?

ありがとう。

47
DanM

もちろん、いくつかのC/C++をコーディングして-lav *にリンクし、基本的にフレームを抽出するためにffmpegの簡易バージョンを作成し、PHP拡張機能として実行することもできます(同じユーザーとして実行しません) 、もちろん同じプロセスで)。ただし、フォークとセットアップのオーバーヘッドを回避するだけであるため、結果が高速になることはほとんどありませんが、実際の問題はデコードであり、これは依然として同じです。

代わりに、最初にffmpegを高速シークモード(または高速/正確なハイブリッドモード)で使用することを検討する必要があります。 彼らのウィキの状態 高速シークについて:

-ssパラメーターは、-iの前に指定する必要があります。

ffmpeg -ss 00:03:00 -i Underworld.Awakening.avi -frames:v 1 out1.jpg

この例では、ムービーの開始から3分前後のどこかに1つのイメージフレーム(out1.jpg)を生成します。入力はキーフレームを使用して解析されますが、これは非常に高速です。欠点は、特定の時間(00:03:00)にあるとは限らないキーフレームでもシークを終了するため、シークが期待どおりに正確にならないことです。

高速シークはそれほど正確ではありませんが、ffmpegはシーク中にムービーの大部分を実際にデコードする必要がないため、非常に高速です。一方、高速/正確なハイブリッドモードは妥協点です。使用可能なすべてのオプションについては、 wikiページ をお読みください。

編集14/06/10

FFmpeg 2.1の時点で、ffmpegを使用してトランスコードする場合(つまり、ストリームコピーではない場合)、-ssは、入力オプションとして使用する場合でも正確になりました。 -noaccurate_seekオプションを使用すると、以前の動作を復元できます。 (ソース)

したがって、2.1 +では、再エンコードに関して正確な結果を得るために「ハイブリッド」シークはもう必要ありません(.jpegへの保存は再エンコードです)。低速シーク(-ss ... -i ...)ではなく、通常の高速シーク(-i ... -ss ...)を行うだけで十分です。

72
nmaier