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
|
|
|
use FFMpeg\Exception\ExceptionInterface; |
15
|
|
|
use Streaming\Clouds\AWS; |
16
|
|
|
use Streaming\Clouds\Cloud; |
17
|
|
|
use Streaming\Clouds\CloudInterface; |
18
|
|
|
use Streaming\Clouds\GoogleCloudStorage; |
19
|
|
|
use Streaming\Clouds\MicrosoftAzure; |
20
|
|
|
use Streaming\Exception\Exception; |
21
|
|
|
use Streaming\Exception\InvalidArgumentException; |
22
|
|
|
use Streaming\Exception\RuntimeException; |
23
|
|
|
use Streaming\Filters\Filter; |
24
|
|
|
use Streaming\Traits\Formats; |
25
|
|
|
|
26
|
|
|
abstract class Export |
27
|
|
|
{ |
28
|
|
|
use Formats; |
29
|
|
|
|
30
|
|
|
/** @var object */ |
31
|
|
|
protected $media; |
32
|
|
|
|
33
|
|
|
/** @var array */ |
34
|
|
|
protected $path_info; |
35
|
|
|
|
36
|
|
|
/** @var string */ |
37
|
|
|
protected $strict = "-2"; |
38
|
|
|
|
39
|
|
|
/** @var string */ |
40
|
|
|
protected $tmp_dir; |
41
|
|
|
|
42
|
|
|
/** |
43
|
|
|
* Export constructor. |
44
|
|
|
* @param Media $media |
45
|
|
|
*/ |
46
|
|
|
public function __construct(Media $media) |
47
|
|
|
{ |
48
|
|
|
$this->media = $media; |
49
|
|
|
$this->path_info = pathinfo($media->getPath()); |
50
|
|
|
} |
51
|
|
|
|
52
|
|
|
/** |
53
|
|
|
* @param string $path |
54
|
|
|
* @param array $clouds |
55
|
|
|
* @param bool $metadata |
56
|
|
|
* @return mixed |
57
|
|
|
* @throws Exception |
58
|
|
|
*/ |
59
|
|
|
public function save(string $path = null, array $clouds = [], bool $metadata = true) |
60
|
|
|
{ |
61
|
|
|
$save_to = $this->getPath($path, $clouds); |
62
|
|
|
|
63
|
|
|
try { |
64
|
|
|
$this->media |
65
|
|
|
->addFilter($this->getFilter()) |
66
|
|
|
->save($this->getFormat(), $save_to); |
67
|
|
|
} catch (ExceptionInterface $e) { |
68
|
|
|
throw new RuntimeException(sprintf("There was an error saving files: \n\n reason: \n %s", $e->getMessage()), |
69
|
|
|
$e->getCode(), |
70
|
|
|
$e |
71
|
|
|
); |
72
|
|
|
} |
73
|
|
|
|
74
|
|
|
$this->saveToClouds($clouds); |
75
|
|
|
$this->moveTmpFolder($path); |
76
|
|
|
|
77
|
|
|
return ($metadata) ? (new Metadata($this))->extract() : $this; |
78
|
|
|
} |
79
|
|
|
|
80
|
|
|
/** |
81
|
|
|
* @return Filter |
82
|
|
|
*/ |
83
|
|
|
abstract protected function getFilter(): Filter; |
84
|
|
|
|
85
|
|
|
/** |
86
|
|
|
* @param $path |
87
|
|
|
* @param $clouds |
88
|
|
|
* @return string |
89
|
|
|
* @throws Exception |
90
|
|
|
*/ |
91
|
|
|
private function getPath($path, $clouds): string |
92
|
|
|
{ |
93
|
|
|
if (null !== $path) { |
94
|
|
|
$this->path_info = pathinfo($path); |
95
|
|
|
} |
96
|
|
|
|
97
|
|
|
if ($clouds) { |
98
|
|
|
$this->tmpDirectory($path); |
99
|
|
|
} |
100
|
|
|
|
101
|
|
|
if (null === $path && $this->media->isTmp() && !$clouds) { |
102
|
|
|
throw new InvalidArgumentException("You need to specify a path. It is not possible to save to a tmp directory"); |
103
|
|
|
} |
104
|
|
|
|
105
|
|
|
$dirname = str_replace("\\", "/", $this->path_info["dirname"]); |
106
|
|
|
$filename = substr($this->path_info["filename"], -50); |
107
|
|
|
|
108
|
|
|
FileManager::makeDir($dirname); |
109
|
|
|
|
110
|
|
|
if ($this instanceof DASH) { |
111
|
|
|
$path = $dirname . "/" . $filename . ".mpd"; |
112
|
|
|
} elseif ($this instanceof HLS) { |
113
|
|
|
$representations = $this->getRepresentations(); |
114
|
|
|
$path = $dirname . "/" . $filename . "_" . end($representations)->getHeight() . "p.m3u8"; |
115
|
|
|
ExportHLSPlaylist::savePlayList($dirname . DIRECTORY_SEPARATOR . $filename . ".m3u8", $this->getRepresentations(), $filename); |
116
|
|
|
} |
117
|
|
|
|
118
|
|
|
return $path; |
119
|
|
|
} |
120
|
|
|
|
121
|
|
|
/** |
122
|
|
|
* @param string $url |
123
|
|
|
* @param string $name |
124
|
|
|
* @param string|null $path |
125
|
|
|
* @param string $method |
126
|
|
|
* @param array $headers |
127
|
|
|
* @param array $options |
128
|
|
|
* @return mixed |
129
|
|
|
* @throws Exception |
130
|
|
|
* @deprecated this method is deprecated |
131
|
|
|
*/ |
132
|
|
|
// @TODO: should be removed in the next releases. |
133
|
|
|
public function saveToCloud( |
134
|
|
|
string $url, |
135
|
|
|
string $name, |
136
|
|
|
string $path = null, |
137
|
|
|
string $method = 'GET', |
138
|
|
|
array $headers = [], |
139
|
|
|
array $options = [] |
140
|
|
|
) |
141
|
|
|
{ |
142
|
|
|
@trigger_error('saveToCloud method is deprecated and will be removed in a future release. Use Cloud instead', E_USER_DEPRECATED); |
143
|
|
|
if ($this instanceof HLS && $this->getTsSubDirectory()) { |
144
|
|
|
throw new InvalidArgumentException("It is not possible to create subdirectory in a cloud"); |
145
|
|
|
} |
146
|
|
|
$results = $this->saveToTemporaryFolder($path); |
|
|
|
|
147
|
|
|
sleep(1); |
148
|
|
|
|
149
|
|
|
$cloud = new Cloud($url, $method, $options); |
150
|
|
|
$cloud->uploadDirectory($this->tmp_dir, ['name' => $name, 'headers' => $headers]); |
151
|
|
|
|
152
|
|
|
$this->moveTmpFolder($path); |
153
|
|
|
|
154
|
|
|
return $results; |
155
|
|
|
} |
156
|
|
|
|
157
|
|
|
/** |
158
|
|
|
* @param array $config |
159
|
|
|
* @param string $dest |
160
|
|
|
* @param string|null $path |
161
|
|
|
* @return mixed |
162
|
|
|
* @throws Exception |
163
|
|
|
* @deprecated this method is deprecated |
164
|
|
|
*/ |
165
|
|
|
// @TODO: should be removed in the next releases. |
166
|
|
|
public function saveToS3( |
167
|
|
|
array $config, |
168
|
|
|
string $dest, |
169
|
|
|
string $path = null |
170
|
|
|
) |
171
|
|
|
{ |
172
|
|
|
@trigger_error('saveToS3 method is deprecated and will be removed in a future release. Use AWS instead', E_USER_DEPRECATED); |
173
|
|
|
$results = $this->saveToTemporaryFolder($path); |
|
|
|
|
174
|
|
|
sleep(1); |
175
|
|
|
|
176
|
|
|
$aws = new AWS($config); |
177
|
|
|
$aws->uploadDirectory($this->tmp_dir, ['dest' => $dest]); |
178
|
|
|
|
179
|
|
|
$this->moveTmpFolder($path); |
180
|
|
|
|
181
|
|
|
return $results; |
182
|
|
|
} |
183
|
|
|
|
184
|
|
|
/** |
185
|
|
|
* @param array $config |
186
|
|
|
* @param string $bucket |
187
|
|
|
* @param string|null $path |
188
|
|
|
* @param array $options |
189
|
|
|
* @param bool $userProject |
190
|
|
|
* @return mixed |
191
|
|
|
* @throws Exception |
192
|
|
|
* @deprecated this method is deprecated |
193
|
|
|
*/ |
194
|
|
|
// @TODO: should be removed in the next releases. |
195
|
|
|
public function saveToGCS( |
196
|
|
|
array $config, |
197
|
|
|
string $bucket, |
198
|
|
|
string $path = null, |
199
|
|
|
array $options = [], |
200
|
|
|
bool $userProject = false |
201
|
|
|
) |
202
|
|
|
{ |
203
|
|
|
@trigger_error('saveToGCS method is deprecated and will be removed in a future release. Use GoogleCloudStorage instead', E_USER_DEPRECATED); |
204
|
|
|
if ($this instanceof HLS && $this->getTsSubDirectory()) { |
205
|
|
|
throw new InvalidArgumentException("It is not possible to create subdirectory in a cloud"); |
206
|
|
|
} |
207
|
|
|
|
208
|
|
|
$results = $this->saveToTemporaryFolder($path); |
|
|
|
|
209
|
|
|
sleep(1); |
210
|
|
|
|
211
|
|
|
$google_cloud = new GoogleCloudStorage($config, $bucket, $userProject); |
212
|
|
|
$google_cloud->uploadDirectory($this->tmp_dir, $options); |
213
|
|
|
|
214
|
|
|
$this->moveTmpFolder($path); |
215
|
|
|
|
216
|
|
|
return $results; |
217
|
|
|
} |
218
|
|
|
|
219
|
|
|
/** |
220
|
|
|
* @param string $connectionString |
221
|
|
|
* @param string $container |
222
|
|
|
* @param string|null $path |
223
|
|
|
* @return mixed |
224
|
|
|
* @throws Exception |
225
|
|
|
* @deprecated this method is deprecated |
226
|
|
|
*/ |
227
|
|
|
// @TODO: should be removed in the next releases. |
228
|
|
|
public function saveToMAS( |
229
|
|
|
string $connectionString, |
230
|
|
|
string $container, |
231
|
|
|
string $path = null |
232
|
|
|
) |
233
|
|
|
{ |
234
|
|
|
@trigger_error('saveToMAS method is deprecated and will be removed in a future release. Use MicrosoftAzure instead', E_USER_DEPRECATED); |
235
|
|
|
|
236
|
|
|
if ($this instanceof HLS && $this->getTsSubDirectory()) { |
237
|
|
|
throw new InvalidArgumentException("It is not possible to create subdirectory in a cloud"); |
238
|
|
|
} |
239
|
|
|
|
240
|
|
|
$results = $this->saveToTemporaryFolder($path); |
|
|
|
|
241
|
|
|
sleep(1); |
242
|
|
|
|
243
|
|
|
$google_cloud = new MicrosoftAzure($connectionString); |
244
|
|
|
$google_cloud->uploadDirectory($this->tmp_dir, ['container' => $container]); |
245
|
|
|
|
246
|
|
|
$this->moveTmpFolder($path); |
247
|
|
|
|
248
|
|
|
return $results; |
249
|
|
|
} |
250
|
|
|
|
251
|
|
|
/** |
252
|
|
|
* @return array |
253
|
|
|
*/ |
254
|
|
|
public function getPathInfo(): array |
255
|
|
|
{ |
256
|
|
|
return $this->path_info; |
257
|
|
|
} |
258
|
|
|
|
259
|
|
|
/** |
260
|
|
|
* @return object|Media |
261
|
|
|
*/ |
262
|
|
|
public function getMedia(): Media |
263
|
|
|
{ |
264
|
|
|
return $this->media; |
265
|
|
|
} |
266
|
|
|
|
267
|
|
|
/** |
268
|
|
|
* @param $path |
269
|
|
|
* @return array |
270
|
|
|
* @throws Exception |
271
|
|
|
* @deprecated this method is deprecated |
272
|
|
|
*/ |
273
|
|
|
// @TODO: should be removed in the next releases. |
274
|
|
|
private function saveToTemporaryFolder($path) |
275
|
|
|
{ |
276
|
|
|
$basename = Helper::randomString(); |
277
|
|
|
|
278
|
|
|
if (null !== $path) { |
279
|
|
|
$basename = pathinfo($path, PATHINFO_BASENAME); |
280
|
|
|
} |
281
|
|
|
|
282
|
|
|
$this->tmp_dir = FileManager::tmpDir(); |
283
|
|
|
|
284
|
|
|
return $this->save($this->tmp_dir . $basename); |
285
|
|
|
} |
286
|
|
|
|
287
|
|
|
/** |
288
|
|
|
* clear tmp files |
289
|
|
|
*/ |
290
|
|
|
public function __destruct() |
291
|
|
|
{ |
292
|
|
|
sleep(1); |
293
|
|
|
|
294
|
|
|
if ($this->media->isTmp()) { |
295
|
|
|
@unlink($this->media->getPath()); |
|
|
|
|
296
|
|
|
} |
297
|
|
|
|
298
|
|
|
if ($this->tmp_dir) { |
299
|
|
|
FileManager::deleteDirectory($this->tmp_dir); |
300
|
|
|
} |
301
|
|
|
} |
302
|
|
|
|
303
|
|
|
/** |
304
|
|
|
* @param string|null $path |
305
|
|
|
* @throws Exception |
306
|
|
|
*/ |
307
|
|
|
private function moveTmpFolder(?string $path) |
308
|
|
|
{ |
309
|
|
|
if ($this->tmp_dir && $path) { |
310
|
|
|
FileManager::moveDir($this->tmp_dir, pathinfo($path, PATHINFO_DIRNAME) . DIRECTORY_SEPARATOR); |
311
|
|
|
} |
312
|
|
|
} |
313
|
|
|
|
314
|
|
|
/** |
315
|
|
|
* @param string $strict |
316
|
|
|
* @return Export |
317
|
|
|
*/ |
318
|
|
|
public function setStrict(string $strict): Export |
319
|
|
|
{ |
320
|
|
|
$this->strict = $strict; |
321
|
|
|
return $this; |
322
|
|
|
} |
323
|
|
|
|
324
|
|
|
/** |
325
|
|
|
* @return string |
326
|
|
|
*/ |
327
|
|
|
public function getStrict(): string |
328
|
|
|
{ |
329
|
|
|
return $this->strict; |
330
|
|
|
} |
331
|
|
|
|
332
|
|
|
/** |
333
|
|
|
* @param $path |
334
|
|
|
* @throws Exception |
335
|
|
|
*/ |
336
|
|
|
private function tmpDirectory($path) |
337
|
|
|
{ |
338
|
|
|
if (null !== $path) { |
339
|
|
|
$basename = pathinfo($path, PATHINFO_BASENAME); |
340
|
|
|
} else { |
341
|
|
|
$basename = Helper::randomString(); |
342
|
|
|
} |
343
|
|
|
|
344
|
|
|
$this->tmp_dir = FileManager::tmpDir(); |
345
|
|
|
$this->path_info = pathinfo($this->tmp_dir . $basename); |
346
|
|
|
} |
347
|
|
|
|
348
|
|
|
/** |
349
|
|
|
* @param array $clouds |
350
|
|
|
*/ |
351
|
|
|
private function saveToClouds(array $clouds): void |
352
|
|
|
{ |
353
|
|
|
if ($clouds) { |
|
|
|
|
354
|
|
|
|
355
|
|
|
if (!is_array(current($clouds))) { |
356
|
|
|
$clouds = [$clouds]; |
357
|
|
|
} |
358
|
|
|
|
359
|
|
|
sleep(1); |
360
|
|
|
|
361
|
|
|
foreach ($clouds as $cloud) { |
362
|
|
|
if (is_array($cloud) && $cloud['cloud'] instanceof CloudInterface) { |
363
|
|
|
$cloud_obj = $cloud['cloud']; |
364
|
|
|
$options = (isset($cloud['options']) && is_array($cloud['options'])) ? $cloud['options'] : []; |
365
|
|
|
|
366
|
|
|
$cloud_obj->uploadDirectory($this->tmp_dir, $options); |
367
|
|
|
} else { |
368
|
|
|
throw new InvalidArgumentException('You must pass an array of clouds to the save method. |
369
|
|
|
and the cloud must be instance of CloudInterface'); |
370
|
|
|
} |
371
|
|
|
} |
372
|
|
|
} |
373
|
|
|
} |
374
|
|
|
} |
This function has been deprecated. The supplier of the function has supplied an explanatory message.
The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.