1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
declare(strict_types=1); |
4
|
|
|
|
5
|
|
|
namespace Soluble\MediaTools; |
6
|
|
|
|
7
|
|
|
use Soluble\MediaTools\Config\FFMpegConfigInterface; |
8
|
|
|
use Soluble\MediaTools\Exception\FileNotFoundException; |
9
|
|
|
use Soluble\MediaTools\Util\Assert\PathAssertionsTrait; |
10
|
|
|
use Soluble\MediaTools\Video\Converter\FFMpegAdapter; |
11
|
|
|
use Soluble\MediaTools\Video\Filter\Type\VideoFilterInterface; |
12
|
|
|
use Soluble\MediaTools\Video\SeekTime; |
13
|
|
|
use Soluble\MediaTools\Video\ThumbServiceInterface; |
14
|
|
|
use Symfony\Component\Process\Exception as SPException; |
15
|
|
|
use Symfony\Component\Process\Process; |
16
|
|
|
|
17
|
|
|
class VideoThumbService implements ThumbServiceInterface |
18
|
|
|
{ |
19
|
|
|
use PathAssertionsTrait; |
20
|
|
|
|
21
|
|
|
/** @var FFMpegConfigInterface */ |
22
|
|
|
protected $ffmpegConfig; |
23
|
|
|
|
24
|
|
|
/** @var FFMpegAdapter */ |
25
|
|
|
protected $adapter; |
26
|
|
|
|
27
|
3 |
|
public function __construct(FFMpegConfigInterface $ffmpegConfig) |
28
|
|
|
{ |
29
|
3 |
|
$this->ffmpegConfig = $ffmpegConfig; |
30
|
3 |
|
$this->adapter = new FFMpegAdapter($ffmpegConfig); |
31
|
3 |
|
} |
32
|
|
|
|
33
|
|
|
/** |
34
|
|
|
* Return ready-to-run symfony process object that you can use |
35
|
|
|
* to `run()` or `start()` programmatically. Useful if you want |
36
|
|
|
* handle the process your way... |
37
|
|
|
* |
38
|
|
|
* @see https://symfony.com/doc/current/components/process.html |
39
|
|
|
* |
40
|
|
|
* @throws FileNotFoundException when inputFile does not exists |
41
|
|
|
*/ |
42
|
3 |
|
public function getSymfonyProcess(string $videoFile, string $thumbnailFile, ?SeekTime $time = null, ?VideoFilterInterface $videoFilter = null): Process |
43
|
|
|
{ |
44
|
3 |
|
$this->ensureFileExists($videoFile); |
45
|
|
|
|
46
|
2 |
|
$params = (new VideoConversionParams()); |
47
|
|
|
|
48
|
2 |
|
if ($time !== null) { |
49
|
|
|
// For performance reasons time seek must be |
50
|
|
|
// made at the beginning of options |
51
|
2 |
|
$params = $params->withSeekStart($time); |
52
|
|
|
} |
53
|
2 |
|
$params = $params->withVideoFrames(1); |
54
|
|
|
|
55
|
2 |
|
if ($videoFilter !== null) { |
56
|
1 |
|
$params = $params->withVideoFilter($videoFilter); |
57
|
|
|
} |
58
|
|
|
|
59
|
|
|
// Quality scale for the mjpeg encoder |
60
|
2 |
|
$params->withVideoQualityScale(2); |
61
|
|
|
|
62
|
2 |
|
$arguments = $this->adapter->getMappedConversionParams($params); |
63
|
2 |
|
$ffmpegCmd = $this->adapter->getCliCommand($arguments, $videoFile, $thumbnailFile); |
64
|
|
|
|
65
|
2 |
|
$process = new Process($ffmpegCmd); |
66
|
2 |
|
$process->setTimeout($this->ffmpegConfig->getTimeout()); |
67
|
2 |
|
$process->setIdleTimeout($this->ffmpegConfig->getIdleTimeout()); |
68
|
2 |
|
$process->setEnv($this->ffmpegConfig->getEnv()); |
69
|
|
|
|
70
|
2 |
|
return $process; |
71
|
|
|
} |
72
|
|
|
|
73
|
|
|
/** |
74
|
|
|
* @throws FileNotFoundException |
75
|
|
|
* @throws SPException\RuntimeException |
76
|
|
|
*/ |
77
|
3 |
|
public function makeThumbnail(string $videoFile, string $thumbnailFile, ?SeekTime $time = null, ?VideoFilterInterface $videoFilter = null, ?callable $callback = null): void |
78
|
|
|
{ |
79
|
3 |
|
$process = $this->getSymfonyProcess($videoFile, $thumbnailFile, $time, $videoFilter); |
80
|
|
|
try { |
81
|
2 |
|
$process->mustRun($callback); |
82
|
|
|
} catch (SPException\RuntimeException $symfonyProcessException) { |
83
|
|
|
// will include: ProcessFailedException|ProcessTimedOutException|ProcessSignaledException |
|
|
|
|
84
|
|
|
throw $symfonyProcessException; |
85
|
|
|
} catch (FileNotFoundException $e) { |
86
|
|
|
throw $e; |
87
|
|
|
} |
88
|
2 |
|
} |
89
|
|
|
} |
90
|
|
|
|
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.
The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.
This check looks for comments that seem to be mostly valid code and reports them.