aminyazdanpanah /
PHP-FFmpeg-video-streaming
| 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
Loading history...
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
Loading history...
|
|||||||||||
| 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
Loading history...
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. Loading history...
|
|||||||||||
| 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
Loading history...
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. Loading history...
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. Loading history...
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
Loading history...
|
|||||||||||
| 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.