FFmpegで動画の音声だけを取り出す方法と消す方法

​​FFmpeg​AAC,ffprobe,MP3,動画編集

FFmpeg で動画から音声だけを取り出すには -vn(映像を入れない)を、音声を消して映像だけにするには -an(音声を入れない)を付けます。残したほうを -c:a copy や -c:v copy でコピーすると、再エンコードせずに一瞬で終わりました。コピーしたデータは、元の動画とまったく同じでした。動画の BGM や話し声を m4a・MP3・WAV のファイルにしたいときや、SNS に載せる前に動画をミュート(無音)にしたいときに使える方法です。

補足

検証環境は Ubuntu 24.04、FFmpeg 6.1.1(Ubuntu のパッケージ)です。検証に使った動画は、FFmpeg のテスト用の映像(testsrc2)と一定の高さの音(sine)から作った30秒の MP4(H.264 + AAC)で、カメラやマイクで撮ったものではありません。FFmpeg 7 以降、MP4 以外の入力(MKV や MOV など)、AAC 以外の音声、動画プレーヤーでの再生は試していません。

元の動画から、-vn で音声だけのファイルを、-an で映像だけのファイルを作る様子を示した図
-vn と -an で、出力に入れるストリームを選ぶ

動画の中では、映像と音声が別々のストリームになっている

MP4 などの動画ファイルの中では、映像と音声が別々のデータ(ストリーム)として入っています。検証に使った動画を ffprobe で調べると、映像(H.264)と音声(AAC)の2本のストリームがありました。

text
$ ffprobe -v error -show_entries stream=index,codec_type,codec_name,bit_rate,duration:stream_tags=language:format=duration,size,bit_rate -of compact=p=0 in.mp4
index=0|codec_name=h264|codec_type=video|duration=30.000000|bit_rate=736573|tag:language=und
index=1|codec_name=aac|codec_type=audio|duration=30.000000|bit_rate=128019|tag:language=jpn
duration=30.000000|size=3276429|bit_rate=873714

-vn と -an は、このうち映像または音声のストリームを出力に入れないようにするオプションです(公式ドキュメントの元になっている文書にある、ストリームの選び方の説明)。

-c copy は「ストリームコピー」と呼ばれ、デコードとエンコードをせず、圧縮されたデータを入れ物から取り出して別の入れ物に入れ直すだけです。公式ドキュメントのストリームコピーの説明にも、とても速く、画質や音質が落ちないと書かれています。

音声だけを取り出す

AAC のまま m4a にする(再エンコードなし)

元の動画の音声が AAC なら、m4a の入れ物にそのままコピーできます。

bash
ffmpeg -i in.mp4 -vn -c:a copy audio.m4a

この記事のコマンドは、実際には -hide_banner を付けて実行しています。エラーの例以外では -loglevel error も、ファイルを書き出すコマンドには -y も付けています。かかった時間は 0.069秒(time コマンドの real の値)でした。できたファイルは AAC の音声1本だけで、長さとビットレートは元の動画の音声と同じでした。

text
$ ffprobe -v error -show_entries stream=index,codec_type,codec_name,bit_rate,duration:format=format_name,duration,size -of compact=p=0 audio.m4a
index=0|codec_name=aac|codec_type=audio|duration=30.000000|bit_rate=128019
format_name=mov,mp4,m4a,3gp,3g2,mj2|duration=30.000000|size=486852

中身が本当に同じかは、FFmpeg の streamhash という出力形式で、音声のデータの MD5 を出して比べられます。元の動画と取り出した m4a で、同じ値になりました。

text
$ ffmpeg -i in.mp4 -map 0:a -c copy -f streamhash -hash md5 -
0,a,MD5=a96cc02d36cfe57aa389462704c9388b
$ ffmpeg -i audio.m4a -map 0:a -c copy -f streamhash -hash md5 -
0,a,MD5=a96cc02d36cfe57aa389462704c9388b

出力ファイル名を .m4a にしても、-vn がないと映像が入る

-vn を付けずに、出力ファイル名だけを .m4a にすると、映像も入ったファイルができました。エラーも出ませんでした。出力ファイル名の拡張子だけでは、映像は除かれないということです。

text
$ ffmpeg -i in.mp4 -c:a copy audio-novn.m4a; echo exit=$?
exit=0
$ ffprobe -v error -show_entries stream=index,codec_type,codec_name -of compact=p=0 audio-novn.m4a
index=0|codec_name=h264|codec_type=video
index=1|codec_name=aac|codec_type=audio

音声だけのファイルを作るときは、出力の形式に関係なく -vn を付けておくのが確実です。

MP3 や WAV にする(再エンコードあり)

AAC の音声を .mp3 のファイルに -c:a copy でコピーしようとすると、エラーで止まりました。MP3 のファイルには MP3 の音声しか入れられないからです(FFmpeg の MP3 の書き出しの処理で、MP3 以外の音声を受け付けていません)。

text
$ ffmpeg -i in.mp4 -vn -c:a copy audio-copy.mp3; echo exit=$?
(入力の情報は省略)
[mp3 @ 0x55ad458e8740] Invalid audio stream. Exactly one MP3 audio stream is required.
[out#0/mp3 @ 0x55ad458d7400] Could not write header (incorrect codec parameters ?): Invalid argument
Error opening output file audio-copy.mp3.
Error opening output files: Invalid argument
exit=234

このとき、0バイトの audio-copy.mp3 が残っていました。中身のないファイルなので、不要なら消してください。

MP3 にするには、libmp3lame で再エンコードします。-q:a は品質を固定した可変ビットレート(VBR)の指定で(公式ドキュメントの libmp3lame の説明)、検証では 2 にしました。

bash
ffmpeg -i in.mp4 -vn -c:a libmp3lame -q:a 2 audio.mp3

WAV にするなら、コーデックを指定しなくても、非圧縮(pcm_s16le)で書き出されました。

bash
ffmpeg -i in.mp4 -vn audio.wav

それぞれの結果は次のとおりです。

出力 方法 時間(real) サイズ 音声
audio.m4a コピー 0.069秒 486,852 バイト AAC、128kb/s、30.000秒
audio.mp3 変換(MP3 にエンコード) 0.291秒 144,796 バイト MP3、38kb/s(VBR)、30.048秒
audio.wav 変換(非圧縮で書き出し) 0.155秒 5,763,150 バイト PCM、1,536kb/s、30.016秒

MP3 と WAV は、長さが元の30秒よりわずかに長くなりました。MP3 のビットレートは VBR なので音の中身で変わります。検証の音声は一定の高さの音なので、この 38kb/s という数字は、音楽や話し声のファイルの目安にはなりません。

音声を消して映像だけにする

映像は -c:v copy でコピーし、-an で音声を入れないようにします。

bash
ffmpeg -i in.mp4 -an -c:v copy video-only.mp4

かかった時間は 0.060秒でした。できたファイルには映像のストリームだけがあり、900フレーム・30秒は元の動画の映像と同じです。映像のデータの MD5 も、元の動画と同じでした。

text
$ ffprobe -v error -show_entries stream=index,codec_type,codec_name,nb_frames,duration:format=duration,size -of compact=p=0 video-only.mp4
index=0|codec_name=h264|codec_type=video|duration=30.000000|nb_frames=900
duration=30.000000|size=2773219
$ ffmpeg -i in.mp4 -map 0:v -c copy -f streamhash -hash md5 -
0,v,MD5=211df759369178ec159cabe3fe72d36a
$ ffmpeg -i video-only.mp4 -map 0:v -c copy -f streamhash -hash md5 -
0,v,MD5=211df759369178ec159cabe3fe72d36a

-c:v copy を忘れると、映像が作り直される

-an だけを付けて -c:v copy を書かないと、映像がデコードされてから H.264(libx264)でエンコードし直されました。時間は 0.060秒から 2.323秒に増え、映像の MD5 も元と違う値(16f56445496a6500fe6589331b38fc2c)になりました。

方法 時間(real) サイズ 映像の MD5
-an -c:v copy 0.060秒 2,773,219 バイト 元と同じ
-an だけ 2.323秒 2,649,684 バイト 元と違う

音声が2本ある動画で、選んで取り出す・消す

日本語と英語のように、音声が2本入った動画もあります。日本語(jpn、440Hz の音)と英語(eng、880Hz の音)の2本の音声を入れた動画で試しました。

text
$ ffprobe -v error -show_entries stream=index,codec_type,codec_name:stream_tags=language -of compact=p=0 in-2audio.mp4
index=0|codec_name=h264|codec_type=video|tag:language=und
index=1|codec_name=aac|codec_type=audio|tag:language=jpn
index=2|codec_name=aac|codec_type=audio|tag:language=eng

-vn -c:a copy だけでは、1本目(jpn)しか出力に入りませんでした。公式ドキュメントの自動選択の説明によると、-map を書かないとき、音声はチャンネル数がいちばん多い1本だけが選ばれ、同じなら番号の小さいほうになります。検証の2本はどちらもステレオなので、1本目が選ばれました。

ほかの音声を選ぶには、-map オプションで指定します。0:a:1 は「1つ目の入力ファイルの、音声の2本目(0から数える)」という意味です。-map を書くと、映像も自動では選ばれなくなるので、-vn は要りません。

bash
# 2本目の音声だけを取り出す
ffmpeg -i in-2audio.mp4 -map 0:a:1 -c:a copy second.m4a
# 音声を2本とも取り出す
ffmpeg -i in-2audio.mp4 -map 0:a -c:a copy both.m4a
text
$ ffprobe -v error -show_entries stream=index,codec_type:stream_tags=language -of compact=p=0 second.m4a
index=0|codec_type=audio|tag:language=eng
$ ffprobe -v error -show_entries stream=index,codec_type:stream_tags=language -of compact=p=0 both.m4a
index=0|codec_type=audio|tag:language=jpn
index=1|codec_type=audio|tag:language=eng

音声を消すほうは、-an -c:v copy で2本ともなくなり、映像だけが残りました。1本だけを消して、ほかを残したいときは、-map 0 ですべてを選んでから、-map -0:a:0 のように - を付けて除きます。

bash
ffmpeg -i in-2audio.mp4 -map 0 -map -0:a:0 -c copy drop-first.mp4
text
$ ffprobe -v error -show_entries stream=index,codec_type:stream_tags=language -of compact=p=0 drop-first.mp4
index=0|codec_type=video|tag:language=und
index=1|codec_type=audio|tag:language=eng

1本目(jpn)が消え、映像と2本目(eng)が残りました。

​Posted by 86