TSからmp4への圧縮を一括実行するpythonスクリプト

ここで紹介するのは、録画で溜まったTSファイルをmp4ファイルへ圧縮してくれるpythonのスクリプトです。

CentOS 8.2の環境で、使用しています。今回は、ffmpegの性能を測定したスクリプトを簡単にして紹介します。

実行環境の準備

実際に確認した環境は、CentOS 8.2です。

ここで紹介するスクリプトを実行するために、以下の確認が必要です。

  1. python3が実行できる。
  2. ffmpegが実行できる。
  3. ffmpeg-pythonが使用できる。

(1) python3がインストールされているか確認する。

[euser@test ~]$ python3 -V
Python 3.6.8

(2) ffmpegがインストールされているか確認する。

[euser@test ~]$ ffmpeg -version
ffmpeg version 4.2.4 Copyright (c) 2000-2020 the FFmpeg developers
built with gcc 8 (GCC)
configuration: --prefix=/usr --bindir=/usr/bin --datadir=/usr/share/ffmpeg --docdir=/usr/share/doc/ffmpeg --incdir=/usr/include/ffmpeg --libdir=/usr/lib64 --mandir=/usr/share/man --arch=x86_64 --optflags='-O2 -g -pipe -Wall -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -fexceptions -fstack-protector-strong -grecord-gcc-switches -specs=/usr/lib/rpm/redhat/redhat-hardened-cc1 -specs=/usr/lib/rpm/redhat/redhat-annobin-cc1 -m64 -mtune=generic -fasynchronous-unwind-tables -fstack-clash-protection -fcf-protection' --extra-ldflags='-Wl,-z,relro -Wl,-z,now -specs=/usr/lib/rpm/redhat/redhat-hardened-ld ' --extra-cflags=' ' --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libvo-amrwbenc --enable-version3 --enable-bzlib --disable-crystalhd --enable-fontconfig --enable-frei0r --enable-gcrypt --enable-gnutls --enable-ladspa --enable-libaom --enable-libdav1d --enable-libass --enable-libbluray --enable-libcdio --enable-libdrm --enable-libjack --enable-libfreetype --enable-libfribidi --enable-libgsm --enable-libmp3lame --enable-nvenc --enable-openal --enable-opencl --enable-opengl --enable-libopenjpeg --enable-libopus --enable-libpulse --enable-librsvg --enable-libsrt --enable-libsoxr --enable-libspeex --enable-libssh --enable-libtheora --enable-libvorbis --enable-libv4l2 --enable-libvidstab --enable-libvmaf --enable-version3 --enable-vapoursynth --enable-libvpx --enable-libx264 --enable-libx265 --enable-libxvid --enable-libzimg --enable-libzvbi --enable-avfilter --enable-avresample --enable-libmodplug --enable-postproc --enable-pthreads --disable-static --enable-shared --enable-gpl --disable-debug --disable-stripping --shlibdir=/usr/lib64 --enable-libmfx --enable-runtime-cpudetect
libavutil      56. 31.100 / 56. 31.100
libavcodec     58. 54.100 / 58. 54.100
libavformat    58. 29.100 / 58. 29.100
libavdevice    58.  8.100 / 58.  8.100
libavfilter     7. 57.100 /  7. 57.100
libavresample   4.  0.  0 /  4.  0.  0
libswscale      5.  5.100 /  5.  5.100
libswresample   3.  5.100 /  3.  5.100
libpostproc    55.  5.100 / 55.  5.100

(3)ffmpeg-pythonがインストールされているか確認する。

[euser@test ~]$ pip3 --version
pip 9.0.3 from /usr/lib/python3.6/site-packages (python 3.6)
[euser@test ~]$ pip3 install --user ffmpeg-python
Collecting ffmpeg-python
  Using cached https://files.pythonhosted.org/packages/d7/0c/56be52741f75bad4dc6555991fabd2e07b432d333da82c11ad701123888a/ffmpeg_python-0.2.0-py3-none-any.whl
Requirement already satisfied: future in /usr/local/lib/python3.6/site-packages (from ffmpeg-python)
Installing collected packages: ffmpeg-python
Successfully installed ffmpeg-python-0.2.0
[euser@test ~]$ pip3 list
DEPRECATION: The default format will switch to columns in the future. You can use --format=(legacy|columns) (or define a format=(legacy|columns) in your pip.conf under the [list] section) to disable this warning.
asn1crypto (0.24.0)
astroid (2.4.2)
bcc (0.11.0)
blivet (3.1.0)
Brlapi (0.6.7)
cffi (1.11.5)
chardet (3.0.4)
chrome-gnome-shell (0.0.0)
colorama (0.4.3)
configobj (5.0.6)
configshell-fb (1.1.25)
coverage (4.5.1)
crayons (0.4.0)
cryptography (2.3)
cupshelpers (1.0)
dbus-python (1.2.4)
decorator (4.2.1)
ethtool (0.14)
ffmpeg-python (0.2.0)
future (0.18.2)

以上で、python3、ffmpeg、ffmpeg-pythonが実行できることが確認できました。

スクリプトの説明

今回作成したスクリプトは、二つに分かれています。

  1. 実行制御スクリプト
    crf値、preset値を設定して、実行を制御します。
    今回は、1440×1080の解像度で、crf=22、preset=veryfastで1回処理します。
  2. 圧縮処理スクリプト
    与えられたcrf値、preset値を用いて、ffmpegで圧縮を実行します。
    また、logに圧縮速度・圧縮率を記録することができます。

(1)実行制御スクリプト(ts_to_mp4_1440.py)

#ts_to_mp4_1440.py
#created 2020-10-05 by simplelife0530

import trans_mp4
import pathlib
import os

# mode = 1440 or 1920
mode = 1440
in_dir = "./ts/"

# p_list = [veryfast]
# c_list 1440 = [22]
# c_list 1920 = [25]

p_list = ["veryfast"]
if mode == 1440: 
    c_list = [22]
else: c_list = [25]
for preset in p_list:
    for crf in c_list:
        out_dir = "./mp4/" + str(crf) + "-" + preset + "/"
        os.makedirs(out_dir, exist_ok=True)
        f_list = pathlib.Path(in_dir).glob("*.ts")
        for f in f_list:
            trans_mp4.transcode(in_dir + f.name, out_dir + f.name.replace(".ts",".mp4"),crf,preset, "")

(2)圧縮処理スクリプト(trans_mp4.py)

#trans_mp4.py
#created 2020-03-30 by simplelife0530
#
import ffmpeg
import pathlib
import glob
import subprocess
import sys
import time
import json
import os
import datetime
import csv

def transcode(input_file,output_file,crfValue,presetValue,sValue):

    in_options = {}
    if not sValue:
        out_options = {'vcodec':'libx264', 'crf':crfValue, 'preset':presetValue}
        out_tag = str(crfValue) + "-" + presetValue
    else:
        out_options = {'vcodec':'libx264', 'crf':crfValue, 'preset':presetValue, 's':sValue}
        out_tag = str(crfValue) + "-" + presetValue + "-" + sValue

    log_path = "./log/"
    os.makedirs(log_path, exist_ok=True)
    today =  datetime.date.today()
    log_info = str(crfValue) + "-" + presetValue
    log_file = log_path + log_info + ".csv"
    header = ["ファイル名", "再生時間", "処理時間", "トランスコード速度", "入力ファイルサイズ", "出力ファイルサイズ", "圧縮率"]

    try:
        with open(log_file, 'x') as f:     
            writer = csv.writer(f)
            writer.writerow(header)
    except FileExistsError:
        pass
        
    start = time.time()
    (
        ffmpeg
        .input(input_file, **in_options)
        .output(output_file, **out_options)
        .run()
    )
    elapsed_time = time.time() - start

    print("処理時間:{:.1f}".format(elapsed_time))
    file_name = os.path.basename(input_file)
    video_info = ffmpeg.probe(input_file)
    video_stream = next((stream for stream in video_info['streams'] if stream['codec_type'] == 'video'), None)
    video_duration = float(video_stream['duration'])
    print("再生時間:{:.1f}".format(video_duration))
    compression_speed = video_duration/elapsed_time
    print("速度:{:.1f}".format(compression_speed))
    input_filesize = os.path.getsize(input_file)
    output_filesize = os.path.getsize(output_file)
    print("入力サイズ:", input_filesize)
    print("出力サイズ:", output_filesize)
    compression_ratio = output_filesize/input_filesize
    print("圧縮率:{:.3f}".format(compression_ratio) )
    with open(log_file, 'a') as f:
        writer = csv.writer(f)
        writer.writerow([file_name, '{:.1f}'.format(video_duration), '{:.1f}'.format(elapsed_time), '{:.1f}'.format(compression_speed), input_filesize, output_filesize, '{:.3f}'.format(compression_ratio)])

実行制御スクリプトを変更することで、複数のcrf値、複数のpreset値で圧縮を行うことができます。

スクリプトの利用手順

本スクリプトを利用する手順は、以下のとおりです。

  1. TSファイルを用意する。
  2. TSファイルのサイズの1.5倍以上の容量が確保できるフォルダを作成する。
  3. 作成したフォルダの中に、tsという名前のフォルダを作成し、TSファイルを保存する。
  4. 二つのスクリプト ts_to_mp4_1440.pyとtrans_mp4.pyを作成したフォルダにコピーする。
  5. ターミナルを使って、ts_to_mp4.pyを実行する。

以下が、実行準備が整った状態。

ターミナルを開き、コマンドを入力する。

[euser@test test]$ ls
trans_mp4.py  ts  ts_to_mp4_1440.py

[euser@test test]$ python3 ts_to_mp4_1440.py

処理が終了した時の状態。

新たに、「mp4」、「log」、「–pycache–」の3つのフォルダができる。

「mp4」フォルダの中に、「22-veryfast」というフォルダがあり、その中に圧縮してできたmp4ファイルが保存されている。

「log」フォルダの中に、22-veryfast.csvというファイルがあり、ファイルごとの圧縮速度、圧縮率がcsv形式で記録されている。

テストスクリプト

スクリプトをもう一種類紹介します。こちらは、
3種類のpreset(superfast、veryfast、faster)、
5種類のcrf
(21、22、23、24、25)(1440×1080)、
(23、24、25、26、27)(1920×1080)
計15パターンで圧縮を実施します。

FFmpegの性能調査を実施する際に便利なスクリプトです。
test_mp4_1440.pyは、1440x1080の解像度の、主に地上波のTSファイルのためのスクリプトです。

#test_mp4_1440.py
#created 2020-09-12 by simplelife0530

import trans_mp4
import pathlib
import os

# mode = 1440 or 1920
mode = 1440
in_dir = "./ts/"

# p_list = [superfast, veryfast, faster]
# c_list 1440 = [21, 22, 23, 24, 25]
# c_list 1920 = [23, 24, 25, 26, 27]

p_list = ["veryfast"]
if mode == 1440: 
    c_list = [21, 22, 23, 24, 25]
else: c_list = [23, 24, 25, 26, 27]
for preset in p_list:
    for crf in c_list:
        out_dir = "./mp4/" + str(crf) + "-" + preset + "/"
        os.makedirs(out_dir, exist_ok=True)
        f_list = pathlib.Path(in_dir).glob("*.ts")
        for f in f_list:
            trans_mp4.transcode(in_dir + f.name, out_dir + f.name.replace(".ts",".mp4"),crf,preset, "")

test_mp4_1920.pyは、1920x1080の解像度の、主にBSプレミアム、BS11、WOWOW向けのTSファイルのためのスクリプトです。

#test_mp4_1920.py
#created 2020-09-12 by simplelife0530

import trans_mp4
import pathlib
import os

# mode = 1440 or 1920
mode = 1920
in_dir = "./ts/"

# p_list = [superfast, veryfast, faster]
# c_list 1440 = [21, 22, 23, 24, 25]
# c_list 1920 = [23, 24, 25, 26, 27]

p_list = ["veryfast"]
if mode == 1440: 
    c_list = [21, 22, 23, 24, 25]
else: c_list = [23, 24, 25, 26, 27]
for preset in p_list:
    for crf in c_list:
        out_dir = "./mp4/" + str(crf) + "-" + preset + "/"
        os.makedirs(out_dir, exist_ok=True)
        f_list = pathlib.Path(in_dir).glob("*.ts")
        for f in f_list:
            trans_mp4.transcode(in_dir + f.name, out_dir + f.name.replace(".ts",".mp4"),crf,preset, "")

スクリプトのダウンロード

スクリプトは、以下からダウンロードできる。

2020年10月06日 | Posted in 電脳:録画サーバー | タグ: , , No Comments » 

関連記事

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください