1 | <?php |
||||||||||
2 | |||||||||||
3 | /** |
||||||||||
4 | * This file is part of the PHP-FFmpeg-video-streaming package. |
||||||||||
5 | * |
||||||||||
6 | * (c) Amin Yazdanpanah <[email protected]> |
||||||||||
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 | |||||||||||
15 | use FFMpeg\Exception\ExceptionInterface; |
||||||||||
16 | |||||||||||
17 | class HLSPlaylist |
||||||||||
18 | { |
||||||||||
19 | /** @var HLS */ |
||||||||||
20 | private $hls; |
||||||||||
21 | |||||||||||
22 | private const DEFAULT_AUDIO_BITRATE = 0; //131072; |
||||||||||
23 | |||||||||||
24 | /** |
||||||||||
25 | * HLSPlaylist constructor. |
||||||||||
26 | * @param HLS $hls |
||||||||||
27 | */ |
||||||||||
28 | public function __construct(HLS $hls) |
||||||||||
29 | { |
||||||||||
30 | $this->hls = $hls; |
||||||||||
31 | } |
||||||||||
32 | |||||||||||
33 | /** |
||||||||||
34 | * @param Representation $rep |
||||||||||
35 | * @return string |
||||||||||
36 | */ |
||||||||||
37 | private function segmentPath(Representation $rep): string |
||||||||||
38 | { |
||||||||||
39 | return $this->hls->pathInfo(PATHINFO_FILENAME) . "_" . $rep->getHeight() . "p.m3u8"; |
||||||||||
40 | } |
||||||||||
41 | |||||||||||
42 | /** |
||||||||||
43 | * @param Representation $rep |
||||||||||
44 | * @return string |
||||||||||
45 | */ |
||||||||||
46 | private function streamInfo(Representation $rep): string |
||||||||||
47 | { |
||||||||||
48 | $tag = '#EXT-X-STREAM-INF:'; |
||||||||||
49 | $params = array_merge( |
||||||||||
50 | [ |
||||||||||
51 | "BANDWIDTH" => $rep->getKiloBitrate() * 1024 + $this->getAudioBitrate($rep), |
||||||||||
52 | "RESOLUTION" => $rep->size2string(), |
||||||||||
53 | "NAME" => "\"" . $rep->getHeight() . "\"" |
||||||||||
54 | ], |
||||||||||
55 | $rep->getHlsStreamInfo() |
||||||||||
56 | ); |
||||||||||
57 | Utiles::concatKeyValue($params, "="); |
||||||||||
58 | |||||||||||
59 | return $tag . implode(",", $params); |
||||||||||
60 | } |
||||||||||
61 | |||||||||||
62 | /** |
||||||||||
63 | * @return string |
||||||||||
64 | */ |
||||||||||
65 | private function getVersion(): string |
||||||||||
66 | { |
||||||||||
67 | $version = $this->hls->getHlsSegmentType() === "fmp4" ? 7 : 3; |
||||||||||
68 | return "#EXT-X-VERSION:" . $version; |
||||||||||
69 | } |
||||||||||
70 | |||||||||||
71 | /** |
||||||||||
72 | * @param array $description |
||||||||||
73 | * @return string |
||||||||||
74 | */ |
||||||||||
75 | private function contents(array $description): string |
||||||||||
76 | { |
||||||||||
77 | $content = array_merge(["#EXTM3U", $this->getVersion()], $description); |
||||||||||
78 | |||||||||||
79 | foreach ($this->hls->getRepresentations() as $rep) { |
||||||||||
80 | array_push($content, $this->streamInfo($rep), $this->segmentPath($rep)); |
||||||||||
81 | } |
||||||||||
82 | |||||||||||
83 | return implode(PHP_EOL, $content); |
||||||||||
84 | } |
||||||||||
85 | |||||||||||
86 | /** |
||||||||||
87 | * @param string $filename |
||||||||||
88 | * @param array $description |
||||||||||
89 | */ |
||||||||||
90 | public function save(string $filename, array $description): void |
||||||||||
91 | { |
||||||||||
92 | File::put($filename, $this->contents(($description))); |
||||||||||
93 | } |
||||||||||
94 | |||||||||||
95 | /** |
||||||||||
96 | * @param Representation $rep |
||||||||||
97 | * @return int |
||||||||||
98 | */ |
||||||||||
99 | private function getAudioBitrate(Representation $rep): int |
||||||||||
100 | { |
||||||||||
101 | return $rep->getAudioKiloBitrate() ? $rep->getAudioKiloBitrate() * 1024 : $this->getOriginalAudioBitrate(); |
||||||||||
102 | } |
||||||||||
103 | |||||||||||
104 | /** |
||||||||||
105 | * @return int |
||||||||||
106 | */ |
||||||||||
107 | private function getOriginalAudioBitrate(): int |
||||||||||
108 | { |
||||||||||
109 | try { |
||||||||||
110 | $audios = $this->hls->getMedia()->getStreams()->audios(); |
||||||||||
0 ignored issues
–
show
The method
getStreams() does not exist on Streaming\Media . Since you implemented __call , consider adding a @method annotation.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() The method
audios() does not exist on Streaming\Media . Since you implemented __call , consider adding a @method annotation.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||||||
111 | |||||||||||
112 | if (!$audios->count()){ |
||||||||||
0 ignored issues
–
show
The method
count() does not exist on Streaming\Media . Since you implemented __call , consider adding a @method annotation.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() The method
count() does not exist on FFMpeg\Media\Video .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces. This is most likely a typographical error or the method has been renamed. ![]() |
|||||||||||
113 | return static::DEFAULT_AUDIO_BITRATE; |
||||||||||
114 | } |
||||||||||
115 | |||||||||||
116 | return $audios->first()->get('bit_rate', static::DEFAULT_AUDIO_BITRATE); |
||||||||||
0 ignored issues
–
show
The method
get() does not exist on Streaming\Media . Since you implemented __call , consider adding a @method annotation.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() The method
first() does not exist on FFMpeg\Media\Video .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces. This is most likely a typographical error or the method has been renamed. ![]() The method
get() does not exist on FFMpeg\Media\Video .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces. This is most likely a typographical error or the method has been renamed. ![]() The method
first() does not exist on Streaming\Media . Since you implemented __call , consider adding a @method annotation.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||||||
117 | } catch (ExceptionInterface $e) { |
||||||||||
118 | return static::DEFAULT_AUDIO_BITRATE; |
||||||||||
119 | } |
||||||||||
120 | } |
||||||||||
121 | } |
This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.
This is most likely a typographical error or the method has been renamed.