1 | """ |
||
2 | ffmpeg_streaming.media |
||
3 | ~~~~~~~~~~~~ |
||
4 | |||
5 | Auto Generate Representation and Representation Object |
||
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 | from ._format import Format |
||
14 | from ._media_property import Size, Bitrate |
||
15 | |||
16 | MINIMUM_BITRATE = 65536 |
||
17 | |||
18 | |||
19 | class Representation: |
||
20 | def __init__(self, size: Size, bitrate: Bitrate): |
||
21 | """ |
||
22 | @TODO: add documentation |
||
23 | """ |
||
24 | self.size = size |
||
25 | self.bitrate = bitrate |
||
26 | |||
27 | |||
28 | def min_bitrate(bitrate: int) -> int: |
||
29 | """ |
||
30 | @TODO: add documentation |
||
31 | """ |
||
32 | if bitrate < MINIMUM_BITRATE: |
||
33 | return MINIMUM_BITRATE |
||
34 | |||
35 | return bitrate |
||
36 | |||
37 | |||
38 | def reduce_bitrate(bitrate: Bitrate, divide: int) -> Bitrate: |
||
39 | """ |
||
40 | @TODO: add documentation |
||
41 | """ |
||
42 | if divide == 1: |
||
43 | return bitrate |
||
44 | |||
45 | divide = 1 + divide / 2 |
||
46 | |||
47 | overall = min_bitrate(int(bitrate.overall_ / divide)) |
||
48 | video = min_bitrate(int(bitrate.video_ / divide)) if bitrate.video_ is not None and bitrate.video_ != 0 else None |
||
49 | audio = min_bitrate(int(bitrate.audio_ / divide)) if bitrate.audio_ is not None and bitrate.audio_ != 0 else None |
||
50 | |||
51 | return Bitrate(video, audio, overall) |
||
52 | |||
53 | |||
54 | def cal_bitrate(bitrate, org_bitrate: Bitrate, index: int) -> Bitrate: |
||
55 | return bitrate[index - 1] if bitrate is not None else reduce_bitrate(org_bitrate, index) |
||
56 | |||
57 | |||
58 | class AutoRep(object): |
||
59 | def __init__(self, original_size: Size, original_bitrate: Bitrate, _format: Format, heights: list = None, bitrate: list = None): |
||
60 | """ |
||
61 | @TODO: add documentation |
||
62 | """ |
||
63 | self.original_bitrate = original_bitrate |
||
64 | self.original_size = original_size |
||
65 | self._format = _format |
||
66 | self.heights = heights if heights is not None else [2160, 1440, 1080, 720, 480, 360, 240, 144] |
||
67 | self.bitrate = bitrate |
||
68 | self.is_default = True if heights is not None and bitrate is not None else False |
||
69 | |||
70 | if heights is not None and bitrate is not None and len(heights) != len(bitrate): |
||
71 | raise ValueError("The length of heights list must the same as length of bitrate") |
||
72 | |||
73 | def __iter__(self): |
||
74 | """ |
||
75 | @TODO: add documentation |
||
76 | """ |
||
77 | if not self.is_default: |
||
78 | height = self.original_size.ratio.calculate_height(self.original_size.width, self._format.multiply()) |
||
79 | self.heights = [height] + list(filter(lambda x: x < height, self.heights)) |
||
0 ignored issues
–
show
introduced
by
Loading history...
|
|||
80 | |||
81 | self.index = 0 |
||
82 | |||
83 | return self |
||
84 | |||
85 | def __next__(self): |
||
86 | """ |
||
87 | @TODO: add documentation |
||
88 | """ |
||
89 | if self.index < len(self.heights): |
||
90 | height = self.heights[self.index] |
||
91 | width = self.original_size.ratio.calculate_width(height, self._format.multiply()) |
||
92 | self.index += 1 |
||
93 | |||
94 | return Representation(Size(width, height), cal_bitrate(self.bitrate, self.original_bitrate, self.index)) |
||
95 | else: |
||
96 | raise StopIteration |
||
97 | |||
98 | |||
99 | __all__ = [ |
||
100 | 'Representation' |
||
101 | ] |
||
102 |