元のファイルは問題なく再生できていたのに、FFmpegで変換した途端に音と映像がズレてしまった——これはFFmpegで最も分かりにくいトラブルの一つです。変換自体は成功したように見え、エラーも出ず、ファイルも再生でき、映像もきれいなのに、音だけが合わなくなる。原因はほぼ常に、変換が「そのまま引き継いだもの」または「作り直さなかったもの」にあります。壊れたタイムスタンプをそっくりコピーしてしまった、ソースが可変フレームレート(VFR)だった、リマックス時に2つのクロックを整合させられなかった、のいずれかです。本記事では原因を1つずつ切り分け、原因ごとに実行可能な解決コマンドを示します。

動作確認: FFmpeg 8.1


この記事でわかること

  • ソースは問題なかったのに「変換後にだけ」音ズレが起きる理由
  • ストリームコピー(-c copy)が壊れた・可変なタイムスタンプをそのまま引き継ぐ仕組み
  • 可変フレームレート(VFR)ソースがコピー出力で音ズレを起こす理由
  • 4つの実行可能な解決法: 再エンコード、音声タイミングの補正、タイムスタンプの再生成、固定フレームレート化
  • 自分の症状に合った解決法の選び方

この問題は、最初から存在していた「一定のオフセット」(音声が常に200ミリ秒遅れている等)とは別物です。固定の進み・遅れには 音声遅延を手動で直す方法 を参照してください。同期オプション全般のツールボックスは 音声同期を直す方法 にあります。本記事はあくまで「変換後に発生した音ズレ」に特化した内容です。


原因①: ストリームコピーが壊れたタイムスタンプを引き継いだ

-c copy(ストリームコピー)が速くて無劣化なのは、何もデコードせず、パケットを一方のコンテナから取り出してもう一方へ入れるだけだからです。落とし穴は、プレゼンテーションタイムスタンプ(PTS) もそのままの状態でコピーしてしまう点です。ソースのタイムスタンプが不規則・欠落・非単調だった場合、その問題はそっくり出力へ持ち込まれ、新しいコンテナが元とは違う解釈をすることがあります。

これが「以前は問題なく再生できたのに -c copy で音ズレした」という典型的なシナリオです。ソースを開いていたプレイヤーが乱れたタイムスタンプに寛容だっただけで、新しいコンテナ+より厳密なプレイヤーではそうはいきません。

最も確実な解決策は 再エンコード です。FFmpegに強制的にデコードさせ、両ストリームをきれいなタイムライン上に並べ直します。

ffmpeg -i input.mp4 -c:v libx264 -crf 20 -c:a aac output.mp4
  • -c:v libx264 -crf 20 — 映像を再エンコード(CRF 20 は見た目ほぼ無劣化)
  • -c:a aac — 音声を再エンコード
  • -c copy を使わないため、FFmpegがデコード済みフレームからタイムラインを作り直す

再エンコードは最も重い選択肢ですが、ソース本来のタイムスタンプへの依存を完全に取り除けるため、しつこいケースを直せる可能性が最も高い方法です。


原因②: 全再エンコードせずに音声タイミングを補正する

映像自体は問題なく、音声タイミングだけがおかしい場合、映像を再エンコードする必要はありません。aresample フィルタに async=1 を付けると、FFmpegが音声を(サンプルの挿入・削除で)補填・切り詰めし、タイムスタンプが映像クロックに揃い続けるようにします。(async=1 は補填・切り詰めのみを有効にします。実際に音声を伸ばす・縮めるには1より大きい値を使います。)

ffmpeg -i input.mp4 -af aresample=async=1 -c:v copy output.mp4
  • -af aresample=async=1 — 音声をリサンプルし、タイムスタンプに合わせて補填・切り詰める
  • -c:v copy — 映像はそのままコピー(高速・無劣化)
  • フィルタがサンプルを書き換えるため、音声は必然的に再エンコードされる

これなら(しばしば巨大な)映像ストリームをコピーしたまま、音声だけを再処理するので、全再エンコードよりずっと高速です。映像は正しく見えて音だけがズレている場合の、最初の一手として有効です。


原因③: +genpts で欠落したタイムスタンプを再生成する

実際の問題が、ソースの片方のストリームに 使えるタイムスタンプが全く無い、またはタイムスタンプが非単調である、というケースもあります。その場合、それをそのままコピーする(-c copy)と欠落も伝播するだけです。+genpts フラグは、欠落部分の プレゼンテーションタイムスタンプを生成 するようFFmpegに指示し、再エンコードなしで整合を修復できることがよくあります。

ffmpeg -fflags +genpts -i input.mp4 -c copy output.mp4
  • -fflags +genpts — デマックス時に欠落したPTS値を生成(-i の前に置く必要あり)
  • -c copy — 依然として再エンコードしないので、高速・無劣化のまま

+genpts は入力/デマックス段階で適用されるため、-i input.mp4 に置く必要があります。これは最も軽量な解決策です。これで直れば、両ストリームをビット単位で同一に保ったまま、タイミングのメタデータだけが修正されます。


原因④: ソースが可変フレームレートだった(CFR化する)

「同期は問題なかったのに変換後に崩れた」の最も多い根本原因が、可変フレームレート(VFR) のソースです。画面録画ソフト、スマホのカメラ、ゲームキャプチャツールは、しばしばVFRで記録します。フレーム間の間隔がクリップ全体を通して変化するのです。一方、音声は一定のサンプルクロックで進みます。VFRの映像を、新しいプレイヤーが固定フレームレートとして扱うコンテナへコピーすると、2つのクロックが少しずつ乖離し、クリップが進むほど音声がさらにズレていきます。

解決策は、再エンコードしながら映像を 固定フレームレート(CFR) に変換し、すべてのフレームを音声クロックと一致する予測可能な間隔に並べることです。

ffmpeg -i input.mp4 -fps_mode cfr -r 30 -c:v libx264 -c:a aac output.mp4
  • -fps_mode cfr — 出力を固定フレームレートに強制(FFmpeg 8.x のオプション)
  • -r 30 — 目標を毎秒30フレームに設定(ソースの公称レートに合わせる)
  • -c:v libx264 -c:a aac — きれいなCFRタイムライン上に両ストリームを再エンコード

補足: FFmpeg 8.x ではオプションは -fps_mode cfr です。古い -vsync cfr も依然動作しますが非推奨なので、-fps_mode を優先してください。

問題が明確にVFRなら、これが正しい解決策であり、テーマ単体で理解しておく価値があります。専用ガイド 可変フレームレートを固定に変換する を参照してください。音声が一様にズレているのではなく だんだんズレていく(最初は合っているのに終わりに近づくほどひどくなる)場合は、音ズレが徐々に進行する問題を直す で扱うドリフトのパターンです。


どの解決法を使うべきか

症状考えられる原因推奨する解決法
-c copy リマックス直後にズレた壊れたタイムスタンプの引き継ぎ再エンコード: -c:v libx264 -crf 20 -c:a aac
映像は正常、音声だけズレた音声タイミング-af aresample=async=1 -c:v copy
-c copy 出力が合わず、ソースのタイムスタンプが変PTSの欠落・非単調-fflags +genpts -i ... -c copy
時間が経つほど悪化、ソースが画面/スマホ録画VFRソース-fps_mode cfr -r 30(再エンコード)

症状に合う最も軽い解決法から試してください。+genpts で解決しなければ aresample=async=1 に進み、ソースがVFRならCFR強制に直行します。


よくある質問

変換前は同期していたのはなぜですか?

ストリームコピー(-c copy)がソースのタイムスタンプをそのまま引き継ぎ、新しいコンテナ+プレイヤーが元とは違う解釈をするからです。ソースが「完璧」だったのではなく、そのプレイヤーが乱れたタイムスタンプに寛容だっただけです。再エンコードするか -fflags +genpts でタイムスタンプを再生成すれば、その依存を取り除けます。

これを直すには再エンコードが必須ですか?

常にではありません。まず -fflags +genpts -i input.mp4 -c copy を試してください。再エンコードせずに欠落タイムスタンプを生成します。音声だけがズレているなら -af aresample=async=1 -c:v copy で音声だけを再エンコードします。全再エンコードはしつこいケースの最終手段です。

一定の音声遅延との違いは何ですか?

一定の遅延とは、音声が最初から固定量だけ早い・遅い状態で、1回のオフセットで補正します(音声遅延を手動で直す方法 を参照)。本記事の問題は「変換後に発生した」音ズレで、通常は引き継がれたタイムスタンプやVFRソースが原因であり、一定のオフセットにとどまらず時間とともに悪化することが多いです。

ソースがVFRかどうかはどう判断しますか?

VFRファイルは ffprobe で調べると r_frame_rateavg_frame_rate が異なる値を示します。検出と変換の完全な手順は 可変フレームレートを固定に変換する にあります。

-vsync cfr-fps_mode cfr と同じですか?

機能的には同じですが、-vsync は FFmpeg 8.x で非推奨です。今後は -fps_mode cfr を使ってください。古いフラグも今のところ動きますが、新しいコマンドでは -fps_mode を使うべきです。


関連記事


Tested with FFmpeg 8.1 — verified with our command-check script
一次ソース: ffmpeg.org/ffmpeg.html / ffmpeg.org/ffmpeg-filters.html#aresample