Failed Conditions
Push — master ( 1f1533...4e2f19 )
by Sébastien
02:05
created

FFMpegAdapter::getCliCommand()   B

Complexity

Conditions 6
Paths 16

Size

Total Lines 32
Code Lines 23

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 24
CRAP Score 6

Importance

Changes 0
Metric Value
eloc 23
dl 0
loc 32
ccs 24
cts 24
cp 1
rs 8.9297
c 0
b 0
f 0
cc 6
nc 16
nop 4
crap 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\UnescapedFileInterface;
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 29
    public function __construct(FFMpegConfigInterface $ffmpegConfig)
20
    {
21 29
        $this->ffmpegConfig = $ffmpegConfig;
22 29
    }
23
24
    /**
25
     * @return array<string, array<string, string>>
26
     */
27 28
    public function getParamsOptions(): array
28
    {
29
        return [
30 28
            VideoConvertParamsInterface::PARAM_OUTPUT_FORMAT => [
31
                'pattern' => '-f %s',
32
            ],
33 28
            VideoConvertParamsInterface::PARAM_VIDEO_CODEC => [
34
                'pattern' => '-c:v %s',
35
            ],
36 28
            VideoConvertParamsInterface::PARAM_VIDEO_BITRATE => [
37
                'pattern' => '-b:v %s',
38
            ],
39 28
            VideoConvertParamsInterface::PARAM_VIDEO_MIN_BITRATE => [
40
                'pattern' => '-minrate %s',
41
            ],
42 28
            VideoConvertParamsInterface::PARAM_VIDEO_MAX_BITRATE => [
43
                'pattern' => '-maxrate %s',
44
            ],
45 28
            VideoConvertParamsInterface::PARAM_AUDIO_CODEC => [
46
                'pattern' => '-c:a %s',
47
            ],
48 28
            VideoConvertParamsInterface::PARAM_AUDIO_BITRATE => [
49
                'pattern' => '-b:a %s',
50
            ],
51 28
            VideoConvertParamsInterface::PARAM_PIX_FMT => [
52
                'pattern' => '-pix_fmt %s',
53
            ],
54 28
            VideoConvertParamsInterface::PARAM_PRESET => [
55
                'pattern' => '-preset %s',
56
            ],
57 28
            VideoConvertParamsInterface::PARAM_SPEED => [
58
                'pattern' => '-speed %d',
59
            ],
60 28
            VideoConvertParamsInterface::PARAM_THREADS => [
61
                'pattern' => '-threads %d',
62
            ],
63 28
            VideoConvertParamsInterface::PARAM_KEYFRAME_SPACING => [
64
                'pattern' => '-g %d',
65
            ],
66 28
            VideoConvertParamsInterface::PARAM_QUALITY => [
67
                'pattern' => '-quality %s',
68
            ],
69 28
            VideoConvertParamsInterface::PARAM_VIDEO_QUALITY_SCALE => [
70
                'pattern' => '-qscale:v %d',
71
            ],
72 28
            VideoConvertParamsInterface::PARAM_CRF => [
73
                'pattern' => '-crf %d',
74
            ],
75 28
            VideoConvertParamsInterface::PARAM_STREAMABLE => [
76
                'pattern' => '-movflags +faststart',
77
            ],
78 28
            VideoConvertParamsInterface::PARAM_FRAME_PARALLEL => [
79
                'pattern' => '-frame-parallel %s',
80
            ],
81 28
            VideoConvertParamsInterface::PARAM_TILE_COLUMNS => [
82
                'pattern' => '-tile-columns %s',
83
            ],
84 28
            VideoConvertParamsInterface::PARAM_TUNE => [
85
                'pattern' => '-tune %s',
86
            ],
87 28
            VideoConvertParamsInterface::PARAM_VIDEO_FILTER => [
88
                'pattern' => '-filter:v %s',
89
            ],
90 28
            VideoConvertParamsInterface::PARAM_OVERWRITE => [
91
                'pattern' => '-y',
92
            ],
93 28
            VideoConvertParamsInterface::PARAM_VIDEO_FRAMES => [
94
                'pattern' => '-frames:v %d',
95
            ],
96 28
            VideoConvertParamsInterface::PARAM_NOAUDIO => [
97
                'pattern' => '-an',
98
            ],
99 28
            VideoConvertParamsInterface::PARAM_SEEK_START => [
100
                'pattern' => '-ss %s',
101
            ],
102 28
            VideoConvertParamsInterface::PARAM_SEEK_END => [
103
                'pattern' => '-to %s',
104
            ],
105 28
            VideoConvertParamsInterface::PARAM_PASSLOGFILE => [
106
                'pattern' => '-passlogfile %s',
107
            ],
108 28
            VideoConvertParamsInterface::PARAM_PASS => [
109
                'pattern' => '-pass %s',
110
            ],
111 28
            VideoConvertParamsInterface::PARAM_AUTO_ALT_REF => [
112
                'pattern' => '-auto-alt-ref %s',
113
            ],
114 28
            VideoConvertParamsInterface::PARAM_LAG_IN_FRAMES => [
115
                'pattern' => '-lag-in-frames %s',
116
            ],
117
        ];
118
    }
119
120
    /**
121
     * @return array<string, string>
122
     *
123
     * @throws UnsupportedParamException
124
     * @throws UnsupportedParamValueException
125
     */
126 28
    public function getMappedConversionParams(VideoConvertParamsInterface $conversionParams): array
127
    {
128 28
        $args             = [];
129 28
        $supportedOptions = $this->getParamsOptions();
130
131
        // Add default overwrite option if not set
132 28
        $overwriteParam = VideoConvertParamsInterface::PARAM_OVERWRITE;
133 28
        if (!$conversionParams->hasParam($overwriteParam)) {
134 24
            $conversionParams = $conversionParams->withBuiltInParam(
135 24
                $overwriteParam,
136 24
                true
137
            );
138
        }
139
140 28
        foreach ($conversionParams->toArray() as $paramName => $value) {
141 28
            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 28
            $pattern = $supportedOptions[$paramName]['pattern'];
150 28
            if (is_bool($value)) {
151 27
                $args[$paramName] = $value ? $pattern : '';
152 25
            } elseif ($value instanceof FFMpegCLIValueInterface) {
153
                // Will test also FFMpegVideoFilterInterface
154 14
                $args[$paramName] = sprintf($pattern, $value->getFFmpegCLIValue());
155 23
            } elseif (is_string($value) || is_int($value)) {
156 22
                $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 28
                        is_object($value) ? get_class($value) : gettype($value)
163
                    )
164
                );
165
            }
166
        }
167
168 27
        return $args;
169
    }
170
171
    /**
172
     * @param array<string,string>               $arguments        args that will be added
173
     * @param null|string                        $inputFile
174
     * @param null|string|UnescapedFileInterface $outputFile
175
     * @param array<string,string>               $prependArguments args that must be added at the beginning of the command
176
     *
177
     * @throws InvalidArgumentException
178
     */
179 23
    public function getCliCommand(array $arguments, ?string $inputFile, $outputFile = null, array $prependArguments=[]): string
180
    {
181 23
        $inputArg = ($inputFile !== null && $inputFile !== '')
182 23
                        ? sprintf('-i %s', escapeshellarg($inputFile))
183 23
                        : '';
184
185 23
        $outputArg = '';
186 23
        if ($outputFile instanceof UnescapedFileInterface) {
187 5
            $outputArg = $outputFile->getFile();
188 20
        } elseif (is_string($outputFile)) {
189 18
            $outputArg = sprintf('%s', escapeshellarg($outputFile));
190 2
        } elseif ($outputFile !== null) {
0 ignored issues
show
introduced by
The condition $outputFile !== null is always false.
Loading history...
191 2
            throw new InvalidArgumentException(sprintf(
192 2
                'Output file must be either a non empty string, null or PlatformNullFile (type %s)',
193 2
                gettype($outputFile)
194
            ));
195
        }
196
197 21
        $ffmpegCmd = preg_replace(
198 21
            '/(\ ){2,}/',
199 21
            ' ',
200 21
            trim(sprintf(
201 21
                '%s %s %s %s %s',
202 21
                $this->ffmpegConfig->getBinary(),
203 21
                implode(' ', $prependArguments),
204 21
                $inputArg,
205 21
                implode(' ', $arguments),
206 21
                $outputArg
207
            ))
208
        );
209
210 21
        return $ffmpegCmd;
211
    }
212
213 16
    public function getDefaultThreads(): ?int
214
    {
215 16
        return $this->ffmpegConfig->getThreads();
216
    }
217
}
218