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, **options): |
||
21 | """ |
||
22 | @TODO: add documentation |
||
23 | """ |
||
24 | self.size = size |
||
25 | self.bitrate = bitrate |
||
26 | self.options = options |
||
27 | |||
28 | |||
29 | def min_bitrate(bitrate: int) -> int: |
||
30 | """ |
||
31 | @TODO: add documentation |
||
32 | """ |
||
33 | return max(bitrate, MINIMUM_BITRATE) |
||
34 | |||
35 | |||
36 | def reduce_bitrate(bitrate: Bitrate, divide: int) -> Bitrate: |
||
37 | """ |
||
38 | @TODO: add documentation |
||
39 | """ |
||
40 | if divide == 1: |
||
41 | return bitrate |
||
42 | |||
43 | divide = 1 + divide / 2 |
||
44 | |||
45 | overall = min_bitrate(int(bitrate.overall_ / divide)) |
||
46 | video = min_bitrate(int(bitrate.video_ / divide)) if bitrate.video_ is not None and bitrate.video_ != 0 else None |
||
47 | audio = min_bitrate(int(bitrate.audio_ / divide)) if bitrate.audio_ is not None and bitrate.audio_ != 0 else None |
||
48 | |||
49 | return Bitrate(video, audio, overall) |
||
50 | |||
51 | |||
52 | def cal_bitrate(bitrate, org_bitrate: Bitrate, index: int) -> Bitrate: |
||
53 | return bitrate[index - 1] if bitrate is not None else reduce_bitrate(org_bitrate, index) |
||
54 | |||
55 | |||
56 | class AutoRep(object): |
||
57 | def __init__(self, original_size: Size, original_bitrate: Bitrate, _format: Format, |
||
58 | heights: list = None, bitrate: list = None, include_original: bool = True): |
||
59 | """ |
||
60 | @TODO: add documentation |
||
61 | """ |
||
62 | self.include_original = include_original |
||
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 = heights is not None and bitrate is not None |
||
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 | original = [height] if self.include_original else [] |
||
80 | self.heights = original + list(filter(lambda x: x < height, self.heights)) |
||
0 ignored issues
–
show
introduced
by
![]() |
|||
81 | |||
82 | self.index = 0 |
||
83 | |||
84 | return self |
||
85 | |||
86 | def __next__(self): |
||
87 | """ |
||
88 | @TODO: add documentation |
||
89 | """ |
||
90 | if self.index >= len(self.heights): |
||
91 | raise StopIteration |
||
92 | height = self.heights[self.index] |
||
93 | width = self.original_size.ratio.calculate_width(height, self._format.multiply()) |
||
94 | self.index += 1 |
||
95 | |||
96 | return Representation(Size(width, height), cal_bitrate(self.bitrate, self.original_bitrate, self.index)) |
||
97 | |||
98 | |||
99 | __all__ = [ |
||
100 | 'Representation' |
||
101 | ] |
||
102 |