Completed
Push — master ( 3e00d5...ea5e9f )
by Sébastien
02:23
created

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