動画に音声を後付けする方法|ffmpegで劣化させずに結合

生成AIの動画に別の音声を結合する作業(ffmpeg・音声合成)のイメージ

PR

AIで記事作成を効率化したいなら → 高品質SEO記事生成AIツール【Value AI Writer byGMO】

※本記事は2026年9月に実際に行った作業の記録です。コマンドはmacOS(ffmpeg 8系)で動作確認しています。

こんにちは!Conomacです。

SeaArtなどの生成AIで作った動画に、あとから別で作った音声(VOICEVOXなど)を載せたい——よくある要望ですが、動画編集ソフトを開かずにコマンドだけで完結できます。しかも映像は再エンコードせず、画質を一切落とさずに音声だけ差し替えられます。

実際にこの方法で作ったショート動画がこちらです。

https://www.youtube.com/watch?v=4xr4BLahhzk

この記事でわかること

  • 生成AIの動画(mp4/mov)に、別のWAV音声を載せる手順
  • 音声を置き換える場合と、元の環境音を残して重ねる(ミックス)場合の使い分け
  • 映像を劣化させずに処理できたかを数値で確認する方法
  • 「音量が測れない」「音声が途中で切れる」など、ハマりどころ

前提:まず2つの素材の仕様を確認する

いきなり結合する前に、ffprobeで中身を確認します。ここで映像の解像度・フレームレート・音声のサンプルレート・長さを見ておくと、後段のトラブルが激減します。

ffprobe -v error -show_entries stream=index,codec_name,codec_type,width,height,r_frame_rate,channels,sample_rate,duration -show_entries format=duration -of default=noprint_wrappers=1 video.mov
ffprobe -v error -show_entries stream=codec_name,channels,sample_rate,duration -of default=noprint_wrappers=1 voice.wav

今回の実例では、動画が「720×1244 / 30fps / h264 + aac / 10.07秒」、音声が「モノラル 24kHz / 7.37秒」。動画のほうが長い点がポイントです(後述)。

手順1:音声を「置き換える」(いちばんシンプル)

元動画の音を消して、用意した音声だけにしたい場合はこれだけです。

ffmpeg -i video.mov -i voice.wav \
  -map 0:v:0 -map 1:a:0 \
  -c:v copy -c:a aac -b:a 192k -ar 44100 -ac 2 -movflags +faststart out.mp4
  • -c:v copy が最重要。映像をコピーするので再エンコードなし=画質劣化ゼロ・処理も数秒
  • -map 0:v:0 -map 1:a:0 で「1つ目のファイルの映像」+「2つ目のファイルの音声」を選ぶ
  • 音声は aac 192k / 44.1kHz / ステレオ に整えると、各種プラットフォームで再生トラブルが起きにくい
  • -movflags +faststart を付けると、Web再生時の読み込みがスムーズになる

手順2:元の環境音を残して「重ねる」(ミックス)

生成AIの動画には、環境音やBGMが入っていることがあります。それを薄く残したまま、声を上に載せたい場合はこちら。

ffmpeg -i video.mov -i voice.wav -filter_complex \
  "[0:a]volume=0.6[bg];[1:a]volume=1.6,aresample=44100[vo];[bg][vo]amix=inputs=2:duration=first[out]" \
  -map 0:v:0 -map "[out]" -c:v copy -c:a aac -b:a 192k out.mp4
  • volume=0.6 で元の環境音を控えめに、volume=1.6 で声を持ち上げています(数字は聞きながら調整)
  • amix は入力を合成するので、声が埋もれる場合はここでバランスを取る
  • duration=first は「1つ目の入力の長さに合わせる」の意味。動画側の長さを維持したいときに便利です

検証1:映像が本当に無劣化か確かめる

「-c:v copy したから大丈夫」で終わらせず、元動画と出力のフレームを数値で比較します。Python(MoviePy)で同じ秒のフレームを取り出して差を見るだけです。

from moviepy import VideoFileClip
import numpy as np
A = VideoFileClip("video.mov"); B = VideoFileClip("out.mp4")
for t in [1.0, 5.0, 9.0]:
    d = np.abs(A.get_frame(t).astype(int) - B.get_frame(t).astype(int)).max()
    print(t, "差分:", int(d))

すべて差分: 0なら、映像はビット単位で同一=完全に無劣化です。「なんとなくキレイ」ではなく0で確認するのがおすすめ。

検証2:音量を測る(ハマりどころ付き)

ffmpeg -hide_banner -i out.mp4 -af volumedetect -f null - 2>&1 | grep -E 'mean_volume|max_volume'

注意:-v error を付けると volumedetect の結果が出ません(volumedetectはinfoレベルで出力するため)。最初これで「測れない」とハマりました。-hide_bannerだけにして、2>&1で標準エラーも拾うのが正解です。

今回の実例では、元動画の環境音が mean -37.5dB・声が mean -24.2dB / max -5.7dB でした。数字を見ておくと「声が小さすぎないか」「割れていないか」を客観的に判断できます。

つまずきポイント

  • 音声が動画より短いとき:無音区間ができます(今回は声7.37秒/動画10.07秒)。長さを合わせたいなら -shortest を付けて動画を切るか、後ろに無音を足します。どちらが自然かは用途次第です。
  • サンプルレートが違う:VOICEVOXのWAVは24kHzモノラル。そのまま入れると環境によっては再生が不安定なので、-ar 44100 -ac 2で整えるのが無難です。
  • 動画編集ソフト不要:カット・テロップ・BGM合成までffmpegで完結します。手作業より再現性が高く、スクリプト化すれば量産できます。
  • YouTubeは投稿後にタイトル・カテゴリを変更できない:APIのアップロード用スコープでは videos.update が使えないためです。投稿前に決め切りましょう。

まとめ

  • 生成AI動画への音声の後載せは、ffmpegの2行で完結する
  • -c:v copy で映像は無劣化。フレーム差分0で検証できる
  • 「置き換え」と「ミックス」は-filter_complexの有無で使い分け
  • 音量計測は-v errorを付けない(volumedetectが消える)

動画の素材づくりから音声の合成、結合、投稿まで、コマンドでつながると「1本作る」のハードルがぐっと下がります。ぜひ試してみてください。

PR・広告

動画の音声を整えるなら

ナレーションや音声の収録に、1本あると音が変わります。

関連記事

AIショート動画に喋らせてみた|VOICEVOX導入でkokoro版と聴き比べ+実測コスト全公開

ブログ画像3枚からYouTubeショート動画を全自動で作る方法|BGM生成×テロップ×YouTube API連携の全手順

今回の動画の元記事(メインサイト): 【完全保存版】AI画像生成の始め方 完全ガイド