Failed Conditions
Push — master ( bd9fc8...d384bc )
by Sébastien
03:00
created

src/VideoConvert.php (2 issues)

Labels
Severity
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Soluble\MediaTools;
6
7
use ProcessFailedException;
0 ignored issues
show
The type ProcessFailedException was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
8
use Soluble\MediaTools\Config\FFMpegConfig;
9
use Soluble\MediaTools\Exception\FileNotFoundException;
10
use Soluble\MediaTools\Filter\Video\EmptyVideoFilter;
11
use Soluble\MediaTools\Filter\Video\VideoFilterChain;
12
use Soluble\MediaTools\Filter\Video\VideoFilterInterface;
13
use Soluble\MediaTools\Filter\Video\VideoFilterTypeDenoiseInterface;
14
use Soluble\MediaTools\Filter\Video\YadifVideoFilter;
15
use Soluble\MediaTools\Util\CommonAssertionsTrait;
16
use Symfony\Component\Process\Process;
17
18
class VideoConvert
19
{
20
    use CommonAssertionsTrait;
21
22
    /** @var FFMpegConfig */
23
    protected $ffmpegConfig;
24
25
    /** @var VideoProbe */
26
    protected $videoProbe;
27
28 1
    public function __construct(FFMpegConfig $ffmpegConfig, VideoProbe $videoProbe)
29
    {
30 1
        $this->videoProbe   = $videoProbe;
31 1
        $this->ffmpegConfig = $ffmpegConfig;
32 1
        $this->ffmpegConfig->getProcess()->ensureBinaryExists();
33 1
    }
34
35
    /**
36
     * Return ready-to-run symfony process object that you can use
37
     * to `run()` or `start()` programmatically. Useful if you want to make
38
     * things async...
39
     *
40
     * @see https://symfony.com/doc/current/components/process.html
41
     *
42
     * @throws FileNotFoundException when inputFile does not exists
43
     */
44 1
    public function getConversionProcess(string $inputFile, string $outputFile, VideoConvertParams $convertParams): Process
45
    {
46 1
        $this->ensureFileExists($inputFile);
47
48 1
        $process = $this->ffmpegConfig->getProcess();
49
50 1
        if (!$convertParams->hasOption(VideoConvertParams::OPTION_THREADS) && $this->ffmpegConfig->getThreads() !== null) {
51
            $convertParams = $convertParams->withThreads($this->ffmpegConfig->getThreads());
52
        }
53
54 1
        $ffmpegCmd = $process->buildCommand(
55 1
            array_merge(
56
                [
57 1
                    sprintf('-i %s', escapeshellarg($inputFile)), // input filename
58
                ],
59 1
                $convertParams->getFFMpegArguments(),
60
                [
61 1
                    '-y', // tell to overwrite
62 1
                    sprintf('%s', escapeshellarg($outputFile)),
63
                ]
64
            )
65
        );
66
67 1
        $process = new Process($ffmpegCmd);
68 1
        $process->setTimeout($this->ffmpegConfig->getConversionTimeout());
69 1
        $process->setIdleTimeout($this->ffmpegConfig->getConversionIdleTimeout());
70
71 1
        return $process;
72
    }
73
74
    /**
75
     * Run a conversion, throw exception on error.
76
     *
77
     * @throws FileNotFoundException    when inputFile does not exists
78
     * @throws ProcessRuntimeException  The base class for all process exceptions
79
     * @throws ProcessFailedException   Whenever the process has failed to run
80
     * @throws ProcessTimedOutException Whenever a timeout occured before the process finished
81
     * @throws ProcessSignaledException Whenever the process was stopped
82
     */
83
    public function convert(string $inputFile, string $outputFile, VideoConvertParams $convertParams, ?VideoFilterInterface $videoFilter = null): void
84
    {
85
        $process = $this->getConversionProcess($inputFile, $outputFile, $convertParams);
86
        try {
87
            $process->mustRun();
88
        } catch (ProcessRuntimeException $e) {
0 ignored issues
show
The type Soluble\MediaTools\ProcessRuntimeException was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
89
            throw $e;
90
        } catch (FileNotFoundException $e) {
91
            throw $e;
92
        }
93
    }
94
95
    /**
96
     * Try to guess if the original video is interlaced (bff, tff) and
97
     * return ffmpeg yadif filter argument and add denoise filter if any.
98
     *
99
     * @see https://ffmpeg.org/ffmpeg-filters.html (section yadif)
100
     * @see https://askubuntu.com/a/867203
101
     *
102
     * @return VideoFilterInterface|VideoFilterChain|EmptyVideoFilter|YadifVideoFilter
103
     */
104
    public function getDeintFilter(string $videoFile, ?VideoFilterTypeDenoiseInterface $denoiseFilter = null): VideoFilterInterface
105
    {
106
        $guess       = $this->videoProbe->guessInterlacing($videoFile);
107
        $deintFilter = $guess->getDeinterlaceVideoFilter();
108
        // skip all filters if video is not interlaces
109
        if ($deintFilter instanceof EmptyVideoFilter) {
110
            return $deintFilter;
111
        }
112
        if ($denoiseFilter !== null) {
113
            $videoFilterChain = new VideoFilterChain();
114
            $videoFilterChain->addFilter($deintFilter);
115
            $videoFilterChain->addFilter($denoiseFilter);
116
117
            return $videoFilterChain;
118
        }
119
120
        return $deintFilter;
121
    }
122
123
    /*
124
    public function transcodeMultiPass(string $videoFile, string $outputFile, VideoConvertParams $convertParams, VideoFilterInterface $videoFilter=null): void {
125
126
        $this->ensureFileExists($videoFile);
127
        if ($videoFilter === null) {
128
            $videoFilter = new EmptyVideoFilter();
129
        }
130
131
132
        $threads = $convertParams->getOption(VideoConvertParams::OPTION_THREADS, $this->ffmpegConfig->getThreads());
133
134
        $ffmpegBin = $this->ffmpegConfig->getBinary();
135
136
        $commonArgs = array_merge([
137
                $ffmpegBin,
138
                sprintf('-i %s', escapeshellarg($videoFile)), // input filename
139
                $videoFilter->getFFMpegCliArgument(), // add -vf yadif,nlmeans
140
                ($threads === null) ? '' : sprintf('-threads %s', $threads),
141
        ], $convertParams->getFFMpegArguments());
142
143
        $pass1Cmd = implode(' ', array_merge(
144
            $commonArgs,
145
            [
146
                '-pass 1',
147
                // tells VP9 to encode really fast, sacrificing quality. Useful to speed up the first pass.
148
                '-speed 4',
149
                '-y /dev/null',
150
            ]
151
        ));
152
153
        $pass2Cmd = implode( ' ', array_merge(
154
            $commonArgs,
155
            [
156
                '-pass 2',
157
                // speed 1 is a good speed vs. quality compromise.
158
                // Produces output quality typically very close to speed 0, but usually encodes much faster.
159
                '-speed 1',
160
                '-y',
161
                sprintf("%s", escapeshellarg($outputFile))
162
            ]
163
        ));
164
165
166
        $process = new Process($pass1Cmd);
167
        $process->setTimeout(null);
168
        $process->setIdleTimeout(60); // 60 seconds without output will stop the process
169
        $process->start();
170
        foreach ($process as $type => $data) {
171
            if ($process::OUT === $type) {
172
                echo "\nRead from stdout: ".$data;
173
            } else { // $process::ERR === $type
174
                echo "\nRead from stderr: ".$data;
175
            }
176
        }
177
178
        $process = new Process($pass2Cmd);
179
        $process->setTimeout(null);
180
        $process->setIdleTimeout(60); // 60 seconds without output will stop the process
181
        $process->start();
182
        foreach ($process as $type => $data) {
183
            if ($process::OUT === $type) {
184
                echo "\nRead from stdout: ".$data;
185
            } else { // $process::ERR === $type
186
                echo "\nRead from stderr: ".$data;
187
            }
188
        }
189
190
    }
191
    */
192
}
193