Pythonでffmpegを実行するプログラムを作成

Pythonでファイルを渡し、ffmpegを実行するプログラムを作った。
ソース:myFFmpeg.py

#! /usr/bin/python
#coding:utf-8

import sys,os
import command_generate
from collections import OrderedDict

# main処理
def main():
    # コマンド引数と引数の個数を取得
    argv = sys.argv
    argc = len(argv)
     
    # 引数の個数が2個以下(プログラム名を含む)ならUsageを出力して終了
    if (argc < 2):
        print "Usage: # %s inputfile" % argv[0]
        quit()
     
    for inputFile in argv[1:]:
        ffmpeg_convert(inputFile)

# ffmpeg変換処理
def ffmpeg_convert(inputFile):
    # 入力ファイルを取得し、basename、ファイル名を取得し、出力ファイル名を作成
    inputBaseName = os.path.basename(inputFile)
    fileName = inputBaseName.split(".")[0]
    outputBaseName = fileName + ".mp4"
    outputFile = "/var/www/epgrec/video/mp4/" + outputBaseName

    # ffmpegの2パスログファイル名を作成
    ffmpegPassLogFile = "/tmp/pass2_" + fileName + ".log"
    ffmpegLogFile = "/var/log/ffmpeg/" + fileName + ".log"
    # ffmpegのpreset位置
    ffmpegPresetFile = "/usr/local/share/ffmpeg/libx264-hq-ts.ffpreset"

    # ファイル名をダブルクォーテーションでくくる
    inputFile = '"' + inputFile + '"'
    outputFile = '"' + outputFile + '"'
    ffmpegPassLogFile = '"' + ffmpegPassLogFile + '"'
    ffmpegLogFile = '"' + ffmpegLogFile + '"'
    ffmpegPresetFile = '"' + ffmpegPresetFile + '"'

    # 1passか2passを指定
    ffmpegPass = 1

    # FFmpeg
    FFMPEG = "ffmpeg"

    # 1passのオプション作成
    ffmpegArgs = OrderedDict([
        ("-y",""),
        ("-i",inputFile),
        ("-threads","2"),
        ("-cmp","chroma"),
        ("-flags","+ilme+ildct"),
        ("-deinterlace",""),
        ("-top","-1"),
        ("-fpre",ffmpegPresetFile),
        ("-vcodec","libx264"),
        ("-b:v","1280k"),
        ("-s","hd720"),
        ("-pass",str(ffmpegPass)),
        ("-passlogfile",ffmpegPassLogFile),
        ("-f","mp4"),
        ("-acodec","libfaac"),
        ("-ab","128k"),
        ("-ar","48000"),
        # 他の箇所は、("opt","value")となっているが、↓以降は、意味が異なる。
        (outputFile,""),        # ("value","")
        ("2>>",ffmpegLogFile),  # ("リダイレクト",ファイル)
        ])
    command1 = command_generate.command_generate(FFMPEG,ffmpegArgs)

    # 2passのエンコードオプション作成
    ffmpegPass = 2
    ffmpegArgs["-pass"] = str(ffmpegPass)

    command2 = command_generate.command_generate(FFMPEG,ffmpegArgs)

    # パスログを消す
    front = ffmpegPassLogFile[:-1]
    rear = ffmpegPassLogFile[-1:]
    repi = "*"

    ffmpegPassLogFile = front + repi + rear

    ffmpegArgs = OrderedDict([
            ("-f",ffmpegPassLogFile)
            ])
    command3 = command_generate.command_generate("rm",ffmpegArgs)

    # ffmpeg実行
    os.system(command1)
    os.system(command2)
    os.system(command3)

#----main()----
main()

command_generate.py

#! /usr/bin/python
#coding:utf-8

def command_generate(program , argvs):
    command = program
    for opt,value in argvs.items():
        command += " " + opt + " " + value
    return command

特殊な処理をしているのは二つくらい。

  1. ffmpegのオプション作成にOrderedDictを使っている
  2. パスログを消す時に文字列の間に*を入れている。


まず、1. から説明。
ffmpegpythonで実行させるのだが、2パスで実行したい。
そのため、ほぼ同じオプションでffmpegを実行する。
そのたびに、リストを作成するのは無駄だと思ったので、マップでkeyをオプション、valueをオプションの引数にし、command_generate.pyにマップを渡し、自動でコマンドの文字列を生成してくれる関数を作った。
ところが、pythonのマップは順番に並んでいなかったため、順番を覚えているマップクラス(OrderedDict)を使った。
その結果、ffmpegArgs["-pass"] = str(ffmpegPass) とするだけで、オプションの一部だけを簡単に変更できるようになった。

不満なのは、オプションの

        # 他の箇所は、("opt","value")となっているが、↓以降は、意味が異なる。
        (outputFile,""),        # ("value","")
        ("2>>",ffmpegLogFile),  # ("リダイレクト",ファイル)

であり、この2つだけ意味が異なる。
処理としては問題ないが、オプションではないので、なんとかしたいところ。


次に、2.
パスログを消す時に、ファイル名の指定として、 "hoge"を"hoge*"というようにhogeの後ろに*を追加したかった。
しかし、pythonの文字列は不変であるため、破壊的な挿入ができなかった。
そこで、わざわざ

    # パスログを消す
    front = ffmpegPassLogFile[:-1]
    rear = ffmpegPassLogFile[-1:]
    repi = "*"

    ffmpegPassLogFile = front + repi + rear

と記述。
破壊的な挿入ができれば楽なのに。


出力先やフォーマットなどが固定だけれど、出力先くらいは指定できるようにしたほうがいいかもしれない。

参考:
OrderedDict - Python Module of the Week
文字列の途中に破壊的に文字列を挿入する - Cacography Society
Pythonコード研究所 ファイルのパス情報を取得する basename dirname abspath