Passed
Push — master ( bf86e6...5ea322 )
by Sébastien
07:21
created

FFMpegAdapter   A

Complexity

Total Complexity 18

Size/Duplication

Total Lines 186
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 100
dl 0
loc 186
rs 10
c 0
b 0
f 0
wmc 18

4 Methods

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