Skip to content

Commit b23da58

Browse files
v1.2
bug fixes #34
1 parent ac0e9df commit b23da58

29 files changed

+705
-312
lines changed

src/AutoRepresentations.php

Lines changed: 0 additions & 159 deletions
This file was deleted.

src/AutoReps.php

Lines changed: 236 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,236 @@
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

Comments
 (0)