FFmpegで動画の一部を無音にするときは音声を削除せずに無音データで埋めないとダメ

FFmpegに限らずですが、動画の一部を無音にするとき”音声データの削除”と”無音データに置き換え”の区別がついていないと爆死する。

作業手順

  1. 動画を切り分ける(音声を抜く部分、その前後、の3つに)
  2. 音声を無音に変換する
  3. 1で分けた動画を結合する

音を消すだけじゃダメ

無音音声の動画と音声データがない動画は別のものです。

figure1

音声データがない動画を音声データのある動画と結合した場合、図のように部分的に音声データが欠落している動画となるのですが、 プレーヤーが上手いこと補ったりスルーしてくれるわけでもなく、再生時に不具合となります。

なので、代わりの音声データ(無音)をきちんと入れてあげましょう、という話。

以下、正しい作業手順を貼っておきます

具体的な手順

1. 動画を切り分ける

FFmpegで秒数を指定して動画を切り出すワンライナー

上記は切り出すコマンドなので、3回叩きます。切り分けるコマンドもあるのかな?

50秒-60秒を無音にしたいのであれば

ffmpeg -i src.mp4 -t 50 before.mp4
ffmpeg -ss 50 -i src.mp4 -t 10 target.mp4
ffmpeg -ss 60 -i src.mp4 after.mp4

ですね。 -c copy オプションは速いですが時間がズレるので、つけずにトランスコードしたほうが良いかと思います。

2. 音声を無音に変換する

ffmpeg -i target.mp4 -f lavfi -i aevalsrc=0 -c:v copy -map 0:0 -map 1:0 -shortest -ac 2 -strict -2 silence.mp4

軽く解説すると、ffmpegは -i オプションで指定されるデータ元を0からの連番で数えているので

  • 0番目のデータ
-i target.mp4
  • 1番目のデータ
-f lavfi -i aevalsrc=0 

となります。この1番目のデータはFFmpegのフィルタで無音データを生成しています。

出力部ですが、

-map [n番目の入力データの]:[n番目のストリーム]

という書式です。なので

-map 0:0 -map 1:0

0番目の入力データの0番目のストリーム1番目の入力データの0番目のストリーム を使うという意味になります。

他のオプションは

  • -c:v copy : 映像データをトランスコードせずにそのまま使う
  • -shortest : 入力データのうち最も短いものに長さを合わせる。今回は1番目の入力がフィルタで無限なので、つけないと終わらない
  • -ac 2 : 1 はモノラル、 2 はステレオ。元動画に合わせるといいかと
  • -strict -2 : 音声コーデックがaacの場合に必要なもの。今回は明示的に -c:a でコーデックを指定していないが、aacなので。

です。

3. 動画を結合する

FFmpegでMP4を結合(concat)するワンライナー

MP4BoxでMP4を結合(concat)するワンライナー

らへんを参考にして結合。

ffmpeg -i "concat:before.mp4|silence.mp4|after.mp4" -c copy dst.mp4

以上。

動画のfpsが途中で変わっているとか、音声の周波数が〜とか、細かい条件がなければこんな感じで5コマンドくらいですね。

無音ではなくピー音で置き換える場合は工程2の入力データをピー音に差し替えてあげてください。拾ってきてもいいし、 aevalsrc

aevalsrc="sin(880*2*PI*t)"

のように指定して音声を作ってあげてもいいかと。 880 が周波数なので大きくすれば高音に、小さくすれば低音になります。

Share Comments
comments powered by Disqus