FFmpegで動画を逆再生化するPythonスクリプト

MATVToolに組み込むかもしれませんが、いまのところ詳細な動作検証をするほど需要がないので、簡易的にここに置いておきます。

動画ファイルによっては、フレームの欠け、重複が発生したり、変換に失敗するかもしれません。

  • Python 3.11.3
  • FFmpeg 4.2.7-0ubuntu0.1
  • Ubuntu 20.04 (WSL2)
python3 main.py input.mp4 output.mp4
# License: CC0-1.0
import os
import subprocess
import tempfile
import re
import math
def get_duration_seconds(input_file: str) -> float:
proc = subprocess.run(
[
'ffmpeg',
'-hide_banner',
'-i',
input_file,
],
stderr=subprocess.PIPE,
)
lines = proc.stderr.decode(encoding='utf-8').splitlines()
# hh:mm:ss.ff
duration_string = None
for line in lines:
m = re.match(r'^\s*Duration:\s(.+?),.*$', line)
if m:
duration_string = m.group(1)
break
assert duration_string is not None
hours = int(duration_string[0:2])
minutes = int(duration_string[3:5])
seconds = int(duration_string[6:8])
milliseconds = float('0.' + duration_string[9:11])
return hours * 3600 + minutes * 60 + seconds + milliseconds
def parse_time(string: str) -> float:
"""
string: HH:MM:SS.FF
"""
hours = int(string[0:2])
minutes = int(string[3:5])
seconds = int(string[6:8])
milliseconds = float('0.' + string[9:11])
return hours * 3600 + minutes * 60 + seconds + milliseconds
def format_time(seconds: int) -> str:
hours_minutes = seconds // 60
hours = hours_minutes // 60
minutes = hours_minutes - hours * 60
local_seconds = seconds - hours_minutes * 60
return f'{hours:02d}:{minutes:02d}:{local_seconds:02d}'
def main():
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('input_file', type=str)
parser.add_argument('output_file', type=str)
parser.add_argument('--split_duration', type=int, default=10)
args = parser.parse_args()
input_file = args.input_file
output_file = args.output_file
split_duration = args.split_duration
duration_seconds = math.ceil(get_duration_seconds(input_file=input_file))
count = math.ceil(duration_seconds / split_duration)
work_dir_obj = tempfile.TemporaryDirectory()
work_dir = work_dir_obj.name
part_output_file_list = []
for index in range(count):
start = index * split_duration
end = start + split_duration
start_string = format_time(start)
end_string = format_time(end)
print(index, start_string, end_string)
part_output_file = os.path.join(work_dir, f'output{count-index}.mp4')
subprocess.run([
'ffmpeg',
'-hide_banner',
'-ss',
start_string,
'-to',
end_string,
'-i',
'input.mp4',
'-vf',
'reverse',
'-af',
'areverse',
part_output_file,
])
part_output_file_list.append(part_output_file)
list_file = os.path.join(work_dir, 'list.txt')
with open(list_file, 'w', encoding='utf-8') as fp:
for part_output_file in part_output_file_list:
fp.write(f"file '{part_output_file}'\n")
subprocess.run([
'ffmpeg',
'-hide_banner',
'-f',
'concat',
'-safe',
'0',
'-i',
list_file,
'-c',
'copy',
output_file,
])
if __name__ == '__main__':
main()

参考