Passed
Push — master ( dc3048...353d8c )
by Sébastien
03:11
created

FFMpegAdapter   A

Complexity

Total Complexity 19

Size/Duplication

Total Lines 187
Duplicated Lines 0 %

Test Coverage

Coverage 94.94%

Importance

Changes 0
Metric Value
wmc 19
eloc 103
dl 0
loc 187
ccs 75
cts 79
cp 0.9494
rs 10
c 0
b 0
f 0

5 Methods

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