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\Cloud; |
16
|
|
|
use Streaming\Exception\InvalidArgumentException; |
17
|
|
|
use Streaming\Exception\RuntimeException; |
18
|
|
|
use Streaming\Filters\Filter; |
19
|
|
|
use Streaming\Traits\Formats; |
20
|
|
|
|
21
|
|
|
|
22
|
|
|
abstract class Export |
23
|
|
|
{ |
24
|
|
|
use Formats; |
25
|
|
|
|
26
|
|
|
/** @var object */ |
27
|
|
|
protected $media; |
28
|
|
|
|
29
|
|
|
/** @var array */ |
30
|
|
|
protected $path_info; |
31
|
|
|
|
32
|
|
|
/** @var string */ |
33
|
|
|
protected $strict = "-2"; |
34
|
|
|
|
35
|
|
|
/** @var string */ |
36
|
|
|
protected $tmp_dir; |
37
|
|
|
|
38
|
|
|
/** |
39
|
|
|
* Export constructor. |
40
|
|
|
* @param Media $media |
41
|
|
|
*/ |
42
|
|
|
public function __construct(Media $media) |
43
|
|
|
{ |
44
|
|
|
$this->media = $media; |
45
|
|
|
$this->path_info = pathinfo($media->getPath()); |
46
|
|
|
} |
47
|
|
|
|
48
|
|
|
/** |
49
|
|
|
* @return object|Media |
50
|
|
|
*/ |
51
|
|
|
public function getMedia(): Media |
52
|
|
|
{ |
53
|
|
|
return $this->media; |
54
|
|
|
} |
55
|
|
|
|
56
|
|
|
/** |
57
|
|
|
* @param string $strict |
58
|
|
|
* @return Export |
59
|
|
|
*/ |
60
|
|
|
public function setStrict(string $strict): Export |
61
|
|
|
{ |
62
|
|
|
$this->strict = $strict; |
63
|
|
|
return $this; |
64
|
|
|
} |
65
|
|
|
|
66
|
|
|
/** |
67
|
|
|
* @return string |
68
|
|
|
*/ |
69
|
|
|
public function getStrict(): string |
70
|
|
|
{ |
71
|
|
|
return $this->strict; |
72
|
|
|
} |
73
|
|
|
|
74
|
|
|
/** |
75
|
|
|
* @return bool |
76
|
|
|
*/ |
77
|
|
|
public function isTmpDir(): bool |
78
|
|
|
{ |
79
|
|
|
return (bool)$this->tmp_dir; |
80
|
|
|
} |
81
|
|
|
|
82
|
|
|
/** |
83
|
|
|
* @return array |
84
|
|
|
*/ |
85
|
|
|
public function getPathInfo(): array |
86
|
|
|
{ |
87
|
|
|
return $this->path_info; |
88
|
|
|
} |
89
|
|
|
|
90
|
|
|
/** |
91
|
|
|
* @param string|null $path |
92
|
|
|
*/ |
93
|
|
|
private function moveTmp(?string $path): void |
94
|
|
|
{ |
95
|
|
|
if ($this->isTmpDir() && !is_null($path)) { |
96
|
|
|
File::moveDir($this->tmp_dir, dirname($path)); |
97
|
|
|
$this->path_info = pathinfo($path); |
98
|
|
|
$this->tmp_dir = ''; |
99
|
|
|
} |
100
|
|
|
} |
101
|
|
|
|
102
|
|
|
|
103
|
|
|
/** |
104
|
|
|
* @param array $clouds |
105
|
|
|
* @param string $path |
106
|
|
|
*/ |
107
|
|
|
private function clouds(array $clouds, ?string $path): void |
108
|
|
|
{ |
109
|
|
|
if (!empty($clouds)) { |
110
|
|
|
Cloud::uploadDirectory($clouds, $this->tmp_dir); |
111
|
|
|
$this->moveTmp($path); |
112
|
|
|
} |
113
|
|
|
} |
114
|
|
|
|
115
|
|
|
/** |
116
|
|
|
* @return string |
117
|
|
|
*/ |
118
|
|
|
private function getPath(): string |
119
|
|
|
{ |
120
|
|
|
$path = str_replace("\\", "/", $this->path_info["dirname"] . "/" . $this->path_info["filename"]); |
121
|
|
|
|
122
|
|
|
if ($this instanceof DASH) { |
123
|
|
|
$path .= ".mpd"; |
124
|
|
|
} elseif ($this instanceof HLS) { |
125
|
|
|
$reps = $this->getRepresentations(); |
126
|
|
|
HLSPlaylist::save($path . ".m3u8", $reps); |
127
|
|
|
$path .= "_" . end($reps)->getHeight() . "p.m3u8"; |
128
|
|
|
} |
129
|
|
|
|
130
|
|
|
return $path; |
131
|
|
|
} |
132
|
|
|
|
133
|
|
|
/** |
134
|
|
|
* @return Filter |
135
|
|
|
*/ |
136
|
|
|
abstract protected function getFilter(): Filter; |
137
|
|
|
|
138
|
|
|
/** |
139
|
|
|
* Run FFmpeg to package media content |
140
|
|
|
*/ |
141
|
|
|
private function run(): void |
142
|
|
|
{ |
143
|
|
|
try { |
144
|
|
|
$this->media |
145
|
|
|
->addFilter($this->getFilter()) |
146
|
|
|
->save($this->getFormat(), $this->getPath()); |
147
|
|
|
} catch (ExceptionInterface $e) { |
148
|
|
|
throw new RuntimeException("An error occurred while saving files: " . $e->getMessage(), $e->getCode(), $e); |
149
|
|
|
} |
150
|
|
|
} |
151
|
|
|
|
152
|
|
|
/** |
153
|
|
|
* @param string|null $path |
154
|
|
|
*/ |
155
|
|
|
private function tmpDirectory(?string $path): void |
156
|
|
|
{ |
157
|
|
|
$basename = $path ? basename($path) : Utilities::randomString(); |
158
|
|
|
|
159
|
|
|
$this->tmp_dir = File::tmpDir(); |
160
|
|
|
$this->path_info = pathinfo($this->tmp_dir . $basename); |
161
|
|
|
} |
162
|
|
|
|
163
|
|
|
/** |
164
|
|
|
* @param $path |
165
|
|
|
* @param $clouds |
166
|
|
|
*/ |
167
|
|
|
private function makePaths(?string $path, array $clouds): void |
168
|
|
|
{ |
169
|
|
|
if ($clouds) { |
|
|
|
|
170
|
|
|
$this->tmpDirectory($path); |
171
|
|
|
} elseif (!is_null($path)) { |
172
|
|
|
if (strlen($path) > PHP_MAXPATHLEN) { |
173
|
|
|
throw new InvalidArgumentException("The path is too long"); |
174
|
|
|
} |
175
|
|
|
|
176
|
|
|
File::makeDir(dirname($path)); |
177
|
|
|
$this->path_info = pathinfo($path); |
178
|
|
|
} elseif ($this->media->isTmp()) { |
179
|
|
|
throw new InvalidArgumentException("You need to specify a path. It is not possible to save to a tmp directory"); |
180
|
|
|
} |
181
|
|
|
} |
182
|
|
|
|
183
|
|
|
/** |
184
|
|
|
* @param string $path |
185
|
|
|
* @param array $clouds |
186
|
|
|
* @param bool $metadata |
187
|
|
|
* @return mixed |
188
|
|
|
*/ |
189
|
|
|
public function save(string $path = null, array $clouds = [], bool $metadata = true) |
190
|
|
|
{ |
191
|
|
|
$this->makePaths($path, $clouds); |
192
|
|
|
$this->run(); |
193
|
|
|
$this->clouds($clouds, $path); |
194
|
|
|
|
195
|
|
|
return $metadata ? (new Metadata($this))->extract() : $this; |
196
|
|
|
} |
197
|
|
|
|
198
|
|
|
/** |
199
|
|
|
* clear tmp files |
200
|
|
|
*/ |
201
|
|
|
public function __destruct() |
202
|
|
|
{ |
203
|
|
|
sleep(1); |
204
|
|
|
|
205
|
|
|
if ($this->media->isTmp()) { |
206
|
|
|
@unlink($this->media->getPath()); |
|
|
|
|
207
|
|
|
} |
208
|
|
|
|
209
|
|
|
if ($this->tmp_dir) { |
210
|
|
|
File::deleteDirectory($this->tmp_dir); |
211
|
|
|
} |
212
|
|
|
|
213
|
|
|
if ($this instanceof HLS && $this->tmp_key_info_file) { |
214
|
|
|
@unlink($this->getHlsKeyInfoFile()); |
215
|
|
|
} |
216
|
|
|
} |
217
|
|
|
} |
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.
Consider making the comparison explicit by using
empty(..)
or! empty(...)
instead.