Passed
Push — master ( 79d402...4ebce0 )
by Amin
01:15
created

Bitrate.buffer_size()   A

Complexity

Conditions 1

Size

Total Lines 7
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 3
nop 1
dl 0
loc 7
rs 10
c 0
b 0
f 0
1
"""
2
ffmpeg_streaming.media
3
~~~~~~~~~~~~
4
5
Size and Bitrate Objects
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 math
14
15
OVERALL_TO_VIDEO_COEFFICIENT = 1
16
MAX_RATE_COEFFICIENT = 1.2
17
BUFFER_SIZE = 65536
18
19
20
def cnv_bitrate(bitrate: int, _type: str) -> str:
21
    if _type == "k":
22
        bitrate = round(bitrate / 1024)
23
    elif _type == "m":
24
        bitrate = round(bitrate / 1024 * 1024)
25
    else:
26
        raise ValueError("Unknown type!")
27
28
    return str(bitrate) + _type
29
30
31
class Bitrate:
32
    def __init__(self, video: int = None, audio: int = None, overall: int = None, **kwargs):
33
        """
34
        @TODO: add documentation
35
        """
36
        if video is None and overall is None:
37
            raise ValueError("You must at least specify value of the video or overall format")
38
        self.overall_ = overall
39
        self.video_ = video
40
        self.audio_ = audio
41
        self.kwargs = kwargs
42
        self.type = kwargs.pop("type", "k")
43
44
    @property
45
    def overall(self):
46
        """
47
        @TODO: add documentation
48
        """
49
        return cnv_bitrate(self.overall_, self.type) if self.overall_ is not None else None
50
51
    @property
52
    def video(self):
53
        """
54
        @TODO: add documentation
55
        """
56
        return cnv_bitrate(self.video_, self.type) if self.video_ is not None else None
57
58
    @property
59
    def audio(self):
60
        """
61
        @TODO: add documentation
62
        """
63
        return cnv_bitrate(self.audio_, self.type) if self.audio_ is not None else 'copy'
64
65
    def normalize_video(self, convert: bool = True):
66
        """
67
        @TODO: add documentation
68
        """
69
        if self.video_ is not None and self.video_ != 0:
70
            val = self.video_
71
        else:
72
            val = int(self.overall_ * OVERALL_TO_VIDEO_COEFFICIENT)
73
74
        return cnv_bitrate(val, self.type) if convert else val
75
76
    @property
77
    def max_rate(self):
78
        """
79
        @TODO: add documentation
80
        """
81
        return cnv_bitrate(int(self.normalize_video(False) * MAX_RATE_COEFFICIENT), self.type)
82
83
    @property
84
    def buffer_size(self):
85
        """
86
        @TODO: add documentation
87
        """
88
89
        return cnv_bitrate(int(self.kwargs.get('buffer_size', BUFFER_SIZE)), self.type)
90
91
92
def multiple_up(value, multiple):
93
    while 0 != value % multiple:
94
        value += 1
95
96
    return value
97
98
99
def multiple_down(value, multiple):
100
    while 0 != value % multiple:
101
        value -= 1
102
103
    return value
104
105
106
class Ratio:
107
    def __init__(self, width: int, height: int):
108
        """
109
        @TODO: add documentation
110
        """
111
        self.width = width
112
        self.height = height
113
114
    def get_value(self) -> float:
115
        return self.width / self.height
116
117
    def calculate_width(self, height: int, multiple: int = 1) -> int:
118
        """
119
        @TODO: add documentation
120
        """
121
        max_w = multiple_up(math.ceil(self.get_value() * height), multiple)
122
        min_w = multiple_down(math.floor(self.get_value() * height), multiple)
123
124
        max_r = abs(self.get_value() - (max_w / height))
125
        min_r = abs(self.get_value() - (min_w / height))
126
127
        return max_w if max_r < min_r else min_w
128
129
    def calculate_height(self, width: int, multiple: int = 1) -> int:
130
        """
131
        @TODO: add documentation
132
        """
133
        max_h = multiple_up(math.ceil(width / self.get_value()), multiple)
134
        min_h = multiple_down(math.floor(width / self.get_value()), multiple)
135
136
        max_r = abs(self.get_value() - (width / max_h))
137
        min_r = abs(self.get_value() - (width / min_h))
138
139
        return max_h if max_r < min_r else min_h
140
141
142
class Size:
143
    def __init__(self, width: int, height: int):
144
        """
145
        @TODO: add documentation
146
        """
147
        self.width = width
148
        self.height = height
149
150
    @property
151
    def ratio(self) -> Ratio:
152
        """
153
        @TODO: add documentation
154
        """
155
        return Ratio(self.width, self.height)
156
157
    @property
158
    def normalize(self) -> str:
159
        """
160
        @TODO: add documentation
161
        """
162
        return str(self.width) + "x" + str(self.height)
163
164
165
__all__ = [
166
    'Size',
167
    'Bitrate'
168
]