Hatena::ブログ(Diary)

tsntsumi’s NOOTO RSSフィード Twitter

2010-01-25 Mon

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 オプションビットレートを指定している。

複数のムービーをバッチ処理するのに、 次のようなシェルスクリプトを書いてみた。 指定されたムービーのオーディオエンコードを自動判別して m4amp3 ファイルを出力する。 AACMP3 以外のコーデック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

Today's Snack

f:id:tsntsumi:20100121154735j:image:w120

f:id:tsntsumi:20100125135930j:image:w160

白いたいやきアイス

近所のスーパーで売っていた白いたいやきアイスというのがおいしそうだったので買ってみた。 中身はミルクアイスと北海道産小豆のこしあん。 餡がとっても甘くて、 というより甘すぎて、 食べた後いそいでウーロン茶で口をすすいだほど。