Skip to content

✔ VideoInfoReader

The VideoInfoReader service acts as a wrapper over ffprobe and return information about a video file.

Requirements

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

Initialization

The VideoInfoReader service requires an FFProbeConfig object as first parameter. If needed you can configure the location of the ffprobe binary and the various timeouts.

The second parameter can be used to inject any psr-3 compatible logger.

The third one, any psr-16 (simplecache) compatible cache.

<?php
use Soluble\MediaTools\Video\Config\FFProbeConfig;
use Soluble\MediaTools\Video\Exception\InfoReaderExceptionInterface;
use Soluble\MediaTools\Video\VideoInfoReader;

$infoReader = new VideoInfoReader(
    // @param FFMpegConfigInterface
    new FFProbeConfig(
        // (?string) - path to ffprobe binary (default: ffprobe/ffprobe.exe)
        $binary = null,
        // (?float)  - max time in seconds for ffprobe process (null: disable)
        $timeout = null,
        // (?float)  - max idle time in seconds for ffprobe process
        $idleTimeout = null,
        // (array)   - additional environment variables if needed
        $env = []
    ),
    // @param \Psr\Log\LoggerInterface - Default to `\Psr\Log\NullLogger`.
    $logger = null,
    // @param \Psr\SimpleCache\CacheInterface
    $cache = null
);

try {
    $info = $infoReader->getInfo('/path/video.mp4');
} catch (InfoReaderExceptionInterface $e) {
    // Possibly wrong media, see below for exceptions
    // details
}
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\VideoInfoReaderFactory and/or FFProbeConfigFactory to get an example based on a psr-11 compatible container. See also the provided default configuration file.

Usage

Getting general info

<?php

use Soluble\MediaTools\Video\Config\FFProbeConfig;
use Soluble\MediaTools\Video\Exception\InfoReaderExceptionInterface;
use Soluble\MediaTools\Video\VideoInfoReader;
use Soluble\MediaTools\Video\Info\StreamTypeInterface;

$infoReader = new VideoInfoReader(new FFProbeConfig());

try {
    $info = $infoReader->getInfo('/path/video.mp4');
} catch (InfoReaderExceptionInterface $e) {
    // Possibly wrong media, see below for exceptions
    // details
}


// Total duration
$duration = $info->getDuration();
$filesize = $info->getFileSize();

// i.e 'mov,mp4,m4a,3gp,3g2,mj2'
$format   = $info->getFormatName();

// Streams (will be detailled below)

$info->getVideoStreams();
$info->getAudioStreams();
$info->getSubtitleStreams();

Get video stream.

Get video streams information. (generally one, i.e mkv containers can have multiple)

<?php

use Soluble\MediaTools\Video\Config\FFProbeConfig;
use Soluble\MediaTools\Video\VideoInfoReader;
use Soluble\MediaTools\Video\Exception\InfoReaderExceptionInterface;
use Soluble\MediaTools\Video\Exception\NoStreamException;


$infoReader = new VideoInfoReader(new FFProbeConfig());

try {
    $info = $infoReader->getInfo('/path/video.mp4');
} catch (InfoReaderExceptionInterface $e) {
    // Possibly wrong media, see below for exceptions
    // details
}

$videoStreams = $info->getVideoStreams();

// Option 1: The iterable way

foreach($videoStreams as $vStream) {
    // ...
}

// Option 2: Take the first

try {
    $video = $videoStreams->getFirst();
} catch (NoStreamException $e) {
    // No video stream present
}

$video->getCodecName(); // vp9
$video->getFps($decimals=0); // i.e: 24
$video->getCodecTagString();
$video->getFps($roundedDecimals=null);
$video->getNbFrames();
$video->getHeight();
$video->getWidth();
$video->getDuration();
$video->getDurationTs();

$video->getPixFmt();
$video->getNbFrames();
$video->getTimeBase();
$video->getBitRate();
$video->getTags();
$video->getDisplayAspectRatio();
$video->getSampleAspectRatio();
$video->getCodedWidth();
$video->getCodedHeight();
$video->getRFrameRate();

$aspectRatio = $video->getAspectRatio();
if ($aspectRatio !== null) {
    $aspectRatio->getString(); // '16:9'
    $aspectRatio->getX(); // float
    $aspectRatio->getY(); // float
}

Get audio streams

<?php

use Soluble\MediaTools\Video\Config\FFProbeConfig;
use Soluble\MediaTools\Video\VideoInfoReader;
use Soluble\MediaTools\Video\Exception\InfoReaderExceptionInterface;
use Soluble\MediaTools\Video\Exception\NoStreamException;

$infoReader = new VideoInfoReader(new FFProbeConfig());

try {
    $info = $infoReader->getInfo('/path/video.mp4');
} catch (InfoReaderExceptionInterface $e) {
    // Possibly wrong media, see below for exceptions
    // details
}

$audioStreams = $info->getAudioStreams();

// Option 1: The iterable way

foreach($audioStreams as $aStream) {
    // ...
}

// Option 2: take the first one

try {
    $audio = $audioStreams->getFirst();
} catch (NoStreamException $e) {
    // Nothing marked as audio
}

$audio->getCodecName(); // aac
$audio->getCodecTagString();
$audio->getDuration();
$audio->getDurationTs();

$audio->getTimeBase();
$audio->getBitRate();
$audio->getTags();

Get subtitle info

<?php

use Soluble\MediaTools\Video\Config\FFProbeConfig;
use Soluble\MediaTools\Video\VideoInfoReader;
use Soluble\MediaTools\Video\Exception\InfoReaderExceptionInterface;
use Soluble\MediaTools\Video\Exception\NoStreamException;

$infoReader = new VideoInfoReader(new FFProbeConfig());

try {
    $info = $infoReader->getInfo('/path/video.mp4');
} catch (InfoReaderExceptionInterface $e) {
    // Possibly wrong media, see below for exceptions
    // details
}


// For subtitle streams

$subtitleStreams = $info->getSubtitleStreams();

// Option 1: The iterable way

foreach($subtitleStreams as $sStream) {
    // ...
}


// Option 2: taking the first one

try {
    $subtitle = $subtitleStreams->getFirst();
} catch (NoStreamException $e) {
    // No subtitle streams
}

$subtitle->getCodecName(); // webvtt

Exceptions

All info exceptions implements InfoReaderExceptionInterface interface.

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

/** @var VideoInfoReader $vis */
try {

    $info = $vis->getInfo('/path/video.mov');


// All exception below implements VE\InfoReaderExceptionInterface

} catch(VE\MissingInputFileException $e) {

    // 'video.mov does not exists

    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)
    //
    // you can catch all them at once or separately:

      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)
}

Metadata

The VideoInfo::getMetadata() returns the ffprobe result, if you're wondering what it is, have a look to an example with ffprobe 4.0.

Warning, direct use of ffprobe metadata if not ensured by semver, bc break can potentially happen.

Metadata retrieval

<?php

use Soluble\MediaTools\Video\Config\FFProbeConfig;
use Soluble\MediaTools\Video\Exception\InfoReaderExceptionInterface;
use Soluble\MediaTools\Video\VideoInfoReader;
use Soluble\MediaTools\Video\Info\StreamTypeInterface;

$infoReader = new VideoInfoReader(new FFProbeConfig());

try {
    $info = $infoReader->getInfo('/path/video.mp4');
} catch (InfoReaderExceptionInterface $e) {
    // Possibly wrong media, see below for exceptions
    // details
}


// Metadata as returned by ffprobe

$info->getMetadata();

// By stream

$info->getStreamsMetadataByType(StreamTypeInterface::VIDEO);
$info->getStreamsMetadataByType(StreamTypeInterface::AUDIO);
$info->getStreamsMetadataByType(StreamTypeInterface::SUBTITLE);
$info->getStreamsMetadataByType(StreamTypeInterface::DATA);

$nbStreams      = $info->countStreams();

$nbVideoStreams = $info->countStreams(StreamTypeInterface::VIDEO);
$nbAudioStreams = $info->countStreams(StreamTypeInterface::AUDIO);
$nbSubStreams   = $info->countStreams(StreamTypeInterface::SUBTITLE);

Metadata example

As returned by ffprobe

<?php

return [
    'streams' => [
        0 => [
            'index' => 0,
            'codec_name' => 'h264',
            'codec_long_name' => 'H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10',
            'profile' => 'Main',
            'codec_type' => 'video',
            'codec_time_base' => '81/2968',
            'codec_tag_string' => 'avc1',
            'codec_tag' => '0x31637661',
            'width' => 320,
            'height' => 180,
            'coded_width' => 320,
            'coded_height' => 180,
            'has_b_frames' => 2,
            'sample_aspect_ratio' => '1:1',
            'display_aspect_ratio' => '16:9',
            'pix_fmt' => 'yuv420p',
            'level' => 40,
            'color_range' => 'tv',
            'color_space' => 'smpte170m',
            'color_transfer' => 'bt709',
            'color_primaries' => 'smpte170m',
            'chroma_location' => 'left',
            'refs' => 1,
            'is_avc' => 'true',
            'nal_length_size' => '4',
            'r_frame_rate' => '120/1',
            'avg_frame_rate' => '1484/81',
            'time_base' => '1/90000',
            'start_pts' => 0,
            'start_time' => '0.000000',
            'duration_ts' => 5467500,
            'duration' => '60.750000',
            'bit_rate' => '39933',
            'bits_per_raw_sample' => '8',
            'nb_frames' => '1113',
            'disposition' => [
                'default' => 1,
                'dub' => 0,
                'original' => 0,
                'comment' => 0,
                'lyrics' => 0,
                'karaoke' => 0,
                'forced' => 0,
                'hearing_impaired' => 0,
                'visual_impaired' => 0,
                'clean_effects' => 0,
                'attached_pic' => 0,
                'timed_thumbnails' => 0,
            ],
            'tags' => [
                'creation_time' => '2018-07-04T14:51:24.000000Z',
                'language' => 'und',
                'handler_name' => 'VideoHandler',
            ],
        ],
        1 => [
            'index' => 1,
            'codec_name' => 'aac',
            'codec_long_name' => 'AAC (Advanced Audio Coding)',
            'profile' => 'LC',
            'codec_type' => 'audio',
            'codec_time_base' => '1/22050',
            'codec_tag_string' => 'mp4a',
            'codec_tag' => '0x6134706d',
            'sample_fmt' => 'fltp',
            'sample_rate' => '22050',
            'channels' => 1,
            'channel_layout' => 'mono',
            'bits_per_sample' => 0,
            'r_frame_rate' => '0/0',
            'avg_frame_rate' => '0/0',
            'time_base' => '1/22050',
            'start_pts' => 0,
            'start_time' => '0.000000',
            'duration_ts' => 1355766,
            'duration' => '61.485986',
            'bit_rate' => '84255',
            'max_bit_rate' => '84255',
            'nb_frames' => '1325',
            'disposition' => [
                'default' => 1,
                'dub' => 0,
                'original' => 0,
                'comment' => 0,
                'lyrics' => 0,
                'karaoke' => 0,
                'forced' => 0,
                'hearing_impaired' => 0,
                'visual_impaired' => 0,
                'clean_effects' => 0,
                'attached_pic' => 0,
                'timed_thumbnails' => 0,
            ],
            'tags' => [
                'creation_time' => '2018-07-04T14:51:24.000000Z',
                'language' => 'eng',
                'handler_name' => 'Mono',
            ],
        ],
    ],
    'format' => [
        'filename' => '/tmp/big_buck_bunny_low.m4v',
        'nb_streams' => 2,
        'nb_programs' => 0,
        'format_name' => 'mov,mp4,m4a,3gp,3g2,mj2',
        'format_long_name' => 'QuickTime / MOV',
        'start_time' => '0.000000',
        'duration' => '61.533000',
        'size' => '983115',
        'bit_rate' => '127816',
        'probe_score' => 100,
        'tags' => [
            'major_brand' => 'mp42',
            'minor_version' => '512',
            'compatible_brands' => 'isomiso2avc1mp41',
            'creation_time' => '2018-07-04T14:51:24.000000Z',
            'title' => 'big_buck_bunny',
            'encoder' => 'HandBrake 1.1.0 2018042400',
        ],
    ]
];