🤩

複数の動画を同一オプションでワンライナー処理するスクリプト

に公開

はじめに

FFmpegはコマンドラインで動画ファイルを処理できるので大変便利です。
しかし、同じような処理を複数の動画ファイルに対して適用するには、コマンドのパスの部分をファイルごとに変えなければなりません。
これは少し手間です。

以下のスクリプトは、その手間を省いてくれるPythonスクリプトです。
FFmpegを外部コマンドとして呼び出すだけなので、パッケージのインストールは不要です。

コード

import re
import sys
from argparse import ArgumentParser
from pathlib import Path
from subprocess import Popen

parser = ArgumentParser(description='Wrapper for FFmpeg to process multiple files in one-line')

parser.add_argument('-c', '--command', default='ffmpeg', help='command to be executed')
parser.add_argument('-o', '--output', type=Path, help='output directory path')
parser.add_argument('-m', '--multi', action='store_true', help='enable multi-processing')
parser.add_argument('-g', '--glob', default='**/*', help='glob to filter input paths')
parser.add_argument('-wf', '--whitefilter', default='', type=re.compile, help='regex to filter input paths')
parser.add_argument('options', help='options passed to FFmpeg, ex: "-i {} {}.mp4"')
parser.add_argument('input', nargs='+', type=Path, help='input file or directory path(s)')

args = parser.parse_args()

inputs = []

for input in args.input:
    if input.is_file():
        sub_inputs = [input]
    else:
        sub_inputs = input.glob(args.glob)

    inputs += [sub_input for sub_input in sub_inputs if sub_input.is_file() and args.whitefilter.search(str(sub_input))]

placeholder_count = args.options.count('{}')

if placeholder_count not in [1, 2]:
    print('The number of placeholders in options must be 1 or 2.')
    sys.exit()

elif placeholder_count == 2 and args.output is None:
    print('The output directory path must be specified when the number of placeholders in options is 2.')
    sys.exit()

procs = []

for input in inputs:
    sub_args = args.command.strip()

    params = [str(input)]

    if args.output:
        output = args.output / input.stem
        params.append(str(output))

    sub_args += ' ' + args.options.format(*[f'"{param}"' for param in params])
    print(sub_args)

    proc = Popen(sub_args, shell=True)
    if not args.multi:
        proc.wait()

    procs.append(proc)

    print()

codes = {}

for proc in procs:
    code = proc.wait()
    if code in codes:
        codes[code] += 1
    else:
        codes[code] = 1

code_count = sum(codes.values())

for code, count in codes.items():
    print(f"returncode[{code}]:", count, '/', code_count)

使用例

例えば、特定のディレクトリ以下のすべての動画ファイルをH.265でエンコードしなおすには以下のコマンドを実行します。

python script.py "-i {} -c:v libx265 -c:a copy {}.mp4" path/to/input/directory -o path/to/output/directory

Discussion