Skip to content

✔ VideoAnalyzer

The VideoAnalyzer service acts as a wrapper over ffmpeg and will analyze a video stream. It does not query video metadata (like ffprobe or the Video\VideoInfoReader) but really reads the video to infer some characteristics (currently only interlace detection is implemented...).

<?php
use Soluble\MediaTools\Video\Config\FFMpegConfig;
use Soluble\MediaTools\Video\Exception\AnalyzerExceptionInterface;
use Soluble\MediaTools\Video\VideoAnalyzer;

$analyzer = new VideoAnalyzer(new FFMpegConfig('/path/to/ffmpeg'));


try {
    $interlaceGuess = $analyzer->detectInterlacement(
        '/path/input.mov',
        // Optional:
        //   $maxFramesToAnalyze, default: 1000
        $maxFramesToAnalyze = 200
    );

} catch(AnalyzerExceptionInterface $e) {
    // See chapter about exception !!!
}

$interlaced = $interlaceGuess->isInterlaced(
    // Optional:
    //  $threshold, default 0.25 (if >=25% interlaced frames, then true)
    0.25
);

Requirements

You'll need to have ffmpeg installed on your system.

Initialization

The VideoAnalyzer 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\VideoAnalyzer;

$converter = new VideoAnalyzer(
    // @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 Video\VideoAnalyzerFactory and/or FFMpegConfigFactory to get an example based on a psr-11 compatible container. See also the provided default configuration file.

Usage

Interlacement detection

<?php
use Soluble\MediaTools\Video\Config\FFMpegConfig;
use Soluble\MediaTools\Video\Exception\AnalyzerExceptionInterface;
use Soluble\MediaTools\Video\VideoAnalyzer;

$analyzer = new VideoAnalyzer(new FFMpegConfig('/path/to/ffmpeg'));

try {
    $interlaceGuess = $analyzer->detectInterlacement(
        '/path/input.mov',
        // Optional:
        //   $maxFramesToAnalyze, default: 1000
        //   (at 25fps -> 40 seconds)
        $maxFramesToAnalyze = 1000
    );

} catch(AnalyzerExceptionInterface $e) {
    // See chapter about exception !!!
}

$interlaced = $interlaceGuess->isInterlaced(
    // Optional:
    //  $threshold, default 0.25 (if >=25% interlaced frames, then true)
    0.25
);

Exceptions

You can safely catch exceptions with the generic Soluble\MediaTools\Video\Exception\ExceptionInterface, alternatively you can also :

<?php
use Soluble\MediaTools\Video\VideoAnalyzer;
use Soluble\MediaTools\Video\Exception as VE;

/** @var VideoAnalyzer $analyzer */

try {
    $interlaceGuess = $analyzer->detectInterlacement(
        '/path/input.mov'
    );

} catch(VE\MissingInputFileException $e) {

    // 'i.mov does not exists

    echo $e->getMessage();

} catch(

    // The following 3 exeptions 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

Convert with deinterlace detection

<?php

use Soluble\MediaTools\Video\VideoAnalyzer;
use Soluble\MediaTools\Video\Filter\{VideoFilterChain, Hqdn3DVideoFilter, YadifVideoFilter};

/** @var VideoAnalyzer $analyzer */

$interlaceGuess = $analyzer->detectInterlacement(
            '/path/input_video.mov',
            // $max_frames_to_analyze:
            //  - Less is faster... but let's assume some older
            //    videos starts with black screen... 1500 at
            //    25fps = 60 seconds
            1500
);

$convertParams = (new \Soluble\MediaTools\Video\VideoConvertParams())
                    ->withVideoCodec('libvpx-vp9')
                    ->withVideoBitrate('750k');

// Add the deint and denoise filters only if 40% frames have been
// detected as interlaced

if ($interlaceGuess->isInterlaced($threshold=0.4)) {
    $convertParams = $convertParams->withVideoFilter(
        new VideoFilterChain([
            // This will deinterlace
            new YadifVideoFilter(),
            // This will slightly denoise
            new Hqdn3DVideoFilter()
        ])
    );
}

$converter->convert(
    '/path/inputFile.mov',
    '/path/outputFile.webm',
    $convertParams
);