Passed
Push — master ( a91cfe...d8387a )
by Sébastien
02:25
created

FFMpegAdapter   A

Complexity

Total Complexity 19

Size/Duplication

Total Lines 191
Duplicated Lines 0 %

Test Coverage

Coverage 94.87%

Importance

Changes 0
Metric Value
eloc 101
dl 0
loc 191
ccs 74
cts 78
cp 0.9487
rs 10
c 0
b 0
f 0
wmc 19

5 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 3 1
B getMappedConversionParams() 0 43 10
A getParamsOptions() 0 84 1
A getDefaultThreads() 0 3 1
A getCliCommand() 0 27 6
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Soluble\MediaTools\Video\Adapter;
6
7
use Soluble\MediaTools\Common\Exception\InvalidArgumentException;
8
use Soluble\MediaTools\Common\Exception\UnsupportedParamException;
9
use Soluble\MediaTools\Common\Exception\UnsupportedParamValueException;
10
use Soluble\MediaTools\Common\IO\PlatformNullFile;
11
use Soluble\MediaTools\Video\Config\FFMpegConfigInterface;
12
use Soluble\MediaTools\Video\ConversionParamsInterface;
13
14
class FFMpegAdapter implements ConverterAdapterInterface
15
{
16
    /** @var FFMpegConfigInterface */
17
    protected $ffmpegConfig;
18
19 23
    public function __construct(FFMpegConfigInterface $ffmpegConfig)
20
    {
21 23
        $this->ffmpegConfig = $ffmpegConfig;
22 23
    }
23
24 12
    public function getDefaultThreads(): ?int
25
    {
26 12
        return $this->ffmpegConfig->getThreads();
27
    }
28
29
    /**
30
     * @return array<string, array<string, string>>
31
     */
32 22
    public function getParamsOptions(): array
33
    {
34
        return [
35 22
            ConversionParamsInterface::PARAM_OUTPUT_FORMAT => [
36
                'pattern' => '-f %s',
37
            ],
38
39 22
            ConversionParamsInterface::PARAM_VIDEO_CODEC => [
40
                'pattern' => '-c:v %s',
41
            ],
42 22
            ConversionParamsInterface::PARAM_VIDEO_BITRATE => [
43
                'pattern' => '-b:v %s',
44
            ],
45 22
            ConversionParamsInterface::PARAM_VIDEO_MIN_BITRATE => [
46
                'pattern' => '-minrate %s',
47
            ],
48 22
            ConversionParamsInterface::PARAM_VIDEO_MAX_BITRATE => [
49
                'pattern' => '-maxrate %s',
50
            ],
51
52 22
            ConversionParamsInterface::PARAM_AUDIO_CODEC => [
53
                'pattern' => '-c:a %s',
54
            ],
55 22
            ConversionParamsInterface::PARAM_AUDIO_BITRATE => [
56
                'pattern' => '-b:a %s',
57
            ],
58 22
            ConversionParamsInterface::PARAM_PIX_FMT => [
59
                'pattern' => '-pix_fmt %s',
60
            ],
61 22
            ConversionParamsInterface::PARAM_PRESET => [
62
                'pattern' => '-preset %s',
63
            ],
64 22
            ConversionParamsInterface::PARAM_SPEED => [
65
                'pattern' => '-speed %d',
66
            ],
67 22
            ConversionParamsInterface::PARAM_THREADS => [
68
                'pattern' => '-threads %d',
69
            ],
70 22
            ConversionParamsInterface::PARAM_KEYFRAME_SPACING => [
71
                'pattern' => '-g %d',
72
            ],
73 22
            ConversionParamsInterface::PARAM_QUALITY => [
74
                'pattern' => '-quality %s',
75
            ],
76
77 22
            ConversionParamsInterface::PARAM_VIDEO_QUALITY_SCALE => [
78
                'pattern' => '-qscale:v %d',
79
            ],
80
81 22
            ConversionParamsInterface::PARAM_CRF => [
82
                'pattern' => '-crf %d',
83
            ],
84 22
            ConversionParamsInterface::PARAM_STREAMABLE => [
85
                'pattern' => '-movflags +faststart',
86
            ],
87
88 22
            ConversionParamsInterface::PARAM_FRAME_PARALLEL => [
89
                'pattern' => '-frame-parallel %s',
90
            ],
91 22
            ConversionParamsInterface::PARAM_TILE_COLUMNS => [
92
                'pattern' => '-tile-columns %s',
93
            ],
94 22
            ConversionParamsInterface::PARAM_TUNE => [
95
                'pattern' => '-tune %s',
96
            ],
97 22
            ConversionParamsInterface::PARAM_VIDEO_FILTER => [
98
                'pattern' => '-vf %s',
99
            ],
100 22
            ConversionParamsInterface::PARAM_OVERWRITE => [
101
                'pattern' => '-y',
102
            ],
103 22
            ConversionParamsInterface::PARAM_VIDEO_FRAMES => [
104
                'pattern' => '-frames:v %d',
105
            ],
106 22
            ConversionParamsInterface::PARAM_NOAUDIO => [
107
                'pattern' => '-an',
108
            ],
109
110 22
            ConversionParamsInterface::PARAM_SEEK_START => [
111
                'pattern' => '-ss %s',
112
            ],
113
114 22
            ConversionParamsInterface::PARAM_SEEK_END => [
115
                'pattern' => '-to %s',
116
            ],
117
        ];
118
    }
119
120
    /**
121
     * @return array<string, string>
122
     *
123
     * @throws UnsupportedParamException
124
     * @throws UnsupportedParamValueException
125
     */
126 22
    public function getMappedConversionParams(ConversionParamsInterface $conversionParams): array
127
    {
128 22
        $args             = [];
129 22
        $supportedOptions = $this->getParamsOptions();
130
131
        // Add default overwrite option if not set
132 22
        $overwriteParam = ConversionParamsInterface::PARAM_OVERWRITE;
133 22
        if (!$conversionParams->hasParam($overwriteParam)) {
134 19
            $conversionParams = $conversionParams->withBuiltInParam(
135 19
                $overwriteParam,
136 19
                true
137
            );
138
        }
139
140 22
        foreach ($conversionParams->toArray() as $paramName => $value) {
141 22
            if (!array_key_exists($paramName, $supportedOptions)) {
142
                throw new UnsupportedParamException(
143
                    sprintf(
144
                        'FFMpegAdapter does not support param \'%s\'',
145
                        $paramName
146
                    )
147
                );
148
            }
149 22
            $pattern = $supportedOptions[$paramName]['pattern'];
150 22
            if (is_bool($value)) {
151 21
                $args[$paramName] = $value ? $pattern : '';
152 21
            } elseif ($value instanceof FFMpegCLIValueInterface) {
153
                // Will test also FFMpegVideoFilterInterface
154 11
                $args[$paramName] = sprintf($pattern, $value->getFFmpegCLIValue());
155 19
            } elseif (is_string($value) || is_int($value)) {
156 18
                $args[$paramName] = sprintf($pattern, $value);
157
            } else {
158 1
                throw new UnsupportedParamValueException(
159 1
                    sprintf(
160 1
                        'Param \'%s\' has an unsupported type: \'%s\'',
161 1
                        $paramName,
162 22
                        is_object($value) ? get_class($value) : gettype($value)
163
                    )
164
                );
165
            }
166
        }
167
168 21
        return $args;
169
    }
170
171
    /**
172
     * @param array<int|string, string>    $arguments
173
     * @param string|null                  $inputFile  if <null> will not prepend '-i inputFile' in args
174
     * @param null|string|PlatformNullFile $outputFile
175
     *
176
     * @throws InvalidArgumentException
177
     */
178 17
    public function getCliCommand(array $arguments, ?string $inputFile, $outputFile = null): string
179
    {
180 17
        $inputArg = ($inputFile !== null && $inputFile !== '')
181 17
                        ? sprintf('-i %s', escapeshellarg($inputFile))
182 17
                        : '';
183
184 17
        $outputArg = '';
185 17
        if ($outputFile instanceof PlatformNullFile) {
186 1
            $outputArg = $outputFile->getNullFile();
187 16
        } elseif (is_string($outputFile)) {
188 15
            $outputArg = sprintf('%s', escapeshellarg($outputFile));
189 1
        } elseif ($outputFile !== null) {
0 ignored issues
show
introduced by
The condition $outputFile !== null is always false.
Loading history...
190 1
            throw new InvalidArgumentException(sprintf(
191 1
                'Output file must be either a non empty string, null or PlatformNullFile (type %s)',
192 1
                gettype($outputFile)
193
            ));
194
        }
195
196 16
        $ffmpegCmd = trim(sprintf(
197 16
            '%s %s %s %s',
198 16
            $this->ffmpegConfig->getBinary(),
199 16
            $inputArg,
200 16
            implode(' ', $arguments),
201 16
            $outputArg
202
        ));
203
204 16
        return $ffmpegCmd;
205
    }
206
}
207