変換・録画・配信のあとに起きる音ズレ(口の動きと音が合わない、音が 1 秒遅れて聞こえるなど)は、FFmpeg で修正できます。ズレの方向(音が遅い/早い)を確かめてオプションを選べば、再エンコードなしで直せる場合もあります。
ズレの方向を確認する
修正方法を選ぶ前に、どちらの方向にズレているかを確認します。
| 状態 | 意味 | 修正方針 |
|---|---|---|
| 音声が映像より遅い | 音が後から聞こえる(拍手→音) | 音声を前にずらすか、映像を遅らせる |
| 音声が映像より早い | 音が先に聞こえる(音→拍手) | 音声を後ろにずらす |
ffprobe で開始時刻を確認する
# 映像・音声ストリームの開始タイムスタンプを確認
ffprobe -v error -show_entries stream=codec_type,start_time \
-of default=noprint_wrappers=1 input.mp4
出力例:
codec_type=video
start_time=0.000000
codec_type=audio
start_time=1.536000
start_time は、ファイルの中で各ストリームが始まる時刻です。上の例では、音声が映像の 1.536秒後から始まります。ただし、これがそのまま音ズレの量とは限りません。録画そのものにズレがある場合は start_time が同じになるので、再生して確かめてください。
コマンド例
1. -itsoffset で映像を遅らせる(音声が遅い場合・再エンコードなし)
同じファイルを2回入力し、映像はオフセットを付けた2番目の入力から、音声は1番目の入力から取ります。映像を遅らせると、遅れていた音声と揃います。
# 音声が映像より 1.5秒 遅い場合に修正
ffmpeg -i input.mp4 -itsoffset 1.5 -i input.mp4 \
-map 1:v -map 0:a -c copy output.mp4
-itsoffset 1.5— 直後の-i(2番目の入力)のタイムスタンプを 1.5秒遅らせる-map 1:v— 映像は2番目の入力(1.5秒遅らせたもの)から-map 0:a— 音声は1番目の入力(そのまま)から-c copy— 再エンコードなし(高速・無劣化)
2. -itsoffset で音声を遅らせる(音声が早い場合)
# 音声が映像より 1.0秒 早い場合に修正
ffmpeg -i input.mp4 -itsoffset 1.0 -i input.mp4 \
-map 0:v -map 1:a -c copy output.mp4
- 音声を取る2番目の入力に
-itsoffsetを付けて、音声を 1.0秒遅らせる
3. adelay フィルタで音声を遅らせる(ミリ秒指定)
# 音声を 1500ms(1.5秒)遅らせる(ステレオ)
ffmpeg -i input.mp4 -af "adelay=1500|1500" -c:v copy output.mp4
adelay=1500|1500— 左チャンネル 1500ms、右チャンネル 1500ms 遅延|でチャンネルごとに指定(ステレオは2値が必要)- このフィルタは音声を遅らせるのみ(前にずらせない)
音ズレは冒頭・中間・最後で確認してください。全編でほぼ一定ならオフセットで直します。後半ほど増えるなら、フレームレートやタイムスタンプの問題を切り分けます。
4. -async で音声タイムスタンプの隙間を埋める
# 音声タイムスタンプの隙間を無音で埋める
ffmpeg -i input.mp4 -async 1 -c:v copy output.mp4
-async 1— 音声自身のタイムスタンプの隙間を無音で埋め、重なりを切り詰める。映像とは比べないので、映像に合わせて音声を動かすものではない。音程も変わらない- 0.1秒より短い隙間はそのまま残る
- FFmpegが途中で音声を変換するとき(PCMからAACなど)だけ効く。AACからAACへの変換では何も変わらない(エラー5を参照)
5. ズレを修正しながら再エンコード
# 1.5秒の音ズレ修正(音声が遅い場合)+ H.264 再エンコード
ffmpeg -i input.mp4 -itsoffset 1.5 -i input.mp4 \
-map 1:v -map 0:a \
-c:v libx264 -crf 23 -c:a aac output.mp4
修正手法 比較表
| 手法 | 再エンコード | 対応するズレ | 精度 |
|---|---|---|---|
-itsoffset + -c copy |
不要 | 映像・音声どちらも | 高(タイムスタンプ操作) |
adelay フィルタ |
必要(音声のみ) | 音声を遅らせる場合のみ | 高(ミリ秒単位) |
-async 1 |
必要(音声のみ) | 音声タイムスタンプの隙間 | 粗い(0.1秒を超える隙間) |
aresample フィルタ |
必要(音声のみ) | 音声のタイムスタンプの欠け(async を1より大きくすると伸縮も) |
サンプル単位 |
使い分け:
- 再エンコードを避けたい →
-itsoffset+-c copy - ズレ量が既知の固定値 →
-itsoffsetまたはadelay - 音声タイムスタンプの隙間 →
-af aresample=async=1
オプション詳解
| オプション/フィルタ | 意味 | 推奨値 |
|---|---|---|
-itsoffset N |
直後の -i のタイムスタンプをN秒遅らせる |
ズレ量(秒) |
-map 0:a |
0番目の入力から音声ストリームを選択 | itsoffset と組み合わせ |
-map 1:v |
1番目の入力から映像ストリームを選択 | itsoffset と組み合わせ |
-af adelay=N|N |
音声チャンネルをNミリ秒遅らせる | ズレ量×1000(ms) |
-async N |
音声を自身のタイムスタンプに合わせて補填・切り詰め(音声を変換するときのみ) | 1 |
-c copy |
再エンコードなしでコピー | itsoffset 使用時 |
トラブルシューティング
エラー1: -c copy と adelay を一緒に使うとエラーで止まる
原因: adelay はフィルタなので再エンコードが必要。-c copy と一緒に使うと Filtering and streamcopy cannot be used together. と表示されて止まる
解決策: 音声コーデックを再エンコードするか、-itsoffset を代わりに使う:
# adelay を使う場合は音声を再エンコード
ffmpeg -i input.mp4 -af "adelay=1500|1500" -c:v copy -c:a aac output.mp4
エラー2: -itsoffset を付けても映像・音声がズレたまま
原因: -itsoffset の直後に -i がない、または -map の指定が間違っている
解決策: コマンド構造を確認する:
# 正しい順序(音声が遅い場合)
ffmpeg -i input.mp4 -itsoffset 1.5 -i input.mp4 \
-map 1:v -map 0:a -c copy output.mp4
# -itsoffset は直後の -i(ここでは 2 番目の入力 = 1:v)だけに効く
エラー3: 修正後もズレが残る
原因: ズレ量の見積もりが不正確
解決策: ffprobe で開始時刻を確認したうえで、映像と音が対応する場面を再生してズレ量を確かめる。録画そのもののズレは start_time には表れない:
ffprobe -v error -show_entries stream=codec_type,start_time \
-of default=noprint_wrappers=1 input.mp4
エラー4: 修正後に音声が途切れる・無音区間ができる
原因: ずらすと、ずらした量と同じ長さの無音や映像の無い区間が、ずらしたストリームの先頭か末尾にできる(ズレの大きさに関係なく起きる)
解決策: 大きなズレはまずソースファイルの問題(録画設定など)を確認。先頭の区間が不要なら、修正後のファイルから切り取る:
# 修正後のファイルの先頭 1.5秒を切り取る
ffmpeg -ss 1.5 -i output.mp4 -c:v libx264 -c:a aac trimmed.mp4
エラー5: -async を付けても何も変わらない
原因: -async は、FFmpegが音声を変換するために自動で入れるリサンプラーにだけ渡される。AACからAACへの変換ではリサンプラーが入らないので、音声は再エンコードされるだけ
解決策: 常に働く aresample フィルタを使う:
ffmpeg -i input.mp4 -af aresample=async=1:min_hard_comp=0.1 -c:v copy output.mp4
FAQ
Q1. ズレ量がわからない場合はどう測定しますか?
A. 動画プレイヤーで再生しながら、目と耳で確認します。音と映像が一致する拍手や打撃音などがある場面を探すと測定しやすいです。ffprobe の start_time は各ストリームが始まる時刻を示すだけで、録画そのもののズレは表れません。
Q2. -itsoffset の値はどの単位ですか?
A. 秒単位です。1.5 = 1.5秒、0.5 = 500ms です。adelay はミリ秒単位です(1500 = 1.5秒)。
Q3. 再エンコードなしで音ズレを修正できますか?
A. -itsoffset + -c copy の組み合わせで可能です。タイムスタンプのみを変更するため、映像・音声の品質は変わりません。
Q4. ズレが 0.5秒未満の微小な場合は?
A. 大きなズレと同じように、測ったズレ量だけ -itsoffset か adelay でずらします。-async 1 や aresample=async=1 は音声自身のタイムスタンプの隙間を埋めるだけで、映像に合わせて音声を動かすものではありません。
Q5. adelay でモノラル音声を遅らせる場合は?
# モノラル(チャンネル1つ)の場合
ffmpeg -i input.mp4 -af "adelay=1500" -c:v copy output.mp4
モノラルは値を1つだけ指定します(| 区切り不要)。