ffmpeg でムービーからオーディオデータを取り出す
今日はムービーからオーディオデータを取り出す方法を模索してみた。
オーディオのコーデックが AAC の場合は次の ffmpeg コマンドで行けた。 まず取り出す際に再エンコードしない方法。
$ ffmpeg -i Movie.mov -vn -acodec copy Music.m4a出力先のファイル名の拡張子で判断しているようで、
Music.m4a
とすると抽出した AAC データを MP4 コンテナに格納してくれるようだ。
Music.aac
とした場合は生の AAC データが抽出されるみたいだけど、
生の AAC ファイルは iTunes が認識してくれなかった。
mp3 を取り出す場合はこんな感じ。 mp3 データを MP4 コンテナ(.m4a)に格納しても、 iTunes が再生してくれないみたいなので、 出力ファイルの拡張子を mp3 にしている。
$ ffmpeg -i Movie.mov -vn -acodec copy Music.mp3
音声データを取り出す際に、 AAC で再エンコードしたい場合は次のようにすればよいみたい。
$ ffmpeg -i Movie.mov -vn -acodec libfaac -ac 2 -ar 44100 -ab 128k Music.m4aここで
-ar
オプションでサンプリングレートを、
-ab
オプションでビットレートを指定している。
複数のムービーをバッチ処理するのに、 次のようなシェルスクリプトを書いてみた。 指定されたムービーのオーディオエンコードを自動判別して m4a、 mp3 ファイルを出力する。 AAC、MP3 以外のコーデックは AAC で再エンコードするようにしてみた。
#!/bin/sh for f in "$@" do codec=`ffmpeg -i "$f" 2>&1 | sed -n 's/^[ \t]*Stream #[0-9]*\.[0-9]*: Audio: \([^,]*\),.*$/\1/p'` case $codec in mp3) ext="mp3";; aac) ext="m4a";; esac basename=`echo $f | sed -e 's/\.[a-z0-9]*$//'` if [ -n "$ext" ] then ffmpeg -y -i "$f" -vn -acodec copy "$basename.$ext" else ffmpeg -y -i "$f" -vn -acodec libfaac -ac 2 -ar 44100 -ab 128k "$basename.m4a" fi done
せっかくなので、 フォルダアクション用 AppleScript も作ってみた。 ffmpeg コマンドのあるパスは ffmpeg_path プロパティで設定している。
property done_foldername : "iTunes Musics" property originals_foldername : "Original Movies" property ffmpeg_path : "/opt/local/bin/ffmpeg" -- the list of file types which will be processed property type_list : {"3gpp"} -- since file types are optional in Mac OS X, -- check the name extension if there is no file type -- NOTE: do not use periods (.) with the items in the name extensions list -- eg: {"txt", "text", "jpg", "jpeg"}, NOT: {".txt", ".text", ".jpg", ".jpeg"} property extension_list : {"mov", "m4v", "mp4", "3gp", "3gpp", "3g2", "3gpp2", "dv", "mpg", "mpeg", "flv", "avi", "wmv"} property acodec_record : {aac:"m4a", mp3:"mp3", _unknown:"m4a"} on adding folder items to this_folder after receiving these_items tell application "Finder" if not (exists folder done_foldername of this_folder) then make new folder at this_folder with properties {name:done_foldername} end if set the results_folder to (folder done_foldername of this_folder) as alias if not (exists folder originals_foldername of this_folder) then make new folder at this_folder with properties {name:originals_foldername} set current view of container window of this_folder to list view end if set the originals_folder to folder originals_foldername of this_folder end tell set processed_number to 0 repeat with this_item in these_items set the item_info to the info for this_item if (alias of the item_info is false and the file type of the item_info is in the type_list) or (the name extension of the item_info is in the extension_list) then try set audio_codec to do shell script ffmpeg_path & " -i " & quoted form of POSIX path of this_item & " 2>&1 | sed -n 's/^[ \\t]*Stream #[0-9]*\\.[0-9]*: Audio: \\([^,]*\\),.*$/\\1/p'" set newmovie_extension to value of (label(audio_codec)) at acodec_record tell application "Finder" set the new_name to my resolve_conflicts(this_item, results_folder, newmovie_extension) end tell process_item(this_item, new_name, results_folder, audio_codec) tell application "Finder" my resolve_conflicts(this_item, originals_folder, "") move this_item to the originals_folder with replacing end tell set processed_number to processed_number + 1 on error error_message number error_number if the error_number is not -128 then tell application "Finder" activate --say "error has occured; " & error_message display dialog error_message buttons {"Cancel"} default button 1 with title "on adding" giving up after 120 end tell end if end try end if end repeat if processed_number > 0 then say "audio extracting has done" end adding folder items to on resolve_conflicts(this_item, target_folder, new_extension) tell application "Finder" set the file_name to the name of this_item set file_extension to the name extension of this_item if the file_extension is "" then set the trimmed_name to the file_name else set the trimmed_name to text 1 thru -((length of file_extension) + 2) of the file_name end if if the new_extension is "" then set target_name to file_name set target_extension to file_extension else set target_extension to new_extension set target_name to (the trimmed_name & "." & target_extension) as string end if if (exists document file target_name of target_folder) then set the name_increment to 1 repeat set the new_name to (the trimmed_name & "." & (name_increment as string) & "." & target_extension) as string if not (exists document file new_name of the target_folder) then -- rename to conflicting file set the name of document file target_name of the target_folder to the new_name exit repeat else set the name_increment to the name_increment + 1 end if end repeat end if end tell return the target_name end resolve_conflicts on label(target_label) return run script "on value at target_record try set the extension to " & target_label & " of target_record on error m number n if n = -1728 then set the extension to _unknown of target_record else display dialog m buttons {\"Cancel\"} default button 1 giving up after 120 set the extension to \"\" end if end try return the extension end value return me" end label -- this sub-routine processes files on process_item(source_file, new_name, results_folder, audio_codec) try -- the target path is the destination folder and the new file name set the target_path to ((results_folder as string) & new_name) as string with timeout of 900 seconds if audio_codec is in {"aac", "mp3"} then do shell script ffmpeg_path & " -y -i " & quoted form of POSIX path of source_file & " -vn -acodec copy " & quoted form of POSIX path of target_path & " 2> /dev/null" else do shell script ffmpeg_path & " -y -i " & quoted form of POSIX path of source_file & " -vn -acodec libfaac -ac 2 -ar 44100 -ab 128k " & quoted form of POSIX path of target_path & " 2> /dev/null" end if end timeout on error error_message tell application "Finder" activate say "error has occured; " & error_message display dialog error_message buttons {"Cancel"} default button 1 with title "process_item" giving up after 120 end tell end try end process_item