1
|
|
|
""" |
2
|
|
|
ffmpeg_streaming.build_args |
3
|
|
|
~~~~~~~~~~~~ |
4
|
|
|
|
5
|
|
|
Build a command for the FFmpeg |
6
|
|
|
|
7
|
|
|
|
8
|
|
|
:copyright: (c) 2019 by Amin Yazdanpanah. |
9
|
|
|
:website: https://www.aminyazdanpanah.com |
10
|
|
|
:email: [email protected] |
11
|
|
|
:license: MIT, see LICENSE for more details. |
12
|
|
|
""" |
13
|
|
|
|
14
|
|
|
from .utiles import get_path_info |
15
|
|
|
from .rep import Representation |
16
|
|
|
|
17
|
|
|
|
18
|
|
|
def _get_hls_args(hls): |
19
|
|
|
dirname, name = get_path_info(hls.output) |
20
|
|
|
|
21
|
|
|
args = [] |
22
|
|
|
for key, rep in enumerate(hls.reps): |
23
|
|
|
if isinstance(rep, Representation): |
24
|
|
|
if hls.options is not None: |
25
|
|
|
for option in hls.options: |
26
|
|
|
args += ['-' + option, str(hls.options[option])] |
27
|
|
|
if key > 0: |
28
|
|
|
args += ['-c:v', hls.video_format] |
29
|
|
|
if hls.audio_format is not None: |
30
|
|
|
args += ['-c:a', hls.audio_format] |
31
|
|
|
args += ['-s:v', rep.size] |
32
|
|
|
args += ['-crf', '20'] |
33
|
|
|
args += ['-sc_threshold', '0'] |
34
|
|
|
args += ['-g', '48'] |
35
|
|
|
args += ['-keyint_min', '48'] |
36
|
|
|
args += ['-hls_list_size', str(hls.hls_list_size)] |
37
|
|
|
args += ['-hls_time', str(hls.hls_time)] |
38
|
|
|
args += ['-hls_allow_cache', str(hls.hls_allow_cache)] |
39
|
|
|
args += ['-b:v', rep.bit_rate] |
40
|
|
|
if rep.audio_bit_rate is not None: |
41
|
|
|
args += ['-b:a', rep.audio_bit_rate] |
42
|
|
|
args += ['-maxrate', str(round(rep.kilo_bitrate * 1.2)) + "k"] |
43
|
|
|
args += ['-hls_segment_filename', dirname + "/" + name + "_" + str(rep.height) + "p_%04d.ts"] |
44
|
|
|
if hls.hls_key_info_file is not None: |
45
|
|
|
args += ['-hls_key_info_file', hls.hls_key_info_file.replace("\\", "/")] |
46
|
|
|
args += ['-strict', hls.options.get('strict', "-2")] |
47
|
|
|
args += [dirname + "/" + name + "_" + str(rep.height) + "p.m3u8"] |
48
|
|
|
|
49
|
|
|
return args |
50
|
|
|
|
51
|
|
|
|
52
|
|
|
def _get_dash_args(dash): |
53
|
|
|
dirname, name = get_path_info(dash.output) |
54
|
|
|
|
55
|
|
|
args = [ |
56
|
|
|
'-bf', '1', |
57
|
|
|
'-keyint_min', '120', |
58
|
|
|
'-g', '120', |
59
|
|
|
'-sc_threshold', '0', |
60
|
|
|
'-b_strategy', '0', |
61
|
|
|
'-use_timeline', '1', |
62
|
|
|
'-use_template', '1', |
63
|
|
|
'-init_seg_name', (name + '_init_$RepresentationID$.$ext$') if dash.init_seg_name is None else dash.init_seg_name, |
64
|
|
|
"-media_seg_name", (name + '_chunk_$RepresentationID$_$Number%05d$.$ext$') if dash.media_seg_name is None else dash.media_seg_name, |
65
|
|
|
'-f', 'dash' |
66
|
|
|
] |
67
|
|
|
|
68
|
|
|
if dash.options is not None: |
69
|
|
|
for option in dash.options: |
70
|
|
|
args += ['-' + option, str(dash.options[option])] |
71
|
|
|
|
72
|
|
|
for key, rep in enumerate(dash.reps): |
73
|
|
|
if isinstance(rep, Representation): |
74
|
|
|
args += ['-map', '0'] |
75
|
|
|
args += ['-b:v:' + str(key), rep.bit_rate] |
76
|
|
|
if rep.audio_bit_rate is not None: |
77
|
|
|
args += ['-b:a:' + str(key), rep.audio_bit_rate] |
78
|
|
|
args += ['-s:v:' + str(key), rep.size] |
79
|
|
|
|
80
|
|
|
if dash.adaption is not None: |
81
|
|
|
args += ['-adaptation_sets', dash.adaption] |
82
|
|
|
args += ['-strict', dash.options.get('strict', "-2")] |
83
|
|
|
args += ['"' + dirname + '/' + name + '.mpd"'] |
84
|
|
|
|
85
|
|
|
return args |
86
|
|
|
|
87
|
|
|
|
88
|
|
|
def _get_stream2file_args(stream2file): |
89
|
|
|
args = ['-c', 'copy'] |
90
|
|
|
|
91
|
|
|
if stream2file.options is not None: |
92
|
|
|
for option in stream2file.options: |
93
|
|
|
args += ['-' + option, str(stream2file.options[option])] |
94
|
|
|
args += ['"' + stream2file.output + '"'] |
95
|
|
|
|
96
|
|
|
return args |
97
|
|
|
|
98
|
|
|
|
99
|
|
|
def build_command(cmd, media_obj): |
100
|
|
|
if type(cmd) != list: |
101
|
|
|
cmd = [cmd] |
102
|
|
|
|
103
|
|
|
cmd += ['-y', '-i', '"' + media_obj.filename.replace("\\", "/") + '"'] |
104
|
|
|
cmd += ['-c:v', media_obj.video_format] |
105
|
|
|
|
106
|
|
|
if media_obj.audio_format is not None: |
107
|
|
|
cmd += ['-c:a', media_obj.audio_format] |
108
|
|
|
|
109
|
|
|
media_name = type(media_obj).__name__ |
110
|
|
|
|
111
|
|
|
if media_name == 'HLS': |
112
|
|
|
cmd += _get_hls_args(media_obj) |
113
|
|
|
elif media_name == 'DASH': |
114
|
|
|
cmd += _get_dash_args(media_obj) |
115
|
|
|
elif media_name == 'StreamToFile': |
116
|
|
|
cmd += _get_stream2file_args(media_obj) |
117
|
|
|
|
118
|
|
|
return " ".join(cmd) |
119
|
|
|
|