1
+ <?php
2
+
3
+ /**
4
+ * This file is part of the PHP-FFmpeg-video-streaming package.
5
+ *
6
+ * (c) Amin Yazdanpanah <contact@aminyazdanpanah.com>
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ namespace Streaming ;
13
+
14
+ use FFMpeg \Coordinate \Dimension ;
15
+ use FFMpeg \Exception \ExceptionInterface ;
16
+ use Streaming \Exception \InvalidArgumentException ;
17
+ use Streaming \Exception \RuntimeException ;
18
+ use Streaming \Format \VideoInterface ;
19
+
20
+
21
+ class AutoReps implements \IteratorAggregate
22
+ {
23
+ /** @var \FFMpeg\FFProbe\DataMapping\Stream $video */
24
+ private $ video ;
25
+
26
+ /** @var \FFMpeg\FFProbe\DataMapping\Format $format */
27
+ private $ original_format ;
28
+
29
+ /**
30
+ * regular video's heights
31
+ *
32
+ * @var array side_values
33
+ */
34
+ private $ sides = [144 , 240 , 360 , 480 , 720 , 1080 , 1440 , 2160 ];
35
+
36
+ /** @var array $k_bitrate */
37
+ private $ k_bitrate ;
38
+
39
+ /** @var string */
40
+ private $ sort = "asc " ;
41
+
42
+ /** @const VideoInterface */
43
+ private $ format ;
44
+
45
+ /**
46
+ * AutoReps constructor.
47
+ * @param Media $media
48
+ * @param VideoInterface $format
49
+ * @param array|null $sides
50
+ * @param array|null $k_bitrate
51
+ */
52
+ public function __construct (Media $ media , VideoInterface $ format , array $ sides = null , array $ k_bitrate = null )
53
+ {
54
+ $ this ->format = $ format ;
55
+ $ this ->video = $ media ->getStreams ()->videos ()->first ();
56
+ $ this ->original_format = $ media ->getFormat ();
57
+ $ this ->sides ($ sides , $ k_bitrate );
58
+ $ this ->kiloBitrate ($ k_bitrate );
59
+ }
60
+
61
+ /**
62
+ * Set sort order for reps
63
+ * @param string $sort
64
+ */
65
+ public function sort (string $ sort )
66
+ {
67
+ $ this ->sort = $ sort ;
68
+ }
69
+
70
+ /**
71
+ * @return Dimension
72
+ */
73
+ private function getDimensions (): Dimension
74
+ {
75
+ try {
76
+ return $ this ->video ->getDimensions ();
77
+ } catch (ExceptionInterface $ e ) {
78
+ throw new RuntimeException ("Unable to extract dimensions.: " . $ e ->getMessage (), $ e ->getCode (), $ e );
79
+ }
80
+ }
81
+
82
+ /**
83
+ * @return mixed
84
+ * @throws InvalidArgumentException
85
+ */
86
+ private function getKiloBitRate (): int
87
+ {
88
+ if (!$ this ->video ->has ('bit_rate ' )) {
89
+ if (!$ this ->original_format ->has ('bit_rate ' )) {
90
+ throw new InvalidArgumentException ("Unable to extract bitrate. " );
91
+ }
92
+
93
+ return intval (($ this ->original_format ->get ('bit_rate ' ) / 1024 ) * .9 );
94
+ }
95
+
96
+ return (int )$ this ->video ->get ('bit_rate ' ) / 1024 ;
97
+ }
98
+
99
+ /**
100
+ * @param array|null $k_bitrate_values
101
+ */
102
+ private function kiloBitrate (?array $ k_bitrate_values ): void
103
+ {
104
+ $ k_bit_rates = [];
105
+ $ count_sides = count ($ this ->sides );
106
+
107
+ if (!is_null ($ k_bitrate_values )) {
108
+ if ($ count_sides !== count ($ k_bitrate_values )) {
109
+ throw new InvalidArgumentException ("The count of side value array must be the same as the count of kilo bitrate array " );
110
+ }
111
+ $ this ->k_bitrate = $ k_bitrate_values ;
112
+ return ;
113
+ }
114
+
115
+ $ k_bitrate_value = $ this ->getKiloBitRate ();
116
+ $ divided_by = 1.5 ;
117
+
118
+ while ($ count_sides ) {
119
+ $ k_bit_rates [] = (($ k_bitrate = intval ($ k_bitrate_value / $ divided_by )) < 64 ) ? 64 : $ k_bitrate ;
120
+ $ divided_by += .5 ;
121
+ $ count_sides --;
122
+ }
123
+
124
+ $ this ->k_bitrate = array_reverse ($ k_bit_rates );
125
+ }
126
+
127
+ /**
128
+ * @param int $height
129
+ * @return bool
130
+ */
131
+ private function sideFilter (int $ height ): bool
132
+ {
133
+ return $ height < $ this ->getDimensions ()->getHeight ();
134
+ }
135
+
136
+ /**
137
+ * @param array|null $sides
138
+ * @param array|null $k_bitrate
139
+ */
140
+ private function sides (?array $ sides , ?array $ k_bitrate ): void
141
+ {
142
+ if (!is_null ($ sides ) && is_null ($ k_bitrate )) {
143
+ sort ($ sides );
144
+ }
145
+
146
+ $ this ->sides = array_values (array_filter ($ sides ?? $ this ->sides , [$ this , 'sideFilter ' ]));
147
+ }
148
+
149
+ /**
150
+ * @param int $height
151
+ * @return int
152
+ */
153
+ private function computeWidth (int $ height ): int
154
+ {
155
+ return $ this ->getDimensions ()->getRatio ()->calculateWidth ($ height , $ this ->format ->getModulus ());
156
+ }
157
+
158
+ /**
159
+ * @param $width
160
+ * @param $k_bitrate
161
+ * @param $height
162
+ * @return Representation
163
+ * @throws InvalidArgumentException
164
+ */
165
+ private function addRep ($ k_bitrate , $ width , $ height ): Representation
166
+ {
167
+ return (new Representation )->setKiloBitrate ($ k_bitrate )->setResize ($ width , $ height );
168
+ }
169
+
170
+ /**
171
+ * @param array $reps
172
+ */
173
+ private function sortReps (array &$ reps ): void
174
+ {
175
+ usort ($ reps , function (Representation $ rep1 , Representation $ rep2 ) {
176
+ $ ascending = $ rep1 ->getKiloBitrate () > $ rep2 ->getKiloBitrate ();
177
+ return $ this ->sort === "asc " ? $ ascending : !$ ascending ;
178
+ });
179
+ }
180
+
181
+ /**
182
+ * @param bool $sort
183
+ * @return array
184
+ */
185
+ public function getCalculatedReps (bool $ sort = false ): array
186
+ {
187
+ $ reps = [];
188
+ foreach ($ this ->sides as $ key => $ height ) {
189
+ array_push ($ reps , $ this ->addRep ($ this ->k_bitrate [$ key ], $ this ->computeWidth ($ height ), $ height ));
190
+ }
191
+
192
+ if ($ sort ) {
193
+ $ this ->sortReps ($ reps );
194
+ }
195
+
196
+ return $ reps ;
197
+ }
198
+
199
+ /**
200
+ * @return Representation
201
+ */
202
+ public function getOriginalRep (): Representation
203
+ {
204
+ $ dimension = $ this ->getDimensions ();
205
+ return $ this ->addRep ($ this ->getKiloBitRate (), $ dimension ->getWidth (), $ dimension ->getHeight ());
206
+ }
207
+
208
+ /**
209
+ * @return array
210
+ */
211
+ public function getSides (): array
212
+ {
213
+ return $ this ->sides ;
214
+ }
215
+
216
+ /**
217
+ * @return array
218
+ */
219
+ public function getKBitrate (): array
220
+ {
221
+ return $ this ->k_bitrate ;
222
+ }
223
+
224
+ /**
225
+ * Retrieve an external iterator reps
226
+ * @return \Traversable An instance of an object implementing <b>Iterator</b> or <b>Traversable</b>
227
+ */
228
+ public function getIterator ()
229
+ {
230
+ $ reps = $ this ->getCalculatedReps ();
231
+ array_push ($ reps , $ this ->getOriginalRep ());
232
+ $ this ->sortReps ($ reps );
233
+
234
+ return new \ArrayIterator ($ reps );
235
+ }
236
+ }
0 commit comments