Skip to content

Commit 5aad620

Browse files
fixes #46
1 parent 8db0638 commit 5aad620

File tree

2 files changed

+75
-84
lines changed

2 files changed

+75
-84
lines changed

README.md

Lines changed: 19 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -108,14 +108,13 @@ To list the supported, connected capture devices, see **[FFmpeg Capture Webcam](
108108

109109

110110
### DASH
111-
**[Dynamic Adaptive Streaming over HTTP (DASH)](http://dashif.org/)**, also known as MPEG-DASH, is an adaptive bitrate streaming technique that enables high quality streaming of media content over the Internet delivered from conventional HTTP web servers. [Learn more](https://en.wikipedia.org/wiki/Dynamic_Adaptive_Streaming_over_HTTP)
112-
111+
**[Dynamic Adaptive Streaming over HTTP (DASH)](http://dashif.org/)**, also known as MPEG-DASH, is an adaptive bitrate streaming technique that enables high-quality streaming of media content over the Internet delivered from conventional HTTP web servers. [Learn more](https://en.wikipedia.org/wiki/Dynamic_Adaptive_Streaming_over_HTTP)
112+
113113
Create DASH files:
114114
``` php
115115
$video->dash()
116-
->hevc() // Format of the video. Alternatives: x264() and vp9()
116+
->x264() // Format of the video. Alternatives: hevc() and vp9()
117117
->autoGenerateRepresentations() // Auto generate representations
118-
->setAdaption('id=0,streams=v id=1,streams=a') // Set the adaption.
119118
->save(); // It can be passed a path to the method or it can be null
120119
```
121120
Generate representations manually:
@@ -132,16 +131,15 @@ $r_2k = (new Representation)->setKiloBitrate(6144)->setResize(2560, 1440);
132131
$r_4k = (new Representation)->setKiloBitrate(17408)->setResize(3840, 2160);
133132

134133
$video->dash()
135-
->hevc()
134+
->x264()
136135
->addRepresentations([$r_144p, $r_240p, $r_360p, $r_480p, $r_720p, $r_1080p, $r_2k, $r_4k])
137-
->setAdaption('id=0,streams=v id=1,streams=a')
138136
->save('/var/media/dash-stream.mpd');
139137
```
140138
See **[DASH section](https://video.aminyazdanpanah.com/start?r=dash#dash)** in the documentation, for more examples.
141139

142140
### HLS
143-
**[HTTP Live Streaming (also known as HLS)](https://developer.apple.com/streaming/)** is an HTTP-based adaptive bitrate streaming communications protocol implemented by Apple Inc. as part of its QuickTime, Safari, OS X, and iOS software. Client implementations are also available in Microsoft Edge, Firefox and some versions of Google Chrome. Support is widespread in streaming media servers. [Learn more](https://en.wikipedia.org/wiki/HTTP_Live_Streaming)
144-
141+
**[HTTP Live Streaming (also known as HLS)](https://developer.apple.com/streaming/)** is an HTTP-based adaptive bitrate streaming communications protocol implemented by Apple Inc. as part of its QuickTime, Safari, OS X, and iOS software. Client implementations are also available in Microsoft Edge, Firefox, and some versions of Google Chrome. Support is widespread in streaming media servers. [Learn more](https://en.wikipedia.org/wiki/HTTP_Live_Streaming)
142+
145143
Create HLS files:
146144
``` php
147145
$video->hls()
@@ -173,12 +171,12 @@ You must specify a path to save a random key to your local machine and also a UR
173171
The following code generates a key for all segment files.
174172

175173
``` php
176-
//A path you want to save a random key to your server
177-
$save_to = '/home/public_html/"PATH TO THE KEY DIRECTORY"/key';
174+
//A path you want to save a random key to your local machine
175+
$save_to = '/home/public_html/"PATH TO THE KEY DIRECTORY"/key'
178176

179177
//A URL (or a path) to access the key on your website
180-
$url = 'https://www.aminyazdanpanah.com/?"PATH TO THE KEY DIRECTORY"/key';
181-
// or $url = '/PATH TO THE KEY DIRECTORY/key';
178+
$url = 'https://www.aminyazdanpanah.com/?"PATH TO THE KEY DIRECTORY"/key'
179+
// or $url = '/"PATH TO THE KEY DIRECTORY"/key';
182180

183181
$video->hls()
184182
->encryption($save_to, $url)
@@ -192,17 +190,17 @@ An integer as a "key rotation period" can also be passed to the `encryption` met
192190

193191
See **[the example](https://video.aminyazdanpanah.com/start?r=enc-hls#hls-encryption)** for more information.
194192

195-
**IMPORTANT:** It is very important to protect your key(s) on your website. For example, you can check a token(using a Get or Post HTTP method) to access the key(s) on your website. You can also check a session(or cookie) on your website to restrict access to the key(s)(**It is highly recommended**).
193+
**IMPORTANT:** It is very important to protect your key(s) on your website. For example, you can use a token(using a Get or Post HTTP method) to check if the user is eligible to access the key or not. You can also use a session(or cookie) on your website to restrict access to the key(s)(**It is highly recommended**).
196194

197195
##### DRM
198196
However FFmpeg supports AES encryption for HLS packaging, which you can encrypt your content, it is not a full **[DRM](https://en.wikipedia.org/wiki/Digital_rights_management)** solution. If you want to use a full DRM solution, I recommend trying **[FairPlay Streaming](https://developer.apple.com/streaming/fps/)** solution which then securely exchange keys, and protect playback on devices.
199197

200-
**Besides [Apples FairPlay](https://developer.apple.com/streaming/fps/)** DRM system, you can also use other DRM systems such as **[Microsoft's PlayReady](https://www.microsoft.com/playready/overview/)** and **[Googles Widevine](https://www.widevine.com/)**.
198+
**Besides [Apple's FairPlay](https://developer.apple.com/streaming/fps/)** DRM system, you can also use other DRM systems such as **[Microsoft's PlayReady](https://www.microsoft.com/playready/overview/)** and **[Google's Widevine](https://www.widevine.com/)**.
201199

202200
### Transcoding
203201
A format can also extend `FFMpeg\Format\ProgressableInterface` to get realtime information about the transcoding.
204202
``` php
205-
$format = new Streaming\Format\hevc();
203+
$format = new Streaming\Format\X264();
206204
$format->on('progress', function ($video, $format, $percentage){
207205
// You can update a field in your database or can log it to a file
208206
// You can also create a socket connection and show a progress bar to users
@@ -212,7 +210,6 @@ $format->on('progress', function ($video, $format, $percentage){
212210
$video->dash()
213211
->setFormat($format)
214212
->autoGenerateRepresentations()
215-
->setAdaption('id=0,streams=v id=1,streams=a')
216213
->save();
217214
```
218215

@@ -226,9 +223,8 @@ There are several ways to save files.
226223
You can pass a local path to the `save` method. If there was no directory in the path, then the package auto makes the directory.
227224
``` php
228225
$dash = $video->dash()
229-
->hevc()
226+
->x264()
230227
->autoGenerateRepresentations()
231-
->setAdaption('id=0,streams=v id=1,streams=a');
232228

233229
$dash->save('/var/media/dash-stream.mpd');
234230
```
@@ -262,9 +258,7 @@ Visit **[this page](https://video.aminyazdanpanah.com/start/clouds?r=save)** to
262258
<p align="center"><img src="https://github.com/aminyazdanpanah/aminyazdanpanah.github.io/blob/master/video-streaming/video-streaming.gif?raw=true" width="100%"></p>
263259

264260
#### 3. To a Server Instantly
265-
You can pass a url(or a supported resource like `ftp`) to live method to upload all the segments files to the HTTP server(or other protocols) using the HTTP PUT method, and update the manifest files every refresh times.
266-
267-
If you want to save stream files to your local machine, use the `save` method.
261+
You can pass a URL(or a supported resource like `FTP`) to live method to upload all the segments files to the HTTP server(or other protocols) using the HTTP PUT method and update the manifest files every refresh times.
268262

269263
``` php
270264
// DASH
@@ -357,12 +351,12 @@ This method has a third optional boolean parameter, which is the duration of the
357351
To see more examples, visit the **[PHP-FFMpeg Documentation](https://github.com/PHP-FFMpeg/PHP-FFMpeg)** page.
358352

359353
## Asynchronous Task Execution
360-
Packaging process might take a while and it is recommended to run it in the background(or in a cloud e.g. AWS). There are some libraries that you can use for this use case.
354+
The packaging process might take a while and it is recommended to run it in the background(or in a cloud e.g. AWS). There are some libraries that you can use for this use case.
361355
- **[Symphony(The Console Component)](https://github.com/symfony/console):** You can use this library to create command-line commands. Your console commands can be used for any recurring task, such as cronjobs, imports, or other batch jobs. [Learn more](https://symfony.com/doc/current/components/console.html#learn-more)
362356

363357
- **[Laravel(Queues)](https://github.com/illuminate/queue):** If you are using Laravel for development, Laravel Queues is a wonderful tool for this use case. It allows you to create a job and dispatch it. [Learn more](https://laravel.com/docs/7.x/queues)
364358

365-
**NOTE:** You can also create a script to create packaged video files and create your own crontab file to run the script.
359+
**NOTE:** You can also create a script and run it in your cronjob.
366360

367361
## Several Open Source Players
368362
You can use these libraries to play your streams.
@@ -394,9 +388,9 @@ You can use these libraries to play your streams.
394388

395389
**NOTE-1:** You must pass a **link of the master playlist(manifest)**(i.e. `https://www.aminyazdanpanah.com/?"PATH TO STREAM DIRECTORY"/dash-stream.mpd` or `/PATH_TO_STREAM_DIRECTORY/hls-stream.m3u8` ) to these players.
396390

397-
**NOTE-2:** If you save your stream to a cloud(i.e. **[Amazon S3](https://aws.amazon.com/s3)**), the link of your playlist and also other content **MUST BE PUBLIC**.
391+
**NOTE-2:** If you save your stream content to a cloud(i.e. **[Amazon S3](https://aws.amazon.com/s3)**), the link of your playlist and other content **MUST BE PUBLIC**.
398392

399-
**NOTE-3:** As you may know, **[IOS](https://www.apple.com/ios)** does not have native support for DASH. Although there are some libraries such as **[Viblast](https://github.com/Viblast/ios-player-sdk)** and **[MPEGDASH-iOS-Player](https://github.com/MPEGDASHPlayer/MPEGDASH-iOS-Player)** to support this technique, I have never tested them. So maybe som of them will not work correctly.
393+
**NOTE-3:** As you may know, **[IOS](https://www.apple.com/ios)** does not have native support for DASH. Although there are some libraries such as **[Viblast](https://github.com/Viblast/ios-player-sdk)** and **[MPEGDASH-iOS-Player](https://github.com/MPEGDASHPlayer/MPEGDASH-iOS-Player)** to support this technique, I have never tested them. So maybe some of them will not work properly.
400394

401395

402396
## Contributing and Reporting Bugs

src/Filters/DASHFilter.php

Lines changed: 56 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -17,99 +17,96 @@
1717
use Streaming\Representation;
1818
use Streaming\Utiles;
1919

20-
class DASHFilter extends StreamFilter
20+
class DASHFilter extends FormatFilter
2121
{
2222
/** @var \Streaming\DASH */
2323
private $dash;
2424

2525
/**
26-
* @param StreamInterface $stream
26+
* @param Representation $rep
27+
* @param int $key
28+
* @return array
2729
*/
28-
public function streamFilter(StreamInterface $stream): void
30+
private function getAudioBitrate(Representation $rep, int $key): array
2931
{
30-
$this->dash = $stream;
31-
$this->set();
32+
return $rep->getAudioKiloBitrate() ? ["-b:a:" . $key, $rep->getAudioKiloBitrate() . "k"] : [];
3233
}
3334

3435
/**
3536
* @return array
36-
* @TODO: optimize this function
3737
*/
38-
private function set()
38+
private function streams(): array
3939
{
40-
$this->filter = $this->getBaseFilters();
41-
42-
foreach ($this->dash->getRepresentations() as $key => $representation) {
43-
$this->filter[] = "-map";
44-
$this->filter[] = "0";
45-
$this->filter[] = "-b:v:" . $key;
46-
$this->filter[] = $representation->getKiloBitrate() . "k";
47-
$this->filter = array_merge($this->filter, $this->getAudioBitrate($representation, $key));
48-
49-
if (null !== $representation->size2string()) {
50-
$this->filter[] = "-s:v:" . $key;
51-
$this->filter[] = $representation->size2string();
52-
}
40+
$streams = [];
41+
foreach ($this->dash->getRepresentations() as $key => $rep) {
42+
$streams = array_merge(
43+
$streams,
44+
Utiles::arrayToFFmpegOpt([
45+
'map' => 0,
46+
"s:v:$key" => $rep->size2string(),
47+
"b:v:$key" => $rep->getKiloBitrate() . "k"
48+
]),
49+
$this->getAudioBitrate($rep, $key)
50+
);
5351
}
54-
$this->filter = array_merge($this->filter, $this->getFormats());
5552

56-
if ($this->dash->getAdaption()) {
57-
$this->filter[] = "-adaptation_sets";
58-
$this->filter[] = $this->dash->getAdaption();
59-
}
60-
$this->filter = array_merge(
61-
$this->filter,
62-
Utiles::arrayToFFmpegOpt($this->dash->getAdditionalParams()),
63-
["-strict", $this->dash->getStrict()]
64-
);
53+
return $streams;
54+
}
6555

66-
return $this->filter;
56+
/**
57+
* @return array
58+
*/
59+
private function getAdaptions(): array
60+
{
61+
return $this->dash->getAdaption() ? ['-adaptation_sets', $this->dash->getAdaption()] : [];
6762
}
6863

6964
/**
7065
* @return array
7166
*/
72-
private function getBaseFilters(): array
67+
private function init(): array
7368
{
74-
$filename = $this->dash->pathInfo(PATHINFO_FILENAME);
75-
76-
$this->filter = [
77-
"-bf", "1",
78-
"-keyint_min", "120",
79-
"-g", "120",
80-
"-sc_threshold", "0",
81-
"-b_strategy", "0",
82-
"-use_timeline", "1",
83-
"-use_template", "1",
84-
"-init_seg_name", ($filename . '_init_$RepresentationID$.$ext$'),
85-
"-media_seg_name", ($filename . '_chunk_$RepresentationID$_$Number%05d$.$ext$'),
86-
"-seg_duration", $this->dash->getSegDuration(),
87-
"-hls_playlist", (int)$this->dash->isGenerateHlsPlaylist(),
88-
"-f", "dash",
69+
$name = $this->dash->pathInfo(PATHINFO_FILENAME);
70+
71+
$init = [
72+
"use_timeline" => 1,
73+
"use_template" => 1,
74+
"init_seg_name" => $name . '_init_$RepresentationID$.$ext$',
75+
"media_seg_name" => $name . '_chunk_$RepresentationID$_$Number%05d$.$ext$',
76+
"seg_duration" => $this->dash->getSegDuration(),
77+
"hls_playlist" => (int)$this->dash->isGenerateHlsPlaylist(),
78+
"f" => "dash",
8979
];
9080

91-
return $this->filter;
81+
return array_merge(
82+
Utiles::arrayToFFmpegOpt($init),
83+
$this->getAdaptions(),
84+
Utiles::arrayToFFmpegOpt($this->dash->getAdditionalParams())
85+
);
9286
}
9387

9488
/**
9589
* @return array
9690
*/
97-
private function getFormats(): array
91+
private function getArgs(): array
9892
{
99-
$format = ['-c:v', $this->dash->getFormat()->getVideoCodec()];
100-
$audio_format = $this->dash->getFormat()->getAudioCodec();
101-
102-
return $audio_format ? array_merge($format, ['-c:a', $audio_format]) : $format;
93+
return array_merge(
94+
$this->init(),
95+
$this->streams(),
96+
['-strict', $this->dash->getStrict()]
97+
);
10398
}
10499

105-
106100
/**
107-
* @param Representation $rep
108-
* @param int $key
109-
* @return array
101+
* @param StreamInterface $dash
110102
*/
111-
private function getAudioBitrate(Representation $rep, int $key): array
103+
public function streamFilter(StreamInterface $dash): void
112104
{
113-
return $rep->getAudioKiloBitrate() ? ["-b:a:" . $key, $rep->getAudioKiloBitrate() . "k"] : [];
105+
$this->dash = $dash;
106+
107+
$this->filter = array_merge(
108+
$this->getFormatOptions($dash->getFormat()),
109+
$this->getArgs()
110+
);
114111
}
115112
}

0 commit comments

Comments
 (0)