みなさん、こんにちは。どんぶラッコです。
今日は、ffmpegで複数音源ファイルを1つのファイルにまとめる方法について解説していきます。
PHP-FFMpegの方は動作未確認だけどテストで作ったコードがあるのでついでに公開しますね
今回実現したいこと
- no2.webm, no3.webm, no4.webm を用意する
- 音源を結合する
- ついでにフィルターを使えるようにする(今回は指定ミリ秒だけ音源の前に無音部分を挿入する)
ffmpegで複数音源の合成
ffmpeg -i no2.webm -i no3.webm -i no4.webm -filter_complex "[0]adelay=1000[a0];adelay=2000[a1];adelay=3000[a2];[a0][a1][a2]amix=inputs=3[a]" -map "[a]" out.webm
-i
を使って読み込むファイルを指定します。
次に、 -filter_complex
を 使って、各ファイルに対して実施したいフィルタ処理を選択していきます。
-filter_complex
の中身は、 ;
でフィルターチェーンが区切られていきます。
文法としては
[in_link_N]filter_name@id=arguments[out_link_1]...[out_link_M]
のようになっています。[]
と []
の間にフィルター処理を記述することでフィルターを適用できるんですね。
今回はそれぞれの音源に対して adelay=XXXX
をかけています。例えばXXXXが1000だったら 1000ミリ秒 = 1秒 音源の開始時間を遅らせるという処理です。
そしてフィルター処理が終わったそれぞれの音源を [a0]
, [a1]
, [a2]
, として出力させています。
その上で、 [a0][a1][a2]amix=inputs=3[a]
処理をかけることで、mixさせているわけですね。そしてミックスが完了した音源を [a]
にアウトプットさせ、出力ファイルを生成する元を -map
で指定することで、ミックスされた音源が出力ファイルとして生成されます
Laravel-FFMpegで書いてみよう!
Laravelでかくとこんな感じになります。
use ProtoneMedia\LaravelFFMpeg\Filesystem\Media;
use ProtoneMedia\LaravelFFMpeg\Support\FFMpeg;
// ... 中略
$ffMpeg = FFMpeg::open(['no2.webm', 'no3.webm', 'no4.webm'])->export();
$ffMpeg->addFilter('[0]', 'adelay=1000', '[a0]');
$ffMpeg->addFilter('', 'adelay=2000', '[a1]');
$ffMpeg->addFilter('', 'adelay=3000', '[a2]');
$ffMpeg->addFilter('[a0][a1][a2]', 'amix=inputs=3', '[a]');
$ffMpeg->addFormatOutputMapping(new \FFMpeg\Format\Video\WebM, Media::make('local', 'out.webm'), ['[a]']);
$ffMpeg->save();
処理ごとに書けるので、こっっちの方が読みやすいかもしれませんね!
addFormatOutputMapping内にある Media::make('local', 'out.webm')
部分がアウトプットファイル作成の指示です。
local
の部分は、保存したいストレージの名前を指定してください。もし s3
の設定をされている場合は s3
にすればちゃんと向き先も変わってくれます。
PHP-FFMpegの場合(※動作未確認)
PHP-FFMpegの場合はドキュメントを読む限り、こうやって書けばいいんじゃないかな?と思っています。
ただ、私は動作未確認です。あくまでもイメージとしてお考えください。
$ffmpeg = FFMpeg::create();
$advancedMedia = $ffmpeg->openAdvanced($urls);
$advancedMedia->filters()->custom('[0]', 'adelay=1000', '[a0]');
$advancedMedia->filters()->custom('[0]', 'adelay=2000', '[a1]');
$advancedMedia->filters()->custom('[0]', 'adelay=3000', '[a2]');
$advancedMedia->filters()->custom('[a0][a1][a2]', 'amix=inputs=3', '[a]');
$advancedMedia->map(array('[a]'), new \FFMpeg\Format\Video\WebM, 'test_output');
$advancedMedia->save();
意外とffmpegの情報出てこないんですよね〜。でも英語のドキュメントを読んだらしっかり解説されているので、頑張って英語を読みましょう笑