✔ VideoThumbGenerator
The VideoThumbGenerator service acts as a wrapper over ffmpeg and deal with video thumbnail creation.
It exposes an immutable api for thumbnail generation parameters and attempt to make debugging easier with clean exceptions. You can also inject any psr-3 compatible logger if you don't want to log issues by yourself.
<?php
use Soluble\MediaTools\Video\Config\FFMpegConfig;
use Soluble\MediaTools\Video\Exception\ConverterExceptionInterface;
use Soluble\MediaTools\Video\{VideoThumbGenerator, VideoThumbParams};
$generator = new VideoThumbGenerator(new FFMpegConfig('/path/to/ffmpeg'));
$params = (new VideoThumbParams())
->withTime(1.25);
try {
$generator->makeThumbnail(
'/path/inputFile.mov',
'/path/outputFile.jpg',
$params
);
} catch(ConverterExceptionInterface $e) {
// See chapter about exception !!!
}
Requirements¶
You'll need to have ffmpeg installed on your system.
Initialization¶
The VideoThumbGenerator
requires an FFMpegConfig
object as first parameter.
This is where you set the location of the ffmpeg binary, the number of threads you allow for conversions
and the various timeouts if needed. The second parameter can be used to inject any psr-3 compatible logger.
<?php
use Soluble\MediaTools\Video\Config\{FFMpegConfig, FFMpegConfigInterface};
use Soluble\MediaTools\Video\VideoThumbGenerator;
$converter = new VideoThumbGenerator(
// @param FFMpegConfigInterface
new FFMpegConfig(
// (?string) - path to ffmpeg binary (default: ffmpeg/ffmpeg.exe)
$binary = null,
// (?int) - ffmpeg default threads (null: single-thread)
$threads = null,
// (?float) - max time in seconds for ffmpeg process (null: disable)
$timeout = null,
// (?float) - max idle time in seconds for ffmpeg process
$idleTimeout = null,
// (array) - additional environment variables
$env = []
),
// @param ?\Psr\Log\LoggerInterface - Default to `\Psr\Log\NullLogger`.
$logger = null
);
Tip: initialize in a container (psr-11)
It's a good idea to register services in a container.
Depending on available framework integrations, you may have a look to the
VideoThumbGeneratorFactory
and/or FFMpegConfigFactory
to get an example based on a psr-11 compatible container.
See also the provided default configuration file.
Usage¶
Thumbnailing¶
Typically you'll use the VideoThumbGenerator::makeThumbnail()
method in which you specify the input/output files
as well as the thumbnail params.
<?php
use Soluble\MediaTools\Video\Config\FFMpegConfig;
use Soluble\MediaTools\Video\{VideoThumbGenerator, VideoThumbParams, SeekTime};
$generator = new VideoThumbGenerator(new FFMpegConfig('/path/to/ffmpeg'));
$params = (new VideoThumbParams())
->withTime(1.25);
// or: ->withSeekTime(new SeekTime(1.25));
$generator->makeThumbnail(
'/path/inputFile.mov',
'/path/outputFile.jpg',
$params
);
Warning, if the time is out of range, an
NoOutputGeneratedException
will be thrown.
The makeThumbnail()
method will automatically honour the process timeouts, logger... as specified during
service initialization.
What if I need more control over the process ? (advanced usage)
You can use the Video\VideoThumbGenerator::getSymfonyProcess(string $inputFile, string $outputFile, VideoConvertParamsInterface $convertParams, ?ProcessParamsInterface $processParams = null): Process
to get more control on the conversion process.
<?php
$process = $thumbService->getSymfonyProcess(
'/path/inputFile.mov',
'/path/outputFile.jpg',
(new VideoThumbParams())
->withTime(1.25)
);
$process->start();
foreach ($process as $type => $data) {
if ($process::OUT === $type) {
echo "\nRead from stdout: ".$data;
} else { // $process::ERR === $type
echo "\nRead from stderr: ".$data;
}
}
Parameters¶
The Video\VideoThumbParams
exposes an immutable api that attempt to mimic ffmpeg params.
<?php
use Soluble\MediaTools\Video\VideoThumbParams;
$params = (new VideoThumbParams())
->withQualityScale(2)
->withTime(12.23);
// alternatively
//->withSeekTime(SeekTime::createFromHMS('0:00:12.23'));
Immutable api, what does it change for me ? (vs fluent)
VideoThumbParams exposes an immutable style api (->withXXX()
, like PSR-7 for example).
It means that the original object is never touched, the withXXX()
methods will return a newly
created object.
Please be aware of it especially if you're used to fluent interfaces as both expose chainable methods... your primary reflexes might cause pain:
<?php
$params = (new VideoThumbParams());
$newParams = $params->withSeekTime(new SeekTime(1.1212));
// $params does not contain SeekTime (incorrect usage)
$generator->convert('i.mov', 'output.jpg', $params);
// $newParams contains SeekTime (correct)
$generator->convert('i.mov', 'output.jpg', $newParams);
Here's a list of categorized built-in methods you can use. See the ffmpeg doc for more information.
- Time related:
Method | FFmpeg arg(s) | Example(s) | Note(s) |
---|---|---|---|
withTime(float) |
-ss ◌ | 61.123 | Set the time in seconds, decimals are considered milliseconds |
withFrame(int) |
-vf "select=eq()" | 10 | Choose a specific frame, useful for getting the last image for example |
withSeekTime(SeekTime) |
-ss ◌ | SeekTime::createFromHms('0:00:01.9') |
- Quality options:
Method | FFmpeg arg(s) | Example(s) | Note(s) |
---|---|---|---|
withQualityScale(int) |
-qscale:v ◌ | 5 |
- General process options:
Method | FFmpeg arg(s) | Example(s) | Note(s) |
---|---|---|---|
withOutputFormat(string) |
-format ◌ | jpeg,png… | file extension (if not provided) |
withOverwrite() |
-y | by default. overwrite if file exists | |
withNoOverwrite() |
throw exception if output exists |
- Other methods:
Method | Note(s) |
---|---|
withBuiltInParam(string, mixed) |
With any supported built-in param, see constants. |
withoutParam(string) |
Without the specified parameter. |
getParam(string $param): mixed |
Return the param calue or throw UnsetParamExeption if not set. |
hasParam(string $param): bool |
Whether the param has been set. |
toArray(): array |
Return the object as array. |
Filters¶
Video filters can be set to the VideoThumbParams through the ->withVideoFilter(VideoFilterInterface $videoFilter)
method:
<?php
use Soluble\MediaTools\Video\Filter;
$params = (new VideoConvertParams())
->withVideoFilter(
new Filter\VideoFilterChain([
// A scaling filter
new Filter\ScaleFilter(800, 600),
// Deint filter
new Filter\YadifVideoFilter(),
// Denoise (slow but best denoiser, ok for thumbs)
new Filter\NlmeansVideoFilter()
])
);
See the complete video filters doc here
Exceptions¶
You can safely catch exceptions with the generic Soluble\MediaTools\VideoException\ConverterExceptionInterface
,
alternatively you can also :
<?php
use Soluble\MediaTools\Video\{VideoThumbGenerator, VideoThumbParams};
use Soluble\MediaTools\Video\Exception as VE;
/** @var VideoThumbGenerator $generator */
$params = (new VideoThumbParams());
try {
$generator->makeThumbnail('i.mov', 'out.jpg', $params);
} catch(VE\MissingInputFileException $e) {
// 'i.mov does not exists
echo $e->getMessage();
// All exception below implements Ve\ConverterExceptionInterface
// It's possible to get them all in once
} catch(VE\MissingTimeException $e) {
// Missing required time
echo $e->getMessage();
} catch(VE\NoOutputGeneratedException $e) {
// Probably the time seek was out of range
// and no thumbnail was generated
echo $e->getMessage();
} catch(
// The following 3 exceptions are linked to process
// failure 'ffmpeg exit code != 0) and implements
//
// - `VE\ConversionProcessExceptionInterface`
// (* which extends Mediatools\Common\Exception\ProcessExceptionInterface)
//
// in case you want to catch them all-in-once
VE\ProcessFailedException
| VE\ProcessSignaledException
| VE\ProcessTimedOutException $e)
{
echo $e->getMessage();
// Because they implement ProcessExceptionInterface
// we can get a reference to the executed (symfony) process:
$process = $e->getProcess();
echo $process->getExitCode();
echo $process->getErrorOutput();
} catch(VE\ConverterExceptionInterface $e) {
// Other exceptions can be
//
// - VE\RuntimeException
// - VE\InvalidParamException (should not happen)
}
Recipes¶
Make a thumbnail of the last frame¶
To get the last frame, use the
VideoInfoReader
to get the total number of frames.
<?php
use Soluble\MediaTools\Video\Config\FFProbeConfig;
use Soluble\MediaTools\Video\Config\FFMpegConfig;
use Soluble\MediaTools\Video\{VideoThumbGenerator, VideoThumbParams};
use Soluble\MediaTools\Video\VideoInfoReader;
use Soluble\MediaTools\Video\Exception\ConverterExceptionInterface;
$myVideo = '/path/video.mp4';
// Can be taken from a service
$infoReader = new VideoInfoReader(new FFProbeConfig('/path/to/ffprobe'));
$generator = new VideoThumbGenerator(new FFMpegConfig('/path/to/ffmpeg'));
$videoInfo = $infoReader->getInfo($myVideo);
$params = (new VideoThumbParams())
->withFrame(
$videoInfo->getNbFrames()
);
try {
$generator->makeThumbnail(
$myVideo,
'/path/outputFile.jpg',
$params
);
} catch(ConverterExceptionInterface $e) {
// See chapter about exception !!!
}