概要
FFmpegで、画面を上下左右4つに分割し、それぞれの場所で動画4つを同時に再生させ、1つの動画にするコマンドを記載します。
手順
4つの動画を同時に再生させ1つの動画に
単純に4つの動画を合体するコマンドを示します。
# 1つの動画の画面解像度
# Full HDの場合は以下になる(最終的に出来上がる動画はFull HD x 4 となる
cut_w=1920
cut_h=1080
input0='左上の動画ファイルパス.mp4'
input1='右上の動画ファイルパス.mp4'
input2='左下の動画ファイルパス.mp4'
input3='右下の動画ファイルパス.mp4'
ffmpeg -i "$input0" -i "$input1" -i "$input2" -i "$input3" \
-filter_complex "\
amix=inputs=4:duration=longest,loudnorm;\
[0:v] setpts=PTS-STARTPTS, scale=${cut_w}x${cut_h} [upperleft];\
[1:v] setpts=PTS-STARTPTS, scale=${cut_w}x${cut_h} [upperright];\
[2:v] setpts=PTS-STARTPTS, scale=${cut_w}x${cut_h} [lowerleft];\
[3:v] setpts=PTS-STARTPTS, scale=${cut_w}x${cut_h} [lowerright];\
[upperleft]pad=2*iw:2*ih[v0];\
[v0][upperright]overlay=w:0[v1];\
[v1][lowerleft]overlay=0:h[v2];\
[v2][lowerright]overlay=w:h;\
" \
-b:v 2M -c:v libx264 \
-c:a libopus -b:a 64k \
output.mp4
以下に各行の詳細を示す。
-
ffmpeg -i "$input0" -i "$input1" -i "$input2" -i "$input3"
- 動画4本をそれぞれ取込む
-
-filter_complex "\
- -filter_complexオプションと呼ばれる設定をし、以降にそれぞれのストリームを定義
-
amix=inputs=4:duration=longest,loudnorm;\
- オーディオストリーム4つをすべてまとめて音量調整し、1つのストリームにする
-
[0:v] setpts=PTS-STARTPTS, scale=${cut_w}x${cut_h} [upperleft];\
-
input0
の映像ストリームを抜き出して[upperleft]
ストリームとして定義
-
-
[1:v] setpts=PTS-STARTPTS, scale=${cut_w}x${cut_h} [upperright];\
-
input1
の映像ストリームを抜き出して[upperright]
ストリームとして定義
-
-
[2:v] setpts=PTS-STARTPTS, scale=${cut_w}x${cut_h} [lowerleft];\
-
input2
の映像ストリームを抜き出して[lowerleft]
ストリームとして定義
-
-
[3:v] setpts=PTS-STARTPTS, scale=${cut_w}x${cut_h} [lowerright];\
-
input3
の映像ストリームを抜き出して[lowerright]
ストリームとして定義
-
-
[upperleft]pad=2*iw:2*ih[v0];\
-
[upperleft]
ストリーム(input0
)を左上に配置する。width、heightそれぞれに2倍の余白を付ける
-
-
[v0][upperright]overlay=w:0[v1];\
- 先ほどのストリームに
[upperright]
ストリーム(input1
)を右上に重ねる
- 先ほどのストリームに
-
[v1][lowerleft]overlay=0:h[v2];\
- 先ほどのストリームに
[lowerleft]
ストリーム(input2
)を左下に重ねる
- 先ほどのストリームに
-
[v2][lowerright]overlay=w:h;\
- 先ほどのストリームに
[lowerright]
ストリーム(input3
)を右下に重ねる
- 先ほどのストリームに
-
-b:v 2M -c:v libx264 \
- 適当な映像エンコード設定
-
-c:a libopus -b:a 64k \
- 適当な音声エンコード設定
-
output.mp4
- 出力ファイル名
4つの動画の開始時間がバラバラな場合(先頭を削除して合わせる)
4つの動画の開始位置がバラバラな場合、それぞれの動画の先頭を削除(trim)して合わせます。以下の遅延が発生しているとします。
-
input1
:input0
に対し、1秒開始が遅れている -
input2
:input0
に対し、2秒開始が遅れている -
input3
:input0
に対し、3秒開始が遅れている
この場合、一番遅れているinput3
の動画に合わせ、それぞれの動画の先頭を以下のように削除(trim)すればよさそうです。
-
input0
: 3秒先頭を削除する -
input1
: 2秒先頭を削除する(3秒-1秒) -
input2
: 1秒先頭を削除する(3秒-2秒) -
input3
: そのまま
遅延をtrimによって解消し、連結するコマンドを示します。
# 1つの動画の画面解像度
cut_w=1920
cut_h=1080
input0='左上の動画ファイルパス.mp4'
input1='右上の動画ファイルパス.mp4'
input2='左下の動画ファイルパス.mp4'
input3='右下の動画ファイルパス.mp4'
# それぞれの動画input0~3の先頭を削除する秒数を設定
trim0=3.000
trim1=2.000
trim2=1.000
trim3=0
ffmpeg -i "$input0" -i "$input1" -i "$input2" -i "$input3" \
-filter_complex "\
[0:v] trim=start=${trim0}, setpts=PTS-STARTPTS, scale=${cut_w}x${cut_h} [upperleft];\
[0:a] atrim=start=${trim0},asetpts=PTS-STARTPTS,loudnorm=I=-16:TP=-1.5:LRA=11 [a0];\
[1:v] trim=start=${trim1}, setpts=PTS-STARTPTS, scale=${cut_w}x${cut_h} [upperright];\
[1:a] atrim=start=${trim1},asetpts=PTS-STARTPTS,loudnorm=I=-16:TP=-1.5:LRA=11 [a1];\
[2:v] trim=start=${trim2}, setpts=PTS-STARTPTS, scale=${cut_w}x${cut_h} [lowerleft];\
[2:a] atrim=start=${trim2},asetpts=PTS-STARTPTS,loudnorm=I=-16:TP=-1.5:LRA=11 [a2];\
[3:v] trim=start=${trim3}, setpts=PTS-STARTPTS, scale=${cut_w}x${cut_h} [lowerright];\
[3:a] atrim=start=${trim3},asetpts=PTS-STARTPTS,loudnorm=I=-16:TP=-1.5:LRA=11 [a3];\
[upperleft]pad=2*iw:2*ih[v0];\
[v0][upperright]overlay=w:0[v1];\
[v1][lowerleft]overlay=0:h[v2];\
[v2][lowerright]overlay=w:h[v];\
[a0][a1][a2][a3]amix=inputs=4:duration=longest,loudnorm[a];\
" \
-b:v 2M -c:v hevc_nvenc \
-c:a libopus -b:a 32k \
-map "[v]" -map "[a]" \
output.mp4
-
ffmpeg -i "$input0" -i "$input1" -i "$input2" -i "$input3"
- 動画4本をそれぞれ取込む
-
-filter_complex "\
- -filter_complexオプションと呼ばれる設定をし、以降にそれぞれのストリームを定義
-
[0:v] trim=start=${trim0}, setpts=PTS-STARTPTS, scale=${cut_w}x${cut_h} [upperleft];\
-
input0
の映像ストリームを抜き出し、$trim0
秒先頭を削除し[upperleft]
ストリームとして定義
-
-
[0:a] atrim=start=${trim0},asetpts=PTS-STARTPTS,loudnorm=I=-16:TP=-1.5:LRA=11 [a0];\
-
input0
の音声ストリームを抜き出し、$trim0
秒先頭を削除し[a0]
ストリームとして定義
-
-
[1:v] trim=start=${trim1}, setpts=PTS-STARTPTS, scale=${cut_w}x${cut_h} [upperright];\
-
input1
の映像ストリームを抜き出し、$trim1
秒先頭を削除し[upperright]
ストリームとして定義
-
-
[1:a] atrim=start=${trim1},asetpts=PTS-STARTPTS,loudnorm=I=-16:TP=-1.5:LRA=11 [a1];\
-
input1
の音声ストリームを抜き出し、$trim1
秒先頭を削除し[a1]
ストリームとして定義
-
-
[2:v] trim=start=${trim2}, setpts=PTS-STARTPTS, scale=${cut_w}x${cut_h} [lowerleft];\
-
input2
の映像ストリームを抜き出し、$trim2
秒先頭を削除し[lowerleft]
ストリームとして定義
-
-
[2:a] atrim=start=${trim2},asetpts=PTS-STARTPTS,loudnorm=I=-16:TP=-1.5:LRA=11 [a2];\
-
input2
の音声ストリームを抜き出し、$trim2
秒先頭を削除し[a2]
ストリームとして定義
-
-
[3:v] trim=start=${trim3}, setpts=PTS-STARTPTS, scale=${cut_w}x${cut_h} [lowerright];\
-
input3
の映像ストリームを抜き出し、$trim3
秒先頭を削除し[lowerright]
ストリームとして定義
-
-
[3:a] atrim=start=${trim3},asetpts=PTS-STARTPTS,loudnorm=I=-16:TP=-1.5:LRA=11 [a3];\
-
input3
の音声ストリームを抜き出し、$trim3
秒先頭を削除し[a3]
ストリームとして定義
-
-
[upperleft]pad=2*iw:2*ih[v0];\
-
[upperleft]
ストリーム(input0
)を左上に配置し、width、heightそれぞれに2倍の余白を付ける
-
-
[v0][upperright]overlay=w:0[v1];\
- 先ほどのストリームに
[upperright]
ストリーム(input1
)を右上に重ねる
- 先ほどのストリームに
-
[v1][lowerleft]overlay=0:h[v2];\
- 先ほどのストリームに
[lowerleft]
ストリーム(input2
)を左下に重ねる
- 先ほどのストリームに
-
[v2][lowerright]overlay=w:h[v];\
- 先ほどのストリームに
[lowerright]
ストリーム(input3
)を右下に重ねる。これを最終的なストリーム[v]
と定義
- 先ほどのストリームに
-
[a0][a1][a2][a3]amix=inputs=4:duration=longest,loudnorm[a];\
- オーディオストリーム4つをすべてまとめて音量調整し、1つのストリームにする。これを最終的なストリーム
[a]
と定義
- オーディオストリーム4つをすべてまとめて音量調整し、1つのストリームにする。これを最終的なストリーム
-
-b:v 2M -c:v hevc_nvenc \
- 適当な映像エンコード設定
-
-c:a libopus -b:a 32k \
- 適当な音声エンコード設定
-
-map "[v]" -map "[a]" \
- ストリーム
[v]
、[a]
を動画ファイルとして保存
- ストリーム
-
output.mp4
- 出力ファイル名
左右の音量バランス調整
Panningして、左上・左下の動画は左から、右上・右下の動画は右から音が鳴るようにします。
# 1つの動画の画面解像度
cut_w=1920
cut_h=1080
input0='左上の動画ファイルパス.mp4'
input1='右上の動画ファイルパス.mp4'
input2='左下の動画ファイルパス.mp4'
input3='右下の動画ファイルパス.mp4'
# それぞれの動画input0~3の先頭を削除する秒数を設定
trim0=3.000
trim1=2.000
trim2=1.000
trim3=0
# 0.0~1.0 の間で指定。0に近づけば左右の音分離が強くなります
pan_gap=0.3
ffmpeg -i "$input0" -i "$input1" -i "$input2" -i "$input3" \
-filter_complex "\
[0:v] trim=start=${trim0}, setpts=PTS-STARTPTS, scale=${cut_w}x${cut_h} [upperleft];\
[0:a] atrim=start=${trim0},asetpts=PTS-STARTPTS,loudnorm=I=-16:TP=-1.5:LRA=11,pan=stereo|c0=c0|c1=${pan_gap}*c1 [a0];\
[1:v] trim=start=${trim1}, setpts=PTS-STARTPTS, scale=${cut_w}x${cut_h} [upperright];\
[1:a] atrim=start=${trim1},asetpts=PTS-STARTPTS,loudnorm=I=-16:TP=-1.5:LRA=11,pan=stereo|c0=${pan_gap}*c0|c1=c1 [a1];\
[2:v] trim=start=${trim2}, setpts=PTS-STARTPTS, scale=${cut_w}x${cut_h} [lowerleft];\
[2:a] atrim=start=${trim2},asetpts=PTS-STARTPTS,loudnorm=I=-16:TP=-1.5:LRA=11,pan=stereo|c0=c0|c1=${pan_gap}*c1 [a2];\
[3:v] trim=start=${trim3}, setpts=PTS-STARTPTS, scale=${cut_w}x${cut_h} [lowerright];\
[3:a] atrim=start=${trim3},asetpts=PTS-STARTPTS,loudnorm=I=-16:TP=-1.5:LRA=11,pan=stereo|c0=${pan_gap}*c0|c1=c1 [a3];\
[upperleft]pad=2*iw:2*ih[v0];\
[v0][upperright]overlay=w:0[v1];\
[v1][lowerleft]overlay=0:h[v2];\
[v2][lowerright]overlay=w:h[v];\
[a0][a1][a2][a3]amix=inputs=4:duration=longest,loudnorm[a];\
" \
-b:v 2M -c:v hevc_nvenc \
-c:a libopus -b:a 32k \
-map "[v]" -map "[a]" \
output.mp4
前節との違いは、[0:a]
、[1:a]
、[2:a]
、[3:a]
のストリームの個所です。
-
[0:a] ... ,pan=stereo|c0=c0|c1=${pan_gap}*c1 [a0];\
- (左上の動画の音声)左をそのまま、右を
${pan_gap}
倍
- (左上の動画の音声)左をそのまま、右を
-
[1:a] ... ,pan=stereo|c0=${pan_gap}*c0|c1=c1 [a1];\
- (右上の動画の音声)左を
${pan_gap}
倍、右をそのまま
- (右上の動画の音声)左を
-
[2:a] ... ,pan=stereo|c0=c0|c1=${pan_gap}*c1 [a2];\
- (左下の動画の音声)左をそのまま、右を
${pan_gap}
倍
- (左下の動画の音声)左をそのまま、右を
-
[3:a] ... ,pan=stereo|c0=${pan_gap}*c0|c1=c1 [a3];\
- (右下の動画の音声)左を
${pan_gap}
倍、右をそのまま
- (右下の動画の音声)左を