Passed
Push — master ( 89fbe5...c257f0 )
by Sébastien
02:18
created

VideoConvertParams::withAudioCodec()   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\UnsetParamException;
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 36
    public function __construct($params = [])
26
    {
27 36
        $this->ensureSupportedParams($params);
28 35
        $this->params = $params;
29 35
    }
30
31 13
    public function withVideoCodec(string $videoCodec): self
32
    {
33 13
        return new self(array_merge($this->params, [
34 13
            self::PARAM_VIDEO_CODEC => $videoCodec,
35
        ]));
36
    }
37
38 10
    public function withVideoFilter(VideoFilterInterface $videoFilter): self
39
    {
40 10
        return new self(array_merge($this->params, [
41 10
            self::PARAM_VIDEO_FILTER => $videoFilter,
42
        ]));
43
    }
44
45 4
    public function withAudioCodec(string $audioCodec): self
46
    {
47 4
        return new self(array_merge($this->params, [
48 4
            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 8
    public function withTileColumns(int $tileColumns): self
65
    {
66 8
        return new self(array_merge($this->params, [
67 8
            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 4
    public function withFrameParallel(int $frameParallel): self
77
    {
78 4
        return new self(array_merge($this->params, [
79 4
            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 4
    public function withKeyframeSpacing(int $keyframeSpacing): self
94
    {
95 4
        return new self(array_merge($this->params, [
96 4
            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 4
    public function withPixFmt(string $pixFmt): self
111
    {
112 4
        return new self(array_merge($this->params, [
113 4
            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 4
    public function withSpeed(int $speed): self
125
    {
126 4
        return new self(array_merge($this->params, [
127 4
            self::PARAM_SPEED => $speed,
128
        ]));
129
    }
130
131 6
    public function withThreads(int $threads): self
132
    {
133 6
        return new self(array_merge($this->params, [
134 6
            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 5
    public function withAudioBitrate(string $bitrate): self
161
    {
162 5
        $this->ensureValidBitRateUnit($bitrate);
163
164 4
        return new self(array_merge($this->params, [
165 4
            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 5
    public function withVideoBitrate(string $bitrate): self
175
    {
176 5
        $this->ensureValidBitRateUnit($bitrate);
177
178 4
        return new self(array_merge($this->params, [
179 4
            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 5
    public function withVideoMinBitrate(string $minBitrate): self
189
    {
190 5
        $this->ensureValidBitRateUnit($minBitrate);
191
192 4
        return new self(array_merge($this->params, [
193 4
            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 5
    public function withVideoMaxBitrate(string $maxBitrate): self
203
    {
204 5
        $this->ensureValidBitRateUnit($maxBitrate);
205
206 4
        return new self(array_merge($this->params, [
207 4
            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 6
    public function withOutputFormat(string $outputFormat): self
243
    {
244 6
        return new self(array_merge($this->params, [
245 6
            self::PARAM_OUTPUT_FORMAT => $outputFormat,
246
        ]));
247
    }
248
249 9
    public function withSeekStart(SeekTime $seekTimeStart): self
250
    {
251 9
        return new self(array_merge($this->params, [
252 9
            self::PARAM_SEEK_START => $seekTimeStart,
253
        ]));
254
    }
255
256 3
    public function withSeekEnd(SeekTime $seekTimeEnd): self
257
    {
258 3
        return new self(array_merge($this->params, [
259 3
            self::PARAM_SEEK_END => $seekTimeEnd,
260
        ]));
261
    }
262
263 4
    public function withNoAudio(): self
264
    {
265 4
        return new self(array_merge($this->params, [
266 4
            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
     * @param bool|string|int|VideoFilterInterface|FFMpegCLIValueInterface $paramValue
293
     *
294
     * @throws InvalidArgumentException in case of unsupported builtin param
295
     *
296
     * @return self (For static analysis the trick is to return 'self' instead of interface)
297
     */
298 20
    public function withBuiltInParam(string $paramName, $paramValue): VideoConvertParamsInterface
299
    {
300 20
        return new self(array_merge($this->params, [
301 20
            $paramName => $paramValue,
302
        ]));
303
    }
304
305
    /**
306
     * @return self (For static analysis the trick is to return 'self' instead of interface)
307
     */
308 1
    public function withoutParam(string $paramName): VideoConvertParamsInterface
309
    {
310 1
        $ao = (new \ArrayObject($this->params));
311 1
        if ($ao->offsetExists($paramName)) {
312 1
            $ao->offsetUnset($paramName);
313
        }
314
315 1
        return new self($ao->getArrayCopy());
316
    }
317
318
    /**
319
     * Return the internal array holding params.
320
     *
321
     * @return array<string,bool|string|int|VideoFilterInterface|FFMpegCLIValueInterface>
322
     */
323 27
    public function toArray(): array
324
    {
325 27
        return $this->params;
326
    }
327
328 33
    public function isParamValid(string $paramName): bool
329
    {
330 33
        return in_array($paramName, self::BUILTIN_PARAMS, true);
331
    }
332
333
    /**
334
     * @return bool|string|int|VideoFilterInterface|FFMpegCLIValueInterface|null
335
     *
336
     * @throws UnsetParamException
337
     */
338 3
    public function getParam(string $paramName)
339
    {
340 3
        if (!$this->hasParam($paramName)) {
341 1
            throw new UnsetParamException(sprintf(
342 1
                'Cannot get param \'%s\', it has not been set',
343 1
                $paramName
344
            ));
345
        }
346
347 2
        return $this->params[$paramName];
348
    }
349
350 27
    public function hasParam(string $paramName): bool
351
    {
352 27
        return array_key_exists($paramName, $this->params);
353
    }
354
355
    /**
356
     * Ensure that all params are supported.
357
     *
358
     * @param array<string, bool|string|int|VideoFilterInterface|FFMpegCLIValueInterface> $params
359
     *
360
     * @throws InvalidArgumentException in case of unsupported option
361
     */
362 36
    protected function ensureSupportedParams(array $params): void
363
    {
364 36
        foreach ($params as $paramName => $paramValue) {
365 33
            if (!$this->isParamValid($paramName)) {
366 1
                throw new InvalidArgumentException(
367 33
                    sprintf('Unsupported param "%s" given.', $paramName)
368
                );
369
            }
370
        }
371 35
    }
372
}
373