Passed
Push — master ( 7bc1c2...5b857f )
by Amin
03:31
created

ffmpeg_streaming._media_property.Ratio.__init__()   A

Complexity

Conditions 1

Size

Total Lines 3
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 3
nop 3
dl 0
loc 3
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 = .8
16
MAX_RATE_COEFFICIENT = 1.2
17
18
19
def cnv_bitrate(bitrate: int, _type: str) -> str:
20
    if _type == "k":
21
        bitrate = round(bitrate / 1024)
22
    elif _type == "m":
23
        bitrate = round(bitrate / 1024 * 1024)
24
    else:
25
        raise ValueError("Unknown type!")
26
27
    return str(bitrate) + _type
28
29
30
class Bitrate:
31
    def __init__(self, video: int = None, audio: int = None, overall: int = None, **kwargs):
32
        if video is None and overall is None:
33
            raise ValueError("You must at least specify value of the video or overall format")
34
        self.overall_ = overall
35
        self.video_ = video
36
        self.audio_ = audio
37
        self.type = kwargs.pop("type", "k")
38
39
    @property
40
    def overall(self):
41
        return cnv_bitrate(self.overall_, self.type) if self.overall_ is not None else None
42
43
    @property
44
    def video(self):
45
        return cnv_bitrate(self.video_, self.type) if self.video_ is not None else None
46
47
    @property
48
    def audio(self):
49
        return cnv_bitrate(self.audio_, self.type) if self.audio_ is not None else 'copy'
50
51
    def normalize_video(self, convert: bool = True):
52
        if self.video_ is not None and self.video_ != 0:
53
            val = self.video_
54
        else:
55
            val = int(self.overall_ * OVERALL_TO_VIDEO_COEFFICIENT)
56
57
        return cnv_bitrate(val, self.type) if convert else val
58
59
    @property
60
    def max_rate(self):
61
        return cnv_bitrate(int(self.normalize_video(False) * MAX_RATE_COEFFICIENT), self.type)
62
63
64
def multiple_up(value, multiple):
65
    while 0 != value % multiple:
66
        value += 1
67
68
    return value
69
70
71
def multiple_down(value, multiple):
72
    while 0 != value % multiple:
73
        value -= 1
74
75
    return value
76
77
78
class Ratio:
79
    def __init__(self, width: int, height: int):
80
        self.width = width
81
        self.height = height
82
83
    def get_value(self) -> float:
84
        return self.width / self.height
85
86
    def calculate_width(self, height: int, multiple: int = 1) -> int:
87
        max_w = multiple_up(math.ceil(self.get_value() * height), multiple)
88
        min_w = multiple_down(math.floor(self.get_value() * height), multiple)
89
90
        max_r = abs(self.get_value() - (max_w / height))
91
        min_r = abs(self.get_value() - (min_w / height))
92
93
        return max_w if max_r < min_r else min_w
94
95
    def calculate_height(self, width: int, multiple: int = 1) -> int:
96
        max_h = multiple_up(math.ceil(width / self.get_value()), multiple)
97
        min_h = multiple_down(math.floor(width / self.get_value()), multiple)
98
99
        max_r = abs(self.get_value() - (width / max_h))
100
        min_r = abs(self.get_value() - (width / min_h))
101
102
        return max_h if max_r < min_r else min_h
103
104
105
class Size:
106
    def __init__(self, width: int, height: int):
107
        self.width = width
108
        self.height = height
109
110
    @property
111
    def ratio(self) -> Ratio:
112
        return Ratio(self.width, self.height)
113
114
    @property
115
    def normalize(self) -> str:
116
        return str(self.width) + "x" + str(self.height)
117
118
119
__all__ = [
120
    'Size',
121
    'Bitrate'
122
]