ffmpeg_streaming._command_builder._dash()   A
last analyzed

Complexity

Conditions 2

Size

Total Lines 20
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 14
nop 1
dl 0
loc 20
rs 9.7
c 0
b 0
f 0
1
"""
2
ffmpeg_streaming.build_args
3
~~~~~~~~~~~~
4
5
Build a command for the FFmpeg
6
7
8
:copyright: (c) 2020 by Amin Yazdanpanah.
9
:website: https://www.aminyazdanpanah.com
10
:email: [email protected]
11
:license: MIT, see LICENSE for more details.
12
"""
13
import sys
14
15
from ._utiles import cnv_options_to_args, get_path_info, clean_args
16
17
# DASH default values
18
USE_TIMELINE = 1
19
USE_TEMPLATE = 1
20
21
# HLS default values
22
HLS_LIST_SIZE = 0
23
HLS_TIME = 10
24
HLS_ALLOW_CACHE = 1
25
26
27
def _stream2file(stream2file):
28
    """
29
    @TODO: add documentation
30
    """
31
    args = stream2file.format.all
32
    args.update({'c': 'copy'})
33
    args.update(stream2file.options)
34
35
    return cnv_options_to_args(args) + [stream2file.output_]
36
37
38
def _get_audio_bitrate(rep, index: int = None):
39
    """
40
    @TODO: add documentation
41
    """
42
    if rep.bitrate.audio_ is not None and rep.bitrate.audio_ != 0:
43
        opt = 'b:a' if index is None else f'b:a:{index}'
44
        return {opt: rep.bitrate.audio}
45
46
    return {}
47
48
49
def _get_dash_stream(key, rep):
50
    """
51
    @TODO: add documentation
52
    """
53
    args = {
54
        'map': 0,
55
        f's:v:{str(key)}': rep.size,
56
        f'b:v:{str(key)}': rep.bitrate.calc_video(),
57
    }
58
59
    args.update(_get_audio_bitrate(rep, key))
60
    args.update(rep.options)
61
    return cnv_options_to_args(args)
62
63
64
def _dash(dash):
65
    """
66
    @TODO: add documentation
67
    """
68
    dirname, name = get_path_info(dash.output_)
69
    _args = dash.format.all
70
    _args.update({
71
        'use_timeline':     USE_TIMELINE,
72
        'use_template':     USE_TEMPLATE,
73
        'init_seg_name':    '{}_init_$RepresentationID$.$ext$'.format(name),
74
        "media_seg_name":   '{}_chunk_$RepresentationID$_$Number%05d$.$ext$'.format(name),
75
        'f': 'dash'
76
    })
77
    _args.update(dash.options)
78
    args = cnv_options_to_args(_args)
79
80
    for key, rep in enumerate(dash.reps):
81
        args += _get_dash_stream(key, rep)
82
83
    return args + ['-strict', '-2', '{}/{}.mpd'.format(dirname, name)]
84
85
86
def _hls_seg_ext(hls):
87
    """
88
    @TODO: add documentation
89
    """
90
    return 'm4s' if hls.options.get('hls_segment_type', '') == 'fmp4' else 'ts'
91
92
93
def _get_hls_stream(hls, rep, dirname, name):
94
    """
95
    @TODO: add documentation
96
    """
97
    args = hls.format.all
98
    args.update({
99
        'hls_list_size':            HLS_LIST_SIZE,
100
        'hls_time':                 HLS_TIME,
101
        'hls_allow_cache':          HLS_ALLOW_CACHE,
102
        'hls_segment_filename':     "{}/{}_{}p_%04d.{}".format(dirname, name, rep.size.height, _hls_seg_ext(hls)),
103
        'hls_fmp4_init_filename':   "{}_{}p_init.mp4".format(name, rep.size.height),
104
        's:v':                      rep.size,
105
        'b:v':                      rep.bitrate.calc_video()
106
    })
107
    args.update(_get_audio_bitrate(rep))
108
    args.update(rep.options)
109
    args.update({'strict': '-2'})
110
    args.update(hls.options)
111
112
    return cnv_options_to_args(args) + ["{}/{}_{}p.m3u8".format(dirname, name, str(rep.size.height))]
113
114
115
def _hls(hls):
116
    """
117
    @TODO: add documentation
118
    """
119
    dirname, name = get_path_info(hls.output_)
120
    streams = []
121
    for key, rep in enumerate(hls.reps):
122
        if key > 0:
123
            streams += input_args(hls)
124
        streams += _get_hls_stream(hls, rep, dirname, name)
125
126
    return streams
127
128
129
def stream_args(media):
130
    """
131
    @TODO: add documentation
132
    """
133
    return getattr(sys.modules[__name__], "_%s" % type(media).__name__.lower())(media)
134
135
136
def input_args(media):
137
    inputs = []
138
    for key, _input in enumerate(media.media.inputs.inputs):
139
        _input = dict(_input)
140
        _input.pop('is_tmp', None)
141
        if key > 0:
142
            _input.pop('y', None)
143
        inputs += cnv_options_to_args(_input)
144
145
    return inputs
146
147
148
def command_builder(ffmpeg_bin: str, media):
149
    """
150
    @TODO: add documentation
151
    """
152
    return " ".join(clean_args([ffmpeg_bin] + input_args(media) + stream_args(media)))
153