Passed
Push — master ( 42036d...9952e8 )
by Sébastien
02:35
created

VideoConvertParams::withPreset()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 1
dl 0
loc 4
ccs 3
cts 3
cp 1
crap 1
rs 10
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Soluble\MediaTools\Video;
6
7
use Soluble\MediaTools\Common\Assert\BitrateAssertionsTrait;
8
use Soluble\MediaTools\Video\Adapter\FFMpegCLIValueInterface;
9
use Soluble\MediaTools\Video\Exception\InvalidArgumentException;
10
use Soluble\MediaTools\Video\Exception\UnsetParamReaderException;
11
use Soluble\MediaTools\Video\Filter\Type\VideoFilterInterface;
12
13
class VideoConvertParams implements VideoConvertParamsInterface
14
{
15
    use BitrateAssertionsTrait;
16
17
    /** @var array<string, bool|string|int|VideoFilterInterface|FFMpegCLIValueInterface> */
18
    protected $params = [];
19
20
    /**
21
     * @param array<string, bool|string|int|VideoFilterInterface|FFMpegCLIValueInterface> $params
22
     *
23
     * @throws InvalidArgumentException in case of unsupported option
24
     */
25 41
    public function __construct($params = [])
26
    {
27 41
        $this->ensureSupportedParams($params);
28 40
        $this->params = $params;
29 40
    }
30
31 15
    public function withVideoCodec(string $videoCodec): self
32
    {
33 15
        return new self(array_merge($this->params, [
34 15
            self::PARAM_VIDEO_CODEC => $videoCodec,
35
        ]));
36
    }
37
38 11
    public function withVideoFilter(VideoFilterInterface $videoFilter): self
39
    {
40 11
        return new self(array_merge($this->params, [
41 11
            self::PARAM_VIDEO_FILTER => $videoFilter,
42
        ]));
43
    }
44
45 5
    public function withAudioCodec(string $audioCodec): self
46
    {
47 5
        return new self(array_merge($this->params, [
48 5
            self::PARAM_AUDIO_CODEC => $audioCodec,
49
        ]));
50
    }
51
52
    /**
53
     * Set TileColumns (VP9 - to use in conjunction with FrameParallel).
54
     *
55
     * Tiling splits the video frame into multiple columns,
56
     * which slightly reduces quality but speeds up encoding performance.
57
     * Tiles must be at least 256 pixels wide, so there is a limit to how many tiles can be used.
58
     * Depending upon the number of tiles and the resolution of the tmp frame, more CPU threads may be useful.
59
     *
60
     * Generally speaking, there is limited value to multiple threads when the tmp frame size is very small.
61
     *
62
     * @see self::withFrameParallel()
63
     */
64 10
    public function withTileColumns(int $tileColumns): self
65
    {
66 10
        return new self(array_merge($this->params, [
67 10
            self::PARAM_TILE_COLUMNS => $tileColumns,
68
        ]));
69
    }
70
71
    /**
72
     * Set FrameParallel (VP9 - to use in conjunction with TileColumns).
73
     *
74
     * @see self::withTileColumns()
75
     */
76 5
    public function withFrameParallel(int $frameParallel): self
77
    {
78 5
        return new self(array_merge($this->params, [
79 5
            self::PARAM_FRAME_PARALLEL => $frameParallel,
80
        ]));
81
    }
82
83
    /**
84
     * Set KeyFrameSpacing (VP9).
85
     *
86
     * It is recommended to allow up to 240 frames of video between keyframes (8 seconds for 30fps content).
87
     * Keyframes are video frames which are self-sufficient; they don't rely upon any other frames to render
88
     * but they tend to be larger than other frame types.
89
     *
90
     * For web and mobile playback, generous spacing between keyframes allows the encoder to choose the best
91
     * placement of keyframes to maximize quality.
92
     */
93 5
    public function withKeyframeSpacing(int $keyframeSpacing): self
94
    {
95 5
        return new self(array_merge($this->params, [
96 5
            self::PARAM_KEYFRAME_SPACING => $keyframeSpacing,
97
        ]));
98
    }
99
100
    /**
101
     * Set compression level (Constant Rate Factor).
102
     */
103 6
    public function withCrf(int $crf): self
104
    {
105 6
        return new self(array_merge($this->params, [
106 6
            self::PARAM_CRF => $crf,
107
        ]));
108
    }
109
110 5
    public function withPixFmt(string $pixFmt): self
111
    {
112 5
        return new self(array_merge($this->params, [
113 5
            self::PARAM_PIX_FMT => $pixFmt,
114
        ]));
115
    }
116
117 3
    public function withPreset(string $preset): self
118
    {
119 3
        return new self(array_merge($this->params, [
120 3
            self::PARAM_PRESET => $preset,
121
        ]));
122
    }
123
124 5
    public function withSpeed(int $speed): self
125
    {
126 5
        return new self(array_merge($this->params, [
127 5
            self::PARAM_SPEED => $speed,
128
        ]));
129
    }
130
131 7
    public function withThreads(int $threads): self
132
    {
133 7
        return new self(array_merge($this->params, [
134 7
            self::PARAM_THREADS => $threads,
135
        ]));
136
    }
137
138 4
    public function withTune(string $tune): self
139
    {
140 4
        return new self(array_merge($this->params, [
141 4
            self::PARAM_TUNE => $tune,
142
        ]));
143
    }
144
145
    /**
146
     * If true, add streamable options for mp4 container (-movflags +faststart).
147
     */
148 2
    public function withStreamable(bool $streamable): self
149
    {
150 2
        return new self(array_merge($this->params, [
151 2
            self::PARAM_STREAMABLE => $streamable,
152
        ]));
153
    }
154
155
    /**
156
     * @param string $bitrate Bitrate with optional unit: 1000000, 1000k or 1M
157
     *
158
     * @throws InvalidArgumentException if bitrate value is invalid
159
     */
160 6
    public function withAudioBitrate(string $bitrate): self
161
    {
162 6
        $this->ensureValidBitRateUnit($bitrate);
163
164 5
        return new self(array_merge($this->params, [
165 5
            self::PARAM_AUDIO_BITRATE => $bitrate,
166
        ]));
167
    }
168
169
    /**
170
     * @param string $bitrate Bitrate or target bitrate with optional unit: 1000000, 1000k or 1M
171
     *
172
     * @throws InvalidArgumentException if bitrate value is invalid
173
     */
174 6
    public function withVideoBitrate(string $bitrate): self
175
    {
176 6
        $this->ensureValidBitRateUnit($bitrate);
177
178 5
        return new self(array_merge($this->params, [
179 5
            self::PARAM_VIDEO_BITRATE => $bitrate,
180
        ]));
181
    }
182
183
    /**
184
     * @param string $minBitrate Bitrate with optional unit: 1000000, 1000k or 1M
185
     *
186
     * @throws InvalidArgumentException if bitrate value is invalid
187
     */
188 6
    public function withVideoMinBitrate(string $minBitrate): self
189
    {
190 6
        $this->ensureValidBitRateUnit($minBitrate);
191
192 5
        return new self(array_merge($this->params, [
193 5
            self::PARAM_VIDEO_MIN_BITRATE => $minBitrate,
194
        ]));
195
    }
196
197
    /**
198
     * @param string $maxBitrate Bitrate with optional unit: 1000000, 1000k or 1M
199
     *
200
     * @throws InvalidArgumentException if bitrate value is invalid
201
     */
202 6
    public function withVideoMaxBitrate(string $maxBitrate): self
203
    {
204 6
        $this->ensureValidBitRateUnit($maxBitrate);
205
206 5
        return new self(array_merge($this->params, [
207 5
            self::PARAM_VIDEO_MAX_BITRATE => $maxBitrate,
208
        ]));
209
    }
210
211
    /**
212
     * Add with overwrite option (default).
213
     *
214
     * @see self::withNoOverwrite()
215
     */
216 6
    public function withOverwrite(): self
217
    {
218 6
        return new self(array_merge($this->params, [
219 6
            self::PARAM_OVERWRITE => true
220
        ]));
221
    }
222
223
    /**
224
     * Add protection against output file overwriting.
225
     *
226
     * @see self::witoOverwrite()
227
     */
228 1
    public function withNoOverwrite(): self
229
    {
230 1
        return new self(array_merge($this->params, [
231 1
            self::PARAM_OVERWRITE => false
232
        ]));
233
    }
234
235 2
    public function withQuality(string $quality): self
236
    {
237 2
        return new self(array_merge($this->params, [
238 2
            self::PARAM_QUALITY => $quality,
239
        ]));
240
    }
241
242 8
    public function withOutputFormat(string $outputFormat): self
243
    {
244 8
        return new self(array_merge($this->params, [
245 8
            self::PARAM_OUTPUT_FORMAT => $outputFormat,
246
        ]));
247
    }
248
249 10
    public function withSeekStart(SeekTime $seekTimeStart): self
250
    {
251 10
        return new self(array_merge($this->params, [
252 10
            self::PARAM_SEEK_START => $seekTimeStart,
253
        ]));
254
    }
255
256 4
    public function withSeekEnd(SeekTime $seekTimeEnd): self
257
    {
258 4
        return new self(array_merge($this->params, [
259 4
            self::PARAM_SEEK_END => $seekTimeEnd,
260
        ]));
261
    }
262
263 5
    public function withNoAudio(): self
264
    {
265 5
        return new self(array_merge($this->params, [
266 5
            self::PARAM_NOAUDIO => true,
267
        ]));
268
    }
269
270 10
    public function withVideoFrames(int $numberOfFrames): self
271
    {
272 10
        return new self(array_merge($this->params, [
273 10
            self::PARAM_VIDEO_FRAMES => $numberOfFrames,
274
        ]));
275
    }
276
277
    /**
278
     * Set the video encoder quality scale. (-qscale:v <int>, alias to -q:v <int>).
279
     *
280
     * @param int $qualityScale a number interpreted by the encoder, generally 1-5
281
     *
282
     * @see self::withQuality()
283
     */
284 5
    public function withVideoQualityScale(int $qualityScale): self
285
    {
286 5
        return new self(array_merge($this->params, [
287 5
            self::PARAM_VIDEO_QUALITY_SCALE => $qualityScale,
288
        ]));
289
    }
290
291
    /**
292
     * Setting auto-alt-ref and lag-in-frames >= 12 will turn on VP9's alt-ref frames, a VP9 feature that enhances quality.
293
     */
294 3
    public function withAutoAltRef(int $autoAltRef): self
295
    {
296 3
        return new self(array_merge($this->params, [
297 3
            self::PARAM_AUTO_ALT_REF => $autoAltRef,
298
        ]));
299
    }
300
301
    /**
302
     * Setting auto-alt-ref and lag-in-frames >= 12 will turn on VP9's alt-ref frames, a VP9 feature that enhances quality.
303
     */
304 3
    public function withLagInFrames(int $lagInFrames): self
305
    {
306 3
        return new self(array_merge($this->params, [
307 3
            self::PARAM_LAG_IN_FRAMES => $lagInFrames,
308
        ]));
309
    }
310
311
    /**
312
     * Set the pass number.
313
     */
314 4
    public function withPass(int $passNumber): self
315
    {
316 4
        return new self(array_merge($this->params, [
317 4
            self::PARAM_PASS => $passNumber,
318
        ]));
319
    }
320
321
    /**
322
     * Set the passlogfile (only makes sense for multipass conversions).
323
     */
324 4
    public function withPassLogFile(string $passLogFile): self
325
    {
326 4
        return new self(array_merge($this->params, [
327 4
            self::PARAM_PASSLOGFILE => $passLogFile,
328
        ]));
329
    }
330
331
    /**
332
     * @param bool|string|int|VideoFilterInterface|FFMpegCLIValueInterface $paramValue
333
     *
334
     * @throws InvalidArgumentException in case of unsupported builtin param
335
     *
336
     * @return self (For static analysis the trick is to return 'self' instead of interface)
337
     */
338 24
    public function withBuiltInParam(string $paramName, $paramValue): VideoConvertParamsInterface
339
    {
340 24
        return new self(array_merge($this->params, [
341 24
            $paramName => $paramValue,
342
        ]));
343
    }
344
345
    /**
346
     * @return self (For static analysis the trick is to return 'self' instead of interface)
347
     */
348 2
    public function withoutParam(string $paramName): VideoConvertParamsInterface
349
    {
350 2
        $ao = (new \ArrayObject($this->params));
351 2
        if ($ao->offsetExists($paramName)) {
352 2
            $ao->offsetUnset($paramName);
353
        }
354
355 2
        return new self($ao->getArrayCopy());
356
    }
357
358
    /**
359
     * Return the internal array holding params.
360
     *
361
     * @return array<string,bool|string|int|VideoFilterInterface|FFMpegCLIValueInterface>
362
     */
363 32
    public function toArray(): array
364
    {
365 32
        return $this->params;
366
    }
367
368 38
    public function isParamValid(string $paramName): bool
369
    {
370 38
        return in_array($paramName, self::BUILTIN_PARAMS, true);
371
    }
372
373
    /**
374
     * @return bool|string|int|VideoFilterInterface|FFMpegCLIValueInterface|null
375
     *
376
     * @throws UnsetParamReaderException
377
     */
378 4
    public function getParam(string $paramName)
379
    {
380 4
        if (!$this->hasParam($paramName)) {
381 1
            throw new UnsetParamReaderException(sprintf(
382 1
                'Cannot get param \'%s\', it has not been set',
383 1
                $paramName
384
            ));
385
        }
386
387 3
        return $this->params[$paramName];
388
    }
389
390 32
    public function hasParam(string $paramName): bool
391
    {
392 32
        return array_key_exists($paramName, $this->params);
393
    }
394
395
    /**
396
     * @return VideoConvertParams
397
     */
398 1
    public function withConvertParams(VideoConvertParamsInterface $extraParams): VideoConvertParamsInterface
399
    {
400 1
        return new self(
401 1
            array_merge($this->toArray(), $extraParams->toArray())
402
        );
403
    }
404
405
    /**
406
     * Ensure that all params are supported.
407
     *
408
     * @param array<string, bool|string|int|VideoFilterInterface|FFMpegCLIValueInterface> $params
409
     *
410
     * @throws InvalidArgumentException in case of unsupported option
411
     */
412 41
    protected function ensureSupportedParams(array $params): void
413
    {
414 41
        foreach ($params as $paramName => $paramValue) {
415 38
            if (!$this->isParamValid($paramName)) {
416 1
                throw new InvalidArgumentException(
417 38
                    sprintf('Unsupported built-in param "%s" given.', $paramName)
418
                );
419
            }
420
        }
421 40
    }
422
}
423