-
Notifications
You must be signed in to change notification settings - Fork 18
/
ffmpeg_process_factory.py
134 lines (111 loc) · 3.81 KB
/
ffmpeg_process_factory.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
import subprocess
from utils import line, Logger, show_progress_bar, VideoInfoProvider
log = Logger("factory")
class EncodingArguments:
def __init__(self, infile, encoder, outfile):
self._infile = infile
self._encoder = encoder
self._outfile = outfile
self._base_ffmpeg_arguments = ["-i", self._infile]
# libaom-av1 "cpu-used" option.
def av1_cpu_used(self, value):
self._av1_cpu_used = value
def preset(self, value):
self._preset = value
def crf(self, value):
self._crf = value
def video_filters(self, filters):
if filters is not None:
self._video_filters = ["-vf", filters]
else:
self._video_filters = ""
def outfile(self, value):
self._outfile = value
def get_arguments(self):
base_encoding_arguments = [
"-map",
"0:V",
"-c:v",
"libaom-av1" if self._encoder == "libaom-av1" else f"lib{self._encoder}",
"-crf",
self._crf,
]
if self._encoder == "libaom-av1":
encoding_arguments = base_encoding_arguments + [
"-b:v",
"0",
"-cpu-used",
self._av1_cpu_used,
*self._video_filters,
self._outfile,
]
else:
encoding_arguments = base_encoding_arguments + [
"-preset",
self._preset,
*self._video_filters,
self._outfile,
]
return self._base_ffmpeg_arguments + encoding_arguments
class LibVmafArguments:
def __init__(self, fps, distorted_video, original_video, vmaf_options):
self._fps = fps
self._distorted_video = distorted_video
self._original_video = original_video
self._vmaf_options = vmaf_options
def video_filters(self, filters):
if filters is not None:
self._video_filters = f",{filters}"
else:
self._video_filters = ""
def get_arguments(self):
return [
"-r",
self._fps,
"-i",
self._distorted_video,
"-r",
self._fps,
"-i",
self._original_video,
"-map",
"0:V",
"-map",
"1:V",
"-lavfi",
f"[0:v]setpts=PTS-STARTPTS[dist];"
f"[1:v]setpts=PTS-STARTPTS{self._video_filters}[ref];"
f"[dist][ref]libvmaf={self._vmaf_options}",
"-f",
"null",
"-",
]
class FfmpegProcessFactory:
def create_process(self, arguments, args):
_process_base_arguments = [
"ffmpeg",
"-progress",
"-",
"-nostats",
"-loglevel",
"warning",
"-y",
]
process = FfmpegProcess(_process_base_arguments + arguments.get_arguments(), args)
return process
class FfmpegProcess:
def __init__(self, arguments, args):
self._arguments = arguments
if args.show_commands:
line()
log.debug(f'Running the following command:\n{" ".join(self._arguments)}')
line()
def run(self, video_path, duration):
self._video_path = video_path
self._duration = duration
video_info = VideoInfoProvider(self._video_path)
self._total_frames = int((video_info.get_framerate_float() * self._duration) + 1)
# Start the FFmpeg process.
self._process = subprocess.Popen(self._arguments, stdout=subprocess.PIPE)
# Use tqdm to show a progress bar.
show_progress_bar(self._process, self._total_frames)