動画ファイルを簡単(再エンコードしないで)に結合して結合部分にチャプターを自動生成するスクリプトを、python を使って書いてみました
要件定義
- mp4, mkv ファイルを再エンコードしないで結合したい
- 楽したい!(使いまわしができるように)
- Windows10 環境で動く
- python, ffmpeg, mkvmerge などのインストールはできる前提
- すでにチャプターがついているファイルはそのチャプターを利用したい
- こんな感じで要件を確定させて、実際にどのツールを使っていくのか?を検討していきます
検討結果(=機能リスト)
- Windows10でのみ検証しています(Linuxでも少しの修正で動くはず)
- チャプターを簡単に作成するため最終的なファイルフォーマットを mkv にする
- 結合するファイルのファイル名をチャプター名として利用
- mkvファイルで、すでにチャプターがついている場合はそのまま利用する
- 結合元のソースファイルは、mp4 or mkv のみ
- 結合するファイルの順番は python の Sort関数順
- ワイルドカードで結合ファイルを選択するので、結合するファイル名の先頭部分は同一にする必要がある
- Codec(A,V), 画素数, アスペクト比等は、結合するファイルで統一されているのが望ましい
- ファイルフォーマットが異なる場合はある程度統一します(再エンコーディングしますので要時間)
- pythonのコーディング久しぶりなのでコードが美しくないのはご容赦ください
動作の流れ
- ソースファイルを mkv に統一
- ffmpeg 利用
- mp4 to mkv
- 動画フォーマットを統一
- ffprobe で確認して必要であれば ffmpeg を利用します
# 動画ファイルの情報をjsonで出力します
bat.write('"%s" "%s" -loglevel quiet -show_streams -print_format json > %s\n'
% (ffprobe, c, ffprobejson))
bat.close()
# jsonファイルを確認して想定しているサイズと異なる場合は再エンコードのフラグをたてます
json_f = open(ffprobejson, "r")
json_data = json.load(json_f)
json_f.close()
reenc = False
for stream in json_data['streams']:
if stream['codec_type'] == 'video':
print(stream['codec_type'])
if stream['codec_name'] != codec_name_v:
print(stream['codec_name'])
reenc = True
if stream['width'] != width:
print(stream['width'])
reenc = True
if stream['height'] != height:
print(stream['height'])
reenc = True
- チャプターを追加
- 既存のチャプターを確認(mkvextract 利用)
# チャプターが存在するとチャプター内容がファイル出力されます
bat.write('"%s" "%s" chapters -s "%s"\n'
% (mkvextract, mkv, chkchapfile))
bat.close()
# ファイルが生成されればチャプター付きなのでそのまま利用します
- 結合前のmkv状態で、00:00:00部分にチャプターを追加
- mkvmerge 利用(チャプターデータのファイルを生成してからmkvmergeで追加します)
metafile = open(metafilename, 'w+')
metafile.write('CHAPTER01=00:00:00.000\n')
metafile.write('CHAPTER01NAME=%s\n' % bname)
metafile.close()
bat.write('"%s" --chapters "%s" -o "%s" "%s"\n'
% (mkvmerge, metafilename, mkn, mkv))
bat.close()
- mkvファイルを結合
- mkvmerge 利用
ポイント
- mkvmerge で mkvファイルを結合するときにチャプターが残る仕様を活用しています
- 外部ツールを起動する場合に subprocess(ライブラリ)経由で batファイルを使っています
初期設定
- pythonファイルの先頭部分を修正してください
mkvmergeを起動するバッチファイル(ファイルが作成できる場所であればどこでも可)
batfilename = 'H:\mp4mkvmerge_.bat'
チャプターを作成するときの作業用ファイル(ファイルが作成できる場所であればどこでも可)
metafilename = 'H:\metadata.txt'
mkvmerge.exe の場所
ffmpeg.exe の場所
ffprobe.exe の場所
mkvextract.exe の場所
mkvmerge = 'C:\Program Files\MKVToolNix\mkvmerge.exe'
ffmpeg = 'C:\Program Files\ffmpeg\bin\ffmpeg.exe'
ffprobe = 'C:\Program Files\ffmpeg\bin\ffprobe.exe'
mkvextract = 'C:\Program Files\MKVToolNix\mkvextract.exe'
作業用の空ディレクトリ(存在している必要あり)
作業用ファイル名
tempDir = 'C:\TEMP'
mergefilename = '000.mkv'
chkmp4filename = 'chk.mp4'
chkmkvfilename = 'chk.mkv'
chkchapterfilename = 'chap.txt'
結合時に異なるフォーマットの場合に揃えるパラメータ(タブレット向き?)
codec_name_v = 'hevc'
codec_name_a = 'aac'
width = 1280
height = 720
sample_rate = '48000'
reenc_codec_v = 'hevc_nvenc'
reenc_codec_a = 'aac'
reenc_bitrate = '1200k'
サンプル
python mp4mkvmerge.py "C:\Videos" "DORAMA" "DORAMA #01-12 END" "C:\DELETE"
- C:\Videos ディレクトリにある DORAMAで始まるファイル(DORAMA*.mp4, DORAMA*.mkv)を(ファイル名を pythonの標準sort順で)結合します
- DORAMA #01.mp4 と DORAMA #01.mkv が存在する場合は同一とみなし DORAMA #01.mkv を結合対象とします
- 処理が終わったら、C:\Videos\DORAMA #01-12 END.mkv ファイルが生成されます
- 結合前のファイルは、C:\DELETE フォルダに移動されます
ソースコード
カスタマイズ
- Windows の batファイルを生成しているところをシェルスクリプトに変更すればLinux対応できます
- 再エンコード の ffmpegパラメータは好きなようにカスタマイズしてください(筆者は NVEncC64 を使っているので適当ですいません)