Passed
Push — master ( 3ed505...db420a )
by Amin
03:22 queued 10s
created

Bitrate.calc_video()   A

Complexity

Conditions 4

Size

Total Lines 10
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 5
nop 2
dl 0
loc 10
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 calc_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 calc_overall(self):
78
        """
79
        @TODO: add documentation
80
        """
81
        return self.overall_ if self.overall_ is not None else self.video_ + self.audio_
82
83
84
def multiple_up(value, multiple):
85
    while 0 != value % multiple:
86
        value += 1
87
88
    return value
89
90
91
def multiple_down(value, multiple):
92
    while 0 != value % multiple:
93
        value -= 1
94
95
    return value
96
97
98
class Ratio:
99
    def __init__(self, width: int, height: int):
100
        """
101
        @TODO: add documentation
102
        """
103
        self.width = width
104
        self.height = height
105
106
    def get_value(self) -> float:
107
        return self.width / self.height
108
109
    def calculate_width(self, height: int, multiple: int = 1) -> int:
110
        """
111
        @TODO: add documentation
112
        """
113
        max_w = multiple_up(math.ceil(self.get_value() * height), multiple)
114
        min_w = multiple_down(math.floor(self.get_value() * height), multiple)
115
116
        max_r = abs(self.get_value() - (max_w / height))
117
        min_r = abs(self.get_value() - (min_w / height))
118
119
        return max_w if max_r < min_r else min_w
120
121
    def calculate_height(self, width: int, multiple: int = 1) -> int:
122
        """
123
        @TODO: add documentation
124
        """
125
        max_h = multiple_up(math.ceil(width / self.get_value()), multiple)
126
        min_h = multiple_down(math.floor(width / self.get_value()), multiple)
127
128
        max_r = abs(self.get_value() - (width / max_h))
129
        min_r = abs(self.get_value() - (width / min_h))
130
131
        return max_h if max_r < min_r else min_h
132
133
134
class Size:
135
    def __init__(self, width: int, height: int):
136
        """
137
        @TODO: add documentation
138
        """
139
        self.width = width
140
        self.height = height
141
142
    @property
143
    def ratio(self) -> Ratio:
144
        """
145
        @TODO: add documentation
146
        """
147
        return Ratio(self.width, self.height)
148
149
    @property
150
    def normalize(self) -> str:
151
        """
152
        @TODO: add documentation
153
        """
154
        return "{}x{}".format(str(self.width), str(self.height))
155
156
157
__all__ = [
158
    'Size',
159
    'Bitrate'
160
]