scratch

Subversion Repositories:
Compare Path: Rev
With Path: Rev
?path1? @ 114  →  ?path2? @ 115
/vendor/php-ffmpeg/php-ffmpeg/src/FFMpeg/Coordinate/AspectRatio.php
@@ -0,0 +1,248 @@
<?php
 
/*
* This file is part of PHP-FFmpeg.
*
* (c) Alchemy <dev.team@alchemy.fr>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
 
namespace FFMpeg\Coordinate;
 
use FFMpeg\Exception\InvalidArgumentException;
 
// see http://en.wikipedia.org/wiki/List_of_common_resolutions
class AspectRatio
{
// named 4:3 or 1.33:1 Traditional TV
const AR_4_3 = '4/3';
// named 16:9 or 1.77:1 HD video standard
const AR_16_9 = '16/9';
 
// named 3:2 or 1.5:1 see http://en.wikipedia.org/wiki/135_film
const AR_3_2 = '3/2';
// named 5:3 or 1.66:1 see http://en.wikipedia.org/wiki/Super_16_mm
const AR_5_3 = '5/3';
 
// mostly used in Photography
const AR_5_4 = '5/4';
const AR_1_1 = '1/1';
 
// 1.85:1 US widescreen cinema standard see http://en.wikipedia.org/wiki/Widescreen#Film
const AR_1_DOT_85_1 = '1.85:1';
// 2.39:1 or 2.40:1 Current widescreen cinema standard see http://en.wikipedia.org/wiki/Anamorphic_format
const AR_2_DOT_39_1 = '2.39:1';
 
// Rotated constants
 
// Rotated 4:3
const AR_ROTATED_3_4 = '3/4';
// Rotated 16:9
const AR_ROTATED_9_16 = '9/16';
 
// Rotated 3:2
const AR_ROTATED_2_3 = '2/3';
// Rotated 5:3
const AR_ROTATED_3_5 = '3/5';
 
// Rotated 5:4
const AR_ROTATED_4_5 = '4/5';
 
// Rotated 1.85
const AR_ROTATED_1_DOT_85 = '1/1.85';
// Rotated 2.39
const AR_ROTATED_2_DOT_39 = '1/2.39';
 
/** @var float */
private $ratio;
 
public function __construct($ratio)
{
$this->ratio = $ratio;
}
 
/**
* Returns the value of the ratio.
*
* @return float
*/
public function getValue()
{
return $this->ratio;
}
 
/**
* Computes the best width for given height and modulus.
*
* @param Integer $height
* @param Integer $modulus
*
* @return Integer
*/
public function calculateWidth($height, $modulus = 1)
{
$maxPossibleWidth = $this->getMultipleUp(ceil($this->ratio * $height), $modulus);
$minPossibleWidth = $this->getMultipleDown(floor($this->ratio * $height), $modulus);
 
$maxRatioDiff = abs($this->ratio - ($maxPossibleWidth / $height));
$minRatioDiff = abs($this->ratio - ($minPossibleWidth / $height));
 
return $maxRatioDiff < $minRatioDiff ? $maxPossibleWidth : $minPossibleWidth;
}
 
/**
* Computes the best height for given width and modulus.
*
* @param Integer $width
* @param Integer $modulus
*
* @return Integer
*/
public function calculateHeight($width, $modulus = 1)
{
$maxPossibleHeight = $this->getMultipleUp(ceil($width / $this->ratio), $modulus);
$minPossibleHeight = $this->getMultipleDown(floor($width / $this->ratio), $modulus);
 
$maxRatioDiff = abs($this->ratio - ($width / $maxPossibleHeight));
$minRatioDiff = abs($this->ratio - ($width / $minPossibleHeight));
 
return $maxRatioDiff < $minRatioDiff ? $maxPossibleHeight : $minPossibleHeight;
}
 
private function getMultipleUp($value, $multiple)
{
while (0 !== $value % $multiple) {
$value++;
}
 
return $value;
}
 
private function getMultipleDown($value, $multiple)
{
while (0 !== $value % $multiple) {
$value--;
}
 
return $value;
}
 
/**
* Creates a ratio based on Dimension.
*
* The strategy parameter forces by default to use standardized ratios. If
* custom ratio need to be used, disable it.
*
* @param Dimension $dimension
* @param Boolean $forceStandards Whether to force or not standard ratios
*
* @return AspectRatio
*
* @throws InvalidArgumentException
*/
public static function create(Dimension $dimension, $forceStandards = true)
{
$incoming = $dimension->getWidth() / $dimension->getHeight();
 
if ($forceStandards) {
return new static(static::nearestStrategy($incoming));
} else {
return new static(static::customStrategy($incoming));
}
}
 
private static function valueFromName($name)
{
switch ($name) {
case static::AR_4_3:
return 4 / 3;
case static::AR_16_9:
return 16 / 9;
case static::AR_1_1:
return 1 / 1;
case static::AR_1_DOT_85_1:
return 1.85;
case static::AR_2_DOT_39_1:
return 2.39;
case static::AR_3_2:
return 3 / 2;
case static::AR_5_3:
return 5 / 3;
case static::AR_5_4:
return 5 / 4;
case static::AR_ROTATED_3_4:
return 3 / 4;
case static::AR_ROTATED_9_16:
return 9 / 16;
case static::AR_ROTATED_2_3:
return 2 / 3;
case static::AR_ROTATED_3_5:
return 3 / 5;
case static::AR_ROTATED_4_5:
return 4 / 5;
case static::AR_ROTATED_1_DOT_85:
return 1 / 1.85;
case static::AR_ROTATED_2_DOT_39:
return 1 / 2.39;
default:
throw new InvalidArgumentException(sprintf('Unable to find value for %s', $name));
}
}
 
private static function customStrategy($incoming)
{
$try = static::nearestStrategy($incoming);
 
if (abs($try - $incoming) < $try * 0.05) {
return $try;
}
 
return $incoming;
}
 
private static function nearestStrategy($incoming)
{
$availables = array(
static::AR_4_3 => static::valueFromName(static::AR_4_3),
static::AR_16_9 => static::valueFromName(static::AR_16_9),
static::AR_1_1 => static::valueFromName(static::AR_1_1),
static::AR_1_DOT_85_1 => static::valueFromName(static::AR_1_DOT_85_1),
static::AR_2_DOT_39_1 => static::valueFromName(static::AR_2_DOT_39_1),
static::AR_3_2 => static::valueFromName(static::AR_3_2),
static::AR_5_3 => static::valueFromName(static::AR_5_3),
static::AR_5_4 => static::valueFromName(static::AR_5_4),
 
// Rotated
static::AR_ROTATED_4_5 => static::valueFromName(static::AR_ROTATED_4_5),
static::AR_ROTATED_9_16 => static::valueFromName(static::AR_ROTATED_9_16),
static::AR_ROTATED_2_3 => static::valueFromName(static::AR_ROTATED_2_3),
static::AR_ROTATED_3_5 => static::valueFromName(static::AR_ROTATED_3_5),
static::AR_ROTATED_3_4 => static::valueFromName(static::AR_ROTATED_3_4),
static::AR_ROTATED_1_DOT_85 => static::valueFromName(static::AR_ROTATED_1_DOT_85),
static::AR_ROTATED_2_DOT_39 => static::valueFromName(static::AR_ROTATED_2_DOT_39),
);
asort($availables);
 
$previous = $current = null;
 
foreach ($availables as $name => $value) {
$current = $value;
if ($incoming <= $value) {
break;
}
$previous = $value;
}
 
if (null === $previous) {
return $current;
}
 
if (($current - $incoming) < ($incoming - $previous)) {
return $current;
}
 
return $previous;
}
}
/vendor/php-ffmpeg/php-ffmpeg/src/FFMpeg/Coordinate/Dimension.php
@@ -0,0 +1,71 @@
<?php
 
/*
* This file is part of PHP-FFmpeg.
*
* (c) Alchemy <info@alchemy.fr>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
 
namespace FFMpeg\Coordinate;
 
use FFMpeg\Exception\InvalidArgumentException;
 
/**
* Dimension object, used for manipulating width and height couples
*/
class Dimension
{
private $width;
private $height;
 
/**
* @param integer $width
* @param integer $height
*
* @throws InvalidArgumentException when one of the parameteres is invalid
*/
public function __construct($width, $height)
{
if ($width <= 0 || $height <= 0) {
throw new InvalidArgumentException('Width and height should be positive integer');
}
 
$this->width = (int) $width;
$this->height = (int) $height;
}
 
/**
* Returns width.
*
* @return integer
*/
public function getWidth()
{
return $this->width;
}
 
/**
* Returns height.
*
* @return integer
*/
public function getHeight()
{
return $this->height;
}
 
/**
* Returns the ratio.
*
* @param type $forceStandards Whether or not force the use of standards ratios;
*
* @return AspectRatio
*/
public function getRatio($forceStandards = true)
{
return AspectRatio::create($this, $forceStandards);
}
}
/vendor/php-ffmpeg/php-ffmpeg/src/FFMpeg/Coordinate/FrameRate.php
@@ -0,0 +1,36 @@
<?php
 
/*
* This file is part of PHP-FFmpeg.
*
* (c) Alchemy <info@alchemy.fr>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
 
namespace FFMpeg\Coordinate;
 
use FFMpeg\Exception\InvalidArgumentException;
 
class FrameRate
{
private $value;
 
public function __construct($value)
{
if ($value <= 0) {
throw new InvalidArgumentException('Invalid frame rate, must be positive value.');
}
 
$this->value = $value;
}
 
/**
* @return float
*/
public function getValue()
{
return $this->value;
}
}
/vendor/php-ffmpeg/php-ffmpeg/src/FFMpeg/Coordinate/Point.php
@@ -0,0 +1,40 @@
<?php
 
/*
* This file is part of PHP-FFmpeg.
*
* (c) Alchemy <info@alchemy.fr>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
 
namespace FFMpeg\Coordinate;
 
class Point
{
private $x;
private $y;
 
public function __construct($x, $y)
{
$this->x = (int) $x;
$this->y = (int) $y;
}
 
/**
* @return integer
*/
public function getX()
{
return $this->x;
}
 
/**
* @return integer
*/
public function getY()
{
return $this->y;
}
}
/vendor/php-ffmpeg/php-ffmpeg/src/FFMpeg/Coordinate/TimeCode.php
@@ -0,0 +1,120 @@
<?php
 
/*
* This file is part of PHP-FFmpeg.
*
* (c) Alchemy <info@alchemy.fr>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
 
namespace FFMpeg\Coordinate;
 
use FFMpeg\Exception\InvalidArgumentException;
 
class TimeCode
{
//see http://www.dropframetimecode.org/
private $hours;
private $minutes;
private $seconds;
private $frames;
 
public function __construct($hours, $minutes, $seconds, $frames)
{
$this->hours = $hours;
$this->minutes = $minutes;
$this->seconds = $seconds;
$this->frames = $frames;
}
 
public function __toString()
{
return sprintf('%02d:%02d:%02d.%02d', $this->hours, $this->minutes, $this->seconds, $this->frames);
}
 
/**
* Creates timecode from string.
*
* @param string $timecode
*
* @return TimeCode
*
* @throws InvalidArgumentException In case an invalid timecode is supplied
*/
public static function fromString($timecode)
{
$days = 0;
 
if (preg_match('/^[0-9]+:[0-9]+:[0-9]+:[0-9]+\.[0-9]+$/', $timecode)) {
list($days, $hours, $minutes, $seconds, $frames) = sscanf($timecode, '%d:%d:%d:%d.%d');
} elseif (preg_match('/^[0-9]+:[0-9]+:[0-9]+:[0-9]+:[0-9]+$/', $timecode)) {
list($days, $hours, $minutes, $seconds, $frames) = sscanf($timecode, '%d:%d:%d:%d:%d');
} elseif (preg_match('/^[0-9]+:[0-9]+:[0-9]+\.[0-9]+$/', $timecode)) {
list($hours, $minutes, $seconds, $frames) = sscanf($timecode, '%d:%d:%d.%s');
} elseif (preg_match('/^[0-9]+:[0-9]+:[0-9]+:[0-9]+$/', $timecode)) {
list($hours, $minutes, $seconds, $frames) = sscanf($timecode, '%d:%d:%d:%s');
} else {
throw new InvalidArgumentException(sprintf('Unable to parse timecode %s', $timecode));
}
 
$hours += $days * 24;
 
return new static($hours, $minutes, $seconds, $frames);
}
 
/**
* Creates timecode from number of seconds.
*
* @param float $quantity
*
* @return TimeCode
*/
public static function fromSeconds($quantity)
{
$minutes = $hours = $frames = 0;
 
$frames = round(100 * ($quantity - floor($quantity)));
$seconds = floor($quantity);
 
if ($seconds > 59) {
$minutes = floor($seconds / 60);
$seconds = $seconds % 60;
}
if ($minutes > 59) {
$hours = floor($minutes / 60);
$minutes = $minutes % 60;
}
 
return new static($hours, $minutes, $seconds, $frames);
}
 
/**
* Returns this timecode in seconds
* @return int
*/
public function toSeconds() {
$seconds = 0;
 
$seconds += $this->hours * 60 * 60;
$seconds += $this->minutes * 60;
$seconds += $this->seconds;
 
// TODO: Handle frames?
 
return (int) $seconds;
}
 
/**
* Helper function wether `$timecode` is after this one
*
* @param TimeCode $timecode The Timecode to compare
* @return bool
*/
public function isAfter(TimeCode $timecode) {
// convert everything to seconds and compare
return ($this->toSeconds() > $timecode->toSeconds());
}
 
}
/vendor/php-ffmpeg/php-ffmpeg/src/FFMpeg/Driver/FFMpegDriver.php
@@ -0,0 +1,57 @@
<?php
 
/*
* This file is part of PHP-FFmpeg.
*
* (c) Alchemy <info@alchemy.fr>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
 
namespace FFMpeg\Driver;
 
use Alchemy\BinaryDriver\AbstractBinary;
use Alchemy\BinaryDriver\Configuration;
use Alchemy\BinaryDriver\ConfigurationInterface;
use Alchemy\BinaryDriver\Exception\ExecutableNotFoundException as BinaryDriverExecutableNotFound;
use FFMpeg\Exception\ExecutableNotFoundException;
use Psr\Log\LoggerInterface;
 
class FFMpegDriver extends AbstractBinary
{
/**
* {@inheritdoc}
*/
public function getName()
{
return 'ffmpeg';
}
 
/**
* Creates an FFMpegDriver.
*
* @param LoggerInterface $logger
* @param array|Configuration $configuration
*
* @return FFMpegDriver
*/
public static function create(LoggerInterface $logger = null, $configuration = array())
{
if (!$configuration instanceof ConfigurationInterface) {
$configuration = new Configuration($configuration);
}
 
$binaries = $configuration->get('ffmpeg.binaries', array('avconv', 'ffmpeg'));
 
if (!$configuration->has('timeout')) {
$configuration->set('timeout', 300);
}
 
try {
return static::load($binaries, $logger, $configuration);
} catch (BinaryDriverExecutableNotFound $e) {
throw new ExecutableNotFoundException('Unable to load FFMpeg', $e->getCode(), $e);
}
}
}
/vendor/php-ffmpeg/php-ffmpeg/src/FFMpeg/Driver/FFProbeDriver.php
@@ -0,0 +1,53 @@
<?php
 
/*
* This file is part of PHP-FFmpeg.
*
* (c) Alchemy <info@alchemy.fr>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
 
namespace FFMpeg\Driver;
 
use Alchemy\BinaryDriver\AbstractBinary;
use Alchemy\BinaryDriver\Configuration;
use Alchemy\BinaryDriver\ConfigurationInterface;
use Alchemy\BinaryDriver\Exception\ExecutableNotFoundException as BinaryDriverExecutableNotFound;
use FFMpeg\Exception\ExecutableNotFoundException;
use Psr\Log\LoggerInterface;
 
class FFProbeDriver extends AbstractBinary
{
/**
* {@inheritdoc}
*/
public function getName()
{
return 'ffprobe';
}
 
/**
* Creates an FFProbeDriver.
*
* @param array|ConfigurationInterface $configuration
* @param LoggerInterface $logger
*
* @return FFProbeDriver
*/
public static function create($configuration, LoggerInterface $logger = null)
{
if (!$configuration instanceof ConfigurationInterface) {
$configuration = new Configuration($configuration);
}
 
$binaries = $configuration->get('ffprobe.binaries', array('avprobe', 'ffprobe'));
 
try {
return static::load($binaries, $logger, $configuration);
} catch (BinaryDriverExecutableNotFound $e) {
throw new ExecutableNotFoundException('Unable to load FFProbe', $e->getCode(), $e);
}
}
}
/vendor/php-ffmpeg/php-ffmpeg/src/FFMpeg/Exception/ExceptionInterface.php
@@ -0,0 +1,16 @@
<?php
 
/*
* This file is part of PHP-FFmpeg.
*
* (c) Alchemy <info@alchemy.fr>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
 
namespace FFMpeg\Exception;
 
interface ExceptionInterface
{
}
/vendor/php-ffmpeg/php-ffmpeg/src/FFMpeg/Exception/ExecutableNotFoundException.php
@@ -0,0 +1,16 @@
<?php
 
/*
* This file is part of PHP-FFmpeg.
*
* (c) Alchemy <info@alchemy.fr>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
 
namespace FFMpeg\Exception;
 
class ExecutableNotFoundException extends RuntimeException
{
}
/vendor/php-ffmpeg/php-ffmpeg/src/FFMpeg/Exception/InvalidArgumentException.php
@@ -0,0 +1,16 @@
<?php
 
/*
* This file is part of PHP-FFmpeg.
*
* (c) Alchemy <info@alchemy.fr>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
 
namespace FFMpeg\Exception;
 
class InvalidArgumentException extends \InvalidArgumentException implements ExceptionInterface
{
}
/vendor/php-ffmpeg/php-ffmpeg/src/FFMpeg/Exception/LogicException.php
@@ -0,0 +1,16 @@
<?php
 
/*
* This file is part of PHP-FFmpeg.
*
* (c) Alchemy <info@alchemy.fr>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
 
namespace FFMpeg\Exception;
 
class LogicException extends \LogicException implements ExceptionInterface
{
}
/vendor/php-ffmpeg/php-ffmpeg/src/FFMpeg/Exception/RuntimeException.php
@@ -0,0 +1,16 @@
<?php
 
/*
* This file is part of PHP-FFmpeg.
*
* (c) Alchemy <info@alchemy.fr>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
 
namespace FFMpeg\Exception;
 
class RuntimeException extends \RuntimeException implements ExceptionInterface
{
}
/vendor/php-ffmpeg/php-ffmpeg/src/FFMpeg/FFMpeg.php
@@ -0,0 +1,122 @@
<?php
 
/*
* This file is part of PHP-FFmpeg.
*
* (c) Alchemy <info@alchemy.fr>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
 
namespace FFMpeg;
 
use Alchemy\BinaryDriver\ConfigurationInterface;
use FFMpeg\Driver\FFMpegDriver;
use FFMpeg\Exception\InvalidArgumentException;
use FFMpeg\Exception\RuntimeException;
use FFMpeg\Media\Audio;
use FFMpeg\Media\Video;
use Psr\Log\LoggerInterface;
 
class FFMpeg
{
/** @var FFMpegDriver */
private $driver;
/** @var FFProbe */
private $ffprobe;
 
public function __construct(FFMpegDriver $ffmpeg, FFProbe $ffprobe)
{
$this->driver = $ffmpeg;
$this->ffprobe = $ffprobe;
}
 
/**
* Sets FFProbe.
*
* @param FFProbe
*
* @return FFMpeg
*/
public function setFFProbe(FFProbe $ffprobe)
{
$this->ffprobe = $ffprobe;
 
return $this;
}
 
/**
* Gets FFProbe.
*
* @return FFProbe
*/
public function getFFProbe()
{
return $this->ffprobe;
}
 
/**
* Sets the ffmpeg driver.
*
* @return FFMpeg
*/
public function setFFMpegDriver(FFMpegDriver $ffmpeg)
{
$this->driver = $ffmpeg;
 
return $this;
}
 
/**
* Gets the ffmpeg driver.
*
* @return FFMpegDriver
*/
public function getFFMpegDriver()
{
return $this->driver;
}
 
/**
* Opens a file in order to be processed.
*
* @param string $pathfile A pathfile
*
* @return Audio|Video
*
* @throws InvalidArgumentException
*/
public function open($pathfile)
{
if (null === $streams = $this->ffprobe->streams($pathfile)) {
throw new RuntimeException(sprintf('Unable to probe "%s".', $pathfile));
}
 
if (0 < count($streams->videos())) {
return new Video($pathfile, $this->driver, $this->ffprobe);
} elseif (0 < count($streams->audios())) {
return new Audio($pathfile, $this->driver, $this->ffprobe);
}
 
throw new InvalidArgumentException('Unable to detect file format, only audio and video supported');
}
 
/**
* Creates a new FFMpeg instance.
*
* @param array|ConfigurationInterface $configuration
* @param LoggerInterface $logger
* @param FFProbe $probe
*
* @return FFMpeg
*/
public static function create($configuration = array(), LoggerInterface $logger = null, FFProbe $probe = null)
{
if (null === $probe) {
$probe = FFProbe::create($configuration, $logger, null);
}
 
return new static(FFMpegDriver::create($logger, $configuration), $probe);
}
}
/vendor/php-ffmpeg/php-ffmpeg/src/FFMpeg/FFMpegServiceProvider.php
@@ -0,0 +1,64 @@
<?php
 
/*
* This file is part of PHP-FFmpeg.
*
* (c) Alchemy <info@alchemy.fr>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
 
namespace FFMpeg;
 
use Doctrine\Common\Cache\ArrayCache;
use Silex\Application;
use Silex\ServiceProviderInterface;
 
class FFMpegServiceProvider implements ServiceProviderInterface
{
public function register(Application $app)
{
$app['ffmpeg.configuration'] = array();
$app['ffmpeg.default.configuration'] = array(
'ffmpeg.threads' => 4,
'ffmpeg.timeout' => 300,
'ffmpeg.binaries' => array('avconv', 'ffmpeg'),
'ffprobe.timeout' => 30,
'ffprobe.binaries' => array('avprobe', 'ffprobe'),
);
$app['ffmpeg.logger'] = null;
 
$app['ffmpeg.configuration.build'] = $app->share(function (Application $app) {
return array_replace($app['ffmpeg.default.configuration'], $app['ffmpeg.configuration']);
});
 
$app['ffmpeg'] = $app['ffmpeg.ffmpeg'] = $app->share(function (Application $app) {
$configuration = $app['ffmpeg.configuration.build'];
 
if (isset($configuration['ffmpeg.timeout'])) {
$configuration['timeout'] = $configuration['ffmpeg.timeout'];
}
 
return FFMpeg::create($configuration, $app['ffmpeg.logger'], $app['ffmpeg.ffprobe']);
});
 
$app['ffprobe.cache'] = $app->share(function () {
return new ArrayCache();
});
 
$app['ffmpeg.ffprobe'] = $app->share(function (Application $app) {
$configuration = $app['ffmpeg.configuration.build'];
 
if (isset($configuration['ffmpeg.timeout'])) {
$configuration['timeout'] = $configuration['ffprobe.timeout'];
}
 
return FFProbe::create($configuration, $app['ffmpeg.logger'], $app['ffprobe.cache']);
});
}
 
public function boot(Application $app)
{
}
}
/vendor/php-ffmpeg/php-ffmpeg/src/FFMpeg/FFProbe/DataMapping/AbstractData.php
@@ -0,0 +1,93 @@
<?php
 
/*
* This file is part of PHP-FFmpeg.
*
* (c) Alchemy <info@alchemy.fr>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
 
namespace FFMpeg\FFProbe\DataMapping;
 
abstract class AbstractData implements \Countable
{
private $properties;
 
public function __construct(array $properties)
{
$this->properties = $properties;
}
 
/**
* Returns true if data has property.
*
* @param string $property
* @return Boolean
*/
public function has($property)
{
return isset($this->properties[$property]);
}
 
/**
* Returns the property value given its name.
*
* @param string $property
* @param mixed $default
*
* @return mixed
*/
public function get($property, $default = null)
{
if (!isset($this->properties[$property])) {
return $default;
}
 
return $this->properties[$property];
}
 
/**
* Sets the property value given its name.
*
* @param string $property
* @param mixed $value
*
* @return AbstractData
*/
public function set($property, $value)
{
$this->properties[$property] = $value;
 
return $this;
}
 
/**
* Returns all property names.
*
* @return array
*/
public function keys()
{
return array_keys($this->properties);
}
 
/**
* Returns all properties and their values.
*
* @return array
*/
public function all()
{
return $this->properties;
}
 
/**
* {@inheritdoc}
*/
public function count()
{
return count($this->properties);
}
}
/vendor/php-ffmpeg/php-ffmpeg/src/FFMpeg/FFProbe/DataMapping/Format.php
@@ -0,0 +1,16 @@
<?php
 
/*
* This file is part of PHP-FFmpeg.
*
* (c) Alchemy <info@alchemy.fr>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
 
namespace FFMpeg\FFProbe\DataMapping;
 
class Format extends AbstractData
{
}
/vendor/php-ffmpeg/php-ffmpeg/src/FFMpeg/FFProbe/DataMapping/Stream.php
@@ -0,0 +1,107 @@
<?php
 
/*
* This file is part of PHP-FFmpeg.
*
* (c) Alchemy <info@alchemy.fr>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
 
namespace FFMpeg\FFProbe\DataMapping;
 
use FFMpeg\Exception\LogicException;
use FFMpeg\Exception\RuntimeException;
use FFMpeg\Coordinate\Dimension;
 
class Stream extends AbstractData
{
/**
* Returns true if the stream is an audio stream.
*
* @return Boolean
*/
public function isAudio()
{
return $this->get('codec_type') === 'audio';
}
 
/**
* Returns true if the stream is a video stream.
*
* @return Boolean
*/
public function isVideo()
{
return $this->get('codec_type') === 'video';
}
 
/**
* Returns the dimension of the video stream.
*
* @return Dimension
*
* @throws LogicException In case the stream is not a video stream.
* @throws RuntimeException In case the dimensions can not be extracted.
*/
public function getDimensions()
{
if (!$this->isVideo()) {
throw new LogicException('Dimensions can only be retrieved from video streams.');
}
 
$sampleRatio = $displayRatio = null;
 
$width = $this->get('width');
$height = $this->get('height');
 
if (null !== $ratio = $this->extractRatio($this, 'sample_aspect_ratio')) {
$sampleRatio = $ratio;
}
if (null !== $ratio = $this->extractRatio($this, 'display_aspect_ratio')) {
$displayRatio = $ratio;
}
 
if (null === $height || null === $width) {
throw new RuntimeException('Unable to extract dimensions.');
}
 
if (null !== $displayRatio && null !== $sampleRatio) {
if ($sampleRatio[0] !== 1 && $sampleRatio[1] !== 1) {
if (null !== $width && null !== $height) {
// stretch video according to pixel sample aspect ratio
$width = round($width * ($sampleRatio[0] / $sampleRatio[1]));
// set height according to display aspect ratio
$height = round($width * ($displayRatio[1] / $displayRatio[0]));
}
}
}
 
return new Dimension($width, $height);
}
 
/**
* Extracts a ratio from a string in a \d+:\d+ format given a key name.
*
* @param Stream $stream The stream where to look for the ratio.
* @param string $name the name of the key.
* @return null|array An array containing the width and the height, null if not found.
*/
private function extractRatio(Stream $stream, $name)
{
if (!$stream->has($name)) {
return;
}
 
$ratio = $stream->get($name);
if (preg_match('/\d+:\d+/', $ratio)) {
$data = array_filter(explode(':', $ratio), function ($int) {
return $int > 0;
});
if (2 === count($data)) {
return array_map(function ($int) { return (int) $int; }, $data);
}
}
}
}
/vendor/php-ffmpeg/php-ffmpeg/src/FFMpeg/FFProbe/DataMapping/StreamCollection.php
@@ -0,0 +1,99 @@
<?php
 
/*
* This file is part of PHP-FFmpeg.
*
* (c) Alchemy <info@alchemy.fr>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
 
namespace FFMpeg\FFProbe\DataMapping;
 
class StreamCollection implements \Countable, \IteratorAggregate
{
private $streams;
 
public function __construct(array $streams = array())
{
$this->streams = array_values($streams);
}
 
/**
* Returns the first stream of the collection, null if the collection is
* empty.
*
* @return null|Stream
*/
public function first()
{
$stream = reset($this->streams);
 
return $stream ?: null;
}
 
/**
* Adds a stream to the collection.
*
* @param Stream $stream
*
* @return StreamCollection
*/
public function add(Stream $stream)
{
$this->streams[] = $stream;
 
return $this;
}
 
/**
* Returns a new StreamCollection with only video streams.
*
* @return StreamCollection
*/
public function videos()
{
return new static(array_filter($this->streams, function (Stream $stream) {
return $stream->isVideo();
}));
}
 
/**
* Returns a new StreamCollection with only audio streams.
*
* @return StreamCollection
*/
public function audios()
{
return new static(array_filter($this->streams, function (Stream $stream) {
return $stream->isAudio();
}));
}
 
/**
* {@inheritdoc}
*/
public function count()
{
return count($this->streams);
}
 
/**
* Returns the array of contained streams.
*
* @return array
*/
public function all()
{
return $this->streams;
}
 
/**
* {@inheritdoc}
*/
public function getIterator()
{
return new \ArrayIterator($this->streams);
}
}
/vendor/php-ffmpeg/php-ffmpeg/src/FFMpeg/FFProbe/Mapper.php
@@ -0,0 +1,54 @@
<?php
 
/*
* This file is part of PHP-FFmpeg.
*
* (c) Alchemy <info@alchemy.fr>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
 
namespace FFMpeg\FFProbe;
 
use FFMpeg\FFProbe;
use FFMpeg\FFProbe\DataMapping\Format;
use FFMpeg\FFProbe\DataMapping\StreamCollection;
use FFMpeg\FFProbe\DataMapping\Stream;
use FFMpeg\Exception\InvalidArgumentException;
 
class Mapper implements MapperInterface
{
/**
* {@inheritdoc}
*/
public function map($type, $data)
{
switch ($type) {
case FFProbe::TYPE_FORMAT:
return $this->mapFormat($data);
case FFProbe::TYPE_STREAMS:
return $this->mapStreams($data);
default:
throw new InvalidArgumentException(sprintf(
'Invalid type `%s`.', $type
));
}
}
 
private function mapFormat($data)
{
return new Format($data['format']);
}
 
private function mapStreams($data)
{
$streams = new StreamCollection();
 
foreach ($data['streams'] as $properties) {
$streams->add(new Stream($properties));
}
 
return $streams;
}
}
/vendor/php-ffmpeg/php-ffmpeg/src/FFMpeg/FFProbe/MapperInterface.php
@@ -0,0 +1,27 @@
<?php
 
/*
* This file is part of PHP-FFmpeg.
*
* (c) Alchemy <info@alchemy.fr>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
 
namespace FFMpeg\FFProbe;
 
interface MapperInterface
{
/**
* Maps data given its type.
*
* @param string $type One of FFProbe::TYPE_* constant
* @param string $data The data
*
* @return Format|Stream
*
* @throws InvalidArgumentException In case the type is not supported
*/
public function map($type, $data);
}
/vendor/php-ffmpeg/php-ffmpeg/src/FFMpeg/FFProbe/OptionsTester.php
@@ -0,0 +1,70 @@
<?php
 
/*
* This file is part of PHP-FFmpeg.
*
* (c) Alchemy <info@alchemy.fr>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
 
namespace FFMpeg\FFProbe;
 
use Alchemy\BinaryDriver\Exception\ExecutionFailureException;
use Doctrine\Common\Cache\Cache;
use FFMpeg\Driver\FFProbeDriver;
use FFMpeg\Exception\RuntimeException;
 
class OptionsTester implements OptionsTesterInterface
{
/** @var FFProbeDriver */
private $ffprobe;
/** @var Cache */
private $cache;
 
public function __construct(FFProbeDriver $ffprobe, Cache $cache)
{
$this->ffprobe = $ffprobe;
$this->cache = $cache;
}
 
/**
* {@inheritdoc}
*/
public function has($name)
{
$id = sprintf('option-%s', $name);
 
if ($this->cache->contains($id)) {
return $this->cache->fetch($id);
}
 
$output = $this->retrieveHelpOutput();
 
$ret = (Boolean) preg_match('/^'.$name.'/m', $output);
 
$this->cache->save($id, $ret);
 
return $ret;
}
 
private function retrieveHelpOutput()
{
$id = 'help';
 
if ($this->cache->contains($id)) {
return $this->cache->fetch($id);
}
 
try {
$output = $this->ffprobe->command(array('-help', '-loglevel', 'quiet'));
} catch (ExecutionFailureException $e) {
throw new RuntimeException('Your FFProbe version is too old and does not support `-help` option, please upgrade.', $e->getCode(), $e);
}
 
$this->cache->save($id, $output);
 
return $output;
}
}
/vendor/php-ffmpeg/php-ffmpeg/src/FFMpeg/FFProbe/OptionsTesterInterface.php
@@ -0,0 +1,24 @@
<?php
 
/*
* This file is part of PHP-FFmpeg.
*
* (c) Alchemy <info@alchemy.fr>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
 
namespace FFMpeg\FFProbe;
 
interface OptionsTesterInterface
{
/**
* Tells if the given option is supported by ffprobe.
*
* @param string $name
*
* @return Boolean
*/
public function has($name);
}
/vendor/php-ffmpeg/php-ffmpeg/src/FFMpeg/FFProbe/OutputParser.php
@@ -0,0 +1,125 @@
<?php
 
/*
* This file is part of PHP-FFmpeg.
*
* (c) Alchemy <info@alchemy.fr>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
 
namespace FFMpeg\FFProbe;
 
use FFMpeg\FFProbe;
use FFMpeg\Exception\InvalidArgumentException;
 
class OutputParser implements OutputParserInterface
{
/**
* {@inheritdoc}
*/
public function parse($type, $data)
{
switch ($type) {
case FFProbe::TYPE_FORMAT:
return $this->parseFormat($data);
break;
case FFProbe::TYPE_STREAMS:
return $this->parseStreams($data);
break;
default:
throw new InvalidArgumentException(sprintf('Unknown data type %s', $type));
}
}
 
private function parseFormat($data)
{
$ret = array();
 
foreach (explode(PHP_EOL, $data) as $line) {
 
if (in_array($line, array('[FORMAT]', '[/FORMAT]'))) {
continue;
}
 
$chunks = explode('=', $line);
$key = array_shift($chunks);
 
if ('' === trim($key)) {
continue;
}
 
$value = trim(implode('=', $chunks));
 
if ('nb_streams' === $key) {
$value = (int) $value;
}
 
if (0 === strpos($key, 'TAG:')) {
if (!isset($ret['tags'])) {
$ret['tags'] = array();
}
$ret['tags'][substr($key, 4)] = $value;
} else {
$ret[$key] = $value;
}
}
 
return array('format' => $ret);
}
 
private function parseStreams($data)
{
$ret = array();
$n = -1;
 
foreach (explode(PHP_EOL, $data) as $line) {
 
if ($line == '[STREAM]') {
$n ++;
$ret[$n] = array();
continue;
}
if ($line == '[/STREAM]') {
continue;
}
 
$chunks = explode('=', $line);
$key = array_shift($chunks);
 
if ('' === trim($key)) {
continue;
}
 
$value = trim(implode('=', $chunks));
 
if ('N/A' === $value) {
continue;
}
if ('profile' === $key && 'unknown' === $value) {
continue;
}
 
if (in_array($key, array('index', 'width', 'height', 'channels', 'bits_per_sample', 'has_b_frames', 'level', 'start_pts', 'duration_ts'))) {
$value = (int) $value;
}
 
if (0 === strpos($key, 'TAG:')) {
if (!isset($ret[$n]['tags'])) {
$ret[$n]['tags'] = array();
}
$ret[$n]['tags'][substr($key, 4)] = $value;
} elseif (0 === strpos($key, 'DISPOSITION:')) {
if (!isset($ret[$n]['disposition'])) {
$ret[$n]['disposition'] = array();
}
$ret[$n]['disposition'][substr($key, 12)] = $value;
} else {
$ret[$n][$key] = $value;
}
}
 
return array('streams' => $ret);
}
}
/vendor/php-ffmpeg/php-ffmpeg/src/FFMpeg/FFProbe/OutputParserInterface.php
@@ -0,0 +1,27 @@
<?php
 
/*
* This file is part of PHP-FFmpeg.
*
* (c) Alchemy <info@alchemy.fr>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
 
namespace FFMpeg\FFProbe;
 
interface OutputParserInterface
{
/**
* Parses ffprobe raw output.
*
* @param string $type One of FFProbe::TYPE_* constant
* @param string $data The data
*
* @return array
*
* @throws InvalidArgumentException In case the type is not supported
*/
public function parse($type, $data);
}
/vendor/php-ffmpeg/php-ffmpeg/src/FFMpeg/FFProbe.php
@@ -0,0 +1,275 @@
<?php
 
/*
* This file is part of PHP-FFmpeg.
*
* (c) Alchemy <info@alchemy.fr>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
 
namespace FFMpeg;
 
use Alchemy\BinaryDriver\ConfigurationInterface;
use Alchemy\BinaryDriver\Exception\ExecutionFailureException;
use Doctrine\Common\Cache\ArrayCache;
use Doctrine\Common\Cache\Cache;
use FFMpeg\Driver\FFProbeDriver;
use FFMpeg\FFProbe\DataMapping\Format;
use FFMpeg\FFProbe\Mapper;
use FFMpeg\FFProbe\MapperInterface;
use FFMpeg\FFProbe\OptionsTester;
use FFMpeg\FFProbe\OptionsTesterInterface;
use FFMpeg\FFProbe\OutputParser;
use FFMpeg\FFProbe\OutputParserInterface;
use FFMpeg\Exception\InvalidArgumentException;
use FFMpeg\Exception\RuntimeException;
use FFMpeg\FFProbe\DataMapping\StreamCollection;
use Psr\Log\LoggerInterface;
 
class FFProbe
{
const TYPE_STREAMS = 'streams';
const TYPE_FORMAT = 'format';
 
/** @var Cache */
private $cache;
/** @var OptionsTesterInterface */
private $optionsTester;
/** @var OutputParserInterface */
private $parser;
/** @var FFProbeDriver */
private $ffprobe;
/** @var MapperInterface */
private $mapper;
 
public function __construct(FFProbeDriver $ffprobe, Cache $cache)
{
$this->ffprobe = $ffprobe;
$this->optionsTester = new OptionsTester($ffprobe, $cache);
$this->parser = new OutputParser();
$this->mapper = new Mapper();
$this->cache = $cache;
}
 
/**
* @return OutputParserInterface
*/
public function getParser()
{
return $this->parser;
}
 
/**
* @param OutputParserInterface $parser
*
* @return FFProbe
*/
public function setParser(OutputParserInterface $parser)
{
$this->parser = $parser;
 
return $this;
}
 
/**
* @return FFProbeDriver
*/
public function getFFProbeDriver()
{
return $this->ffprobe;
}
 
/**
* @param FFProbeDriver $ffprobe
*
* @return FFProbe
*/
public function setFFProbeDriver(FFProbeDriver $ffprobe)
{
$this->ffprobe = $ffprobe;
 
return $this;
}
 
/**
* @param OptionsTesterInterface $tester
*
* @return FFProbe
*/
public function setOptionsTester(OptionsTesterInterface $tester)
{
$this->optionsTester = $tester;
 
return $this;
}
 
/**
* @return OptionsTesterInterface
*/
public function getOptionsTester()
{
return $this->optionsTester;
}
 
/**
* @param Cache $cache
*
* @return FFProbe
*/
public function setCache(Cache $cache)
{
$this->cache = $cache;
 
return $this;
}
 
/**
* @return Cache
*/
public function getCache()
{
return $this->cache;
}
 
/**
* @return MapperInterface
*/
public function getMapper()
{
return $this->mapper;
}
 
/**
* @param MapperInterface $mapper
*
* @return FFProbe
*/
public function setMapper(MapperInterface $mapper)
{
$this->mapper = $mapper;
 
return $this;
}
 
/**
* @api
*
* Probes the format of a given file.
*
* @param string $pathfile
*
* @return Format A Format object
*
* @throws InvalidArgumentException
* @throws RuntimeException
*/
public function format($pathfile)
{
return $this->probe($pathfile, '-show_format', static::TYPE_FORMAT);
}
 
/**
* @api
*
* Probes the streams contained in a given file.
*
* @param string $pathfile
*
* @return StreamCollection A collection of streams
*
* @throws InvalidArgumentException
* @throws RuntimeException
*/
public function streams($pathfile)
{
return $this->probe($pathfile, '-show_streams', static::TYPE_STREAMS);
}
 
/**
* @api
*
* Creates an FFProbe.
*
* @param array|ConfigurationInterface $configuration
* @param LoggerInterface $logger
* @param Cache $cache
*
* @return FFProbe
*/
public static function create($configuration = array(), LoggerInterface $logger = null, Cache $cache = null)
{
if (null === $cache) {
$cache = new ArrayCache();
}
 
return new static(FFProbeDriver::create($configuration, $logger), $cache);
}
 
private function probe($pathfile, $command, $type, $allowJson = true)
{
$id = sprintf('%s-%s', $command, $pathfile);
 
if ($this->cache->contains($id)) {
return $this->cache->fetch($id);
}
 
if (!$this->optionsTester->has($command)) {
throw new RuntimeException(sprintf(
'This version of ffprobe is too old and '
. 'does not support `%s` option, please upgrade', $command
));
}
 
$commands = array($pathfile, $command);
 
$parseIsToDo = false;
 
if ($allowJson && $this->optionsTester->has('-print_format')) {
// allowed in latest PHP-FFmpeg version
$commands[] = '-print_format';
$commands[] = 'json';
} elseif ($allowJson && $this->optionsTester->has('-of')) {
// option has changed in avconv 9
$commands[] = '-of';
$commands[] = 'json';
} else {
$parseIsToDo = true;
}
 
try {
$output = $this->ffprobe->command($commands);
} catch (ExecutionFailureException $e) {
throw new RuntimeException(sprintf('Unable to probe %s', $pathfile), $e->getCode(), $e);
}
 
if ($parseIsToDo) {
$data = $this->parser->parse($type, $output);
} else {
try {
// Malformed json may be retrieved
$data = $this->parseJson($output);
} catch (RuntimeException $e) {
return $this->probe($pathfile, $command, $type, false);
}
}
 
$ret = $this->mapper->map($type, $data);
 
$this->cache->save($id, $ret);
 
return $ret;
}
 
private function parseJson($data)
{
$ret = @json_decode($data, true);
 
if (JSON_ERROR_NONE !== json_last_error()) {
throw new RuntimeException(sprintf('Unable to parse json %s', $ret));
}
 
return $ret;
}
}
/vendor/php-ffmpeg/php-ffmpeg/src/FFMpeg/Filters/Audio/AddMetadataFilter.php
@@ -0,0 +1,58 @@
<?php
 
/*
* This file is part of PHP-FFmpeg.
*
* (c) Alchemy <info@alchemy.fr>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
 
namespace FFMpeg\Filters\Audio;
 
use FFMpeg\Filters\Audio\AudioFilterInterface;
use FFMpeg\Format\AudioInterface;
use FFMpeg\Media\Audio;
 
class AddMetadataFilter implements AudioFilterInterface
{
/** @var Array */
private $metaArr;
/** @var Integer */
private $priority;
 
function __construct($metaArr = null, $priority = 9)
{
$this->metaArr = $metaArr;
$this->priority = $priority;
}
 
public function getPriority()
{
//must be of high priority in case theres a second input stream (artwork) to register with audio
return $this->priority;
}
 
public function apply(Audio $audio, AudioInterface $format)
{
$meta = $this->metaArr;
 
if (is_null($meta)) {
return ['-map_metadata', '-1', '-vn'];
}
 
$metadata = [];
 
if (array_key_exists("artwork", $meta)) {
array_push($metadata, "-i", $meta['artwork'], "-map", "0", "-map", "1");
unset($meta['artwork']);
}
 
foreach ($meta as $k => $v) {
array_push($metadata, "-metadata", "$k=$v");
}
 
return $metadata;
}
}
/vendor/php-ffmpeg/php-ffmpeg/src/FFMpeg/Filters/Audio/AudioClipFilter.php
@@ -0,0 +1,84 @@
<?php
 
/*
* This file is part of PHP-FFmpeg.
*
* (c) Alchemy <info@alchemy.fr>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
 
namespace FFMpeg\Filters\Audio;
 
use FFMpeg\Coordinate\TimeCode;
use FFMpeg\Format\AudioInterface;
use FFMpeg\Media\Audio;
 
class AudioClipFilter implements AudioFilterInterface {
 
/**
* @var TimeCode
*/
private $start;
 
/**
* @var TimeCode
*/
private $duration;
 
/**
* @var int
*/
private $priority;
 
 
public function __construct(TimeCode $start, TimeCode $duration = null, $priority = 0) {
$this->start = $start;
$this->duration = $duration;
$this->priority = $priority;
}
 
/**
* @inheritDoc
*/
public function getPriority() {
return $this->priority;
}
 
/**
* Returns the start position the audio is being cutted
*
* @return TimeCode
*/
public function getStart() {
return $this->start;
}
 
/**
* Returns how long the audio is being cutted. Returns null when the duration is infinite,
*
* @return TimeCode|null
*/
public function getDuration() {
return $this->duration;
}
 
/**
* @inheritDoc
*/
public function apply(Audio $audio, AudioInterface $format) {
$commands = array('-ss', (string) $this->start);
 
if ($this->duration !== null) {
$commands[] = '-t';
$commands[] = (string) $this->duration;
}
 
$commands[] = '-acodec';
$commands[] = 'copy';
 
return $commands;
}
 
}
/vendor/php-ffmpeg/php-ffmpeg/src/FFMpeg/Filters/Audio/AudioFilterInterface.php
@@ -0,0 +1,29 @@
<?php
 
/*
* This file is part of PHP-FFmpeg.
*
* (c) Alchemy <dev.team@alchemy.fr>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
 
namespace FFMpeg\Filters\Audio;
 
use FFMpeg\Filters\FilterInterface;
use FFMpeg\Format\AudioInterface;
use FFMpeg\Media\Audio;
 
interface AudioFilterInterface extends FilterInterface
{
/**
* Applies the filter on the the Audio media given an format.
*
* @param Audio $audio
* @param AudioInterface $format
*
* @return array An array of arguments
*/
public function apply(Audio $audio, AudioInterface $format);
}
/vendor/php-ffmpeg/php-ffmpeg/src/FFMpeg/Filters/Audio/AudioFilters.php
@@ -0,0 +1,74 @@
<?php
 
/*
* This file is part of PHP-FFmpeg.
*
* (c) Alchemy <info@alchemy.fr>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
 
namespace FFMpeg\Filters\Audio;
 
use FFMpeg\Filters\Audio\AddMetadataFilter;
use FFMpeg\Media\Audio;
use FFMpeg\Coordinate\TimeCode;
 
class AudioFilters
{
protected $media;
 
public function __construct(Audio $media)
{
$this->media = $media;
}
 
/**
* Resamples the audio file.
*
* @param Integer $rate
*
* @return AudioFilters
*/
public function resample($rate)
{
$this->media->addFilter(new AudioResamplableFilter($rate));
 
return $this;
}
 
/**
* Add metadata to an audio file. If no arguments are given then filter
* will remove all metadata from the audio file
* @param Array|Null $data If array must contain one of these key/value pairs:
* - "title": Title metadata
* - "artist": Artist metadata
* - "composer": Composer metadata
* - "album": Album metadata
* - "track": Track metadata
* - "artwork": Song artwork. String of file path
* - "year": Year metadata
* - "genre": Genre metadata
* - "description": Description metadata
*/
public function addMetadata($data = null)
{
$this->media->addFilter(new AddMetadataFilter($data));
 
return $this;
}
 
/**
* Cuts the audio at `$start`, optionally define the end
*
* @param TimeCode $start Where the clipping starts(seek to time)
* @param TimeCode $duration How long the clipped audio should be
* @return AudioFilters
*/
public function clip($start, $duration = null) {
$this->media->addFilter(new AudioClipFilter($start, $duration));
 
return $this;
}
}
/vendor/php-ffmpeg/php-ffmpeg/src/FFMpeg/Filters/Audio/AudioResamplableFilter.php
@@ -0,0 +1,54 @@
<?php
 
/*
* This file is part of PHP-FFmpeg.
*
* (c) Alchemy <dev.team@alchemy.fr>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
 
namespace FFMpeg\Filters\Audio;
 
use FFMpeg\Format\AudioInterface;
use FFMpeg\Media\Audio;
 
class AudioResamplableFilter implements AudioFilterInterface
{
/** @var string */
private $rate;
/** @var integer */
private $priority;
 
public function __construct($rate, $priority = 0)
{
$this->rate = $rate;
$this->priority = $priority;
}
 
/**
* {@inheritdoc}
*/
public function getPriority()
{
return $this->priority;
}
 
/**
*
* @return Integer
*/
public function getRate()
{
return $this->rate;
}
 
/**
* {@inheritdoc}
*/
public function apply(Audio $audio, AudioInterface $format)
{
return array('-ac', 2, '-ar', $this->rate);
}
}
/vendor/php-ffmpeg/php-ffmpeg/src/FFMpeg/Filters/Audio/SimpleFilter.php
@@ -0,0 +1,43 @@
<?php
 
/*
* This file is part of PHP-FFmpeg.
*
* (c) Alchemy <info@alchemy.fr>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
 
namespace FFMpeg\Filters\Audio;
 
use FFMpeg\Media\Audio;
use FFMpeg\Format\AudioInterface;
 
class SimpleFilter implements AudioFilterInterface
{
private $params;
private $priority;
 
public function __construct(array $params, $priority = 0)
{
$this->params = $params;
$this->priority = $priority;
}
 
/**
* {@inheritdoc}
*/
public function getPriority()
{
return $this->priority;
}
 
/**
* {@inheritdoc}
*/
public function apply(Audio $audio, AudioInterface $format)
{
return $this->params;
}
}
/vendor/php-ffmpeg/php-ffmpeg/src/FFMpeg/Filters/Concat/ConcatFilterInterface.php
@@ -0,0 +1,20 @@
<?php
 
/*
* This file is part of PHP-FFmpeg.
*
* (c) Strime <contact@strime.io>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
 
namespace FFMpeg\Filters\Concat;
 
use FFMpeg\Filters\FilterInterface;
use FFMpeg\Media\Concat;
 
interface ConcatFilterInterface extends FilterInterface
{
public function apply(Concat $concat);
}
/vendor/php-ffmpeg/php-ffmpeg/src/FFMpeg/Filters/Concat/ConcatFilters.php
@@ -0,0 +1,24 @@
<?php
 
/*
* This file is part of PHP-FFmpeg.
*
* (c) Strime <contact@strime.io>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
 
namespace FFMpeg\Filters\Concat;
 
use FFMpeg\Media\Concat;
 
class ConcatFilters
{
private $concat;
 
public function __construct(Concat $concat)
{
$this->concat = $concat;
}
}
/vendor/php-ffmpeg/php-ffmpeg/src/FFMpeg/Filters/FilterInterface.php
@@ -0,0 +1,22 @@
<?php
 
/*
* This file is part of PHP-FFmpeg.
*
* (c) Alchemy <dev.team@alchemy.fr>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
 
namespace FFMpeg\Filters;
 
interface FilterInterface
{
/**
* Returns the priority of the filter.
*
* @return integer
*/
public function getPriority();
}
/vendor/php-ffmpeg/php-ffmpeg/src/FFMpeg/Filters/FiltersCollection.php
@@ -0,0 +1,60 @@
<?php
 
/*
* This file is part of PHP-FFmpeg.
*
* (c) Alchemy <dev.team@alchemy.fr>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
 
namespace FFMpeg\Filters;
 
class FiltersCollection implements \Countable, \IteratorAggregate
{
private $sorted;
private $filters = array();
 
/**
* @param FilterInterface $filter
*
* @return FiltersCollection
*/
public function add(FilterInterface $filter)
{
$this->filters[$filter->getPriority()][] = $filter;
$this->sorted = null;
 
return $this;
}
 
/**
* {@inheritdoc}
*/
public function count()
{
if (0 === count($this->filters)) {
return 0;
}
 
return count(call_user_func_array('array_merge', $this->filters));
}
 
/**
* {@inheritdoc}
*/
public function getIterator()
{
if (null === $this->sorted) {
if (0 === count($this->filters)) {
$this->sorted = $this->filters;
} else {
krsort($this->filters);
$this->sorted = call_user_func_array('array_merge', $this->filters);
}
}
 
return new \ArrayIterator($this->sorted);
}
}
/vendor/php-ffmpeg/php-ffmpeg/src/FFMpeg/Filters/Frame/DisplayRatioFixerFilter.php
@@ -0,0 +1,58 @@
<?php
 
/*
* This file is part of PHP-FFmpeg.
*
* (c) Alchemy <dev.team@alchemy.fr>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
 
namespace FFMpeg\Filters\Frame;
 
use FFMpeg\Exception\RuntimeException;
use FFMpeg\Media\Frame;
 
class DisplayRatioFixerFilter implements FrameFilterInterface
{
/** @var integer */
private $priority;
 
public function __construct($priority = 0)
{
$this->priority = $priority;
}
 
/**
* {@inheritdoc}
*/
public function getPriority()
{
return $this->priority;
}
 
/**
* {@inheritdoc}
*/
public function apply(Frame $frame)
{
$dimensions = null;
$commands = array();
 
foreach ($frame->getVideo()->getStreams() as $stream) {
if ($stream->isVideo()) {
try {
$dimensions = $stream->getDimensions();
$commands[] = '-s';
$commands[] = $dimensions->getWidth() . 'x' . $dimensions->getHeight();
break;
} catch (RuntimeException $e) {
 
}
}
}
 
return $commands;
}
}
/vendor/php-ffmpeg/php-ffmpeg/src/FFMpeg/Filters/Frame/FrameFilterInterface.php
@@ -0,0 +1,20 @@
<?php
 
/*
* This file is part of PHP-FFmpeg.
*
* (c) Alchemy <dev.team@alchemy.fr>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
 
namespace FFMpeg\Filters\Frame;
 
use FFMpeg\Filters\FilterInterface;
use FFMpeg\Media\Frame;
 
interface FrameFilterInterface extends FilterInterface
{
public function apply(Frame $frame);
}
/vendor/php-ffmpeg/php-ffmpeg/src/FFMpeg/Filters/Frame/FrameFilters.php
@@ -0,0 +1,39 @@
<?php
 
/*
* This file is part of PHP-FFmpeg.
*
* (c) Alchemy <dev.team@alchemy.fr>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
 
namespace FFMpeg\Filters\Frame;
 
use FFMpeg\Media\Frame;
 
class FrameFilters
{
private $frame;
 
public function __construct(Frame $frame)
{
$this->frame = $frame;
}
 
/**
* Fixes the display ratio of the output frame.
*
* In case the sample ratio and display ratio are different, image may be
* anamorphozed. This filter fixes this by specifying the output size.
*
* @return FrameFilters
*/
public function fixDisplayRatio()
{
$this->frame->addFilter(new DisplayRatioFixerFilter());
 
return $this;
}
}
/vendor/php-ffmpeg/php-ffmpeg/src/FFMpeg/Filters/Gif/GifFilterInterface.php
@@ -0,0 +1,20 @@
<?php
 
/*
* This file is part of PHP-FFmpeg.
*
* (c) Strime <contact@strime.io>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
 
namespace FFMpeg\Filters\Gif;
 
use FFMpeg\Filters\FilterInterface;
use FFMpeg\Media\Gif;
 
interface GifFilterInterface extends FilterInterface
{
public function apply(Gif $gif);
}
/vendor/php-ffmpeg/php-ffmpeg/src/FFMpeg/Filters/Gif/GifFilters.php
@@ -0,0 +1,24 @@
<?php
 
/*
* This file is part of PHP-FFmpeg.
*
* (c) Strime <contact@strime.io>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
 
namespace FFMpeg\Filters\Gif;
 
use FFMpeg\Media\Gif;
 
class GifFilters
{
private $gif;
 
public function __construct(Gif $gif)
{
$this->gif = $gif;
}
}
/vendor/php-ffmpeg/php-ffmpeg/src/FFMpeg/Filters/Video/ClipFilter.php
@@ -0,0 +1,72 @@
<?php
 
/*
* This file is part of PHP-FFmpeg.
*
* (c) Alchemy <dev.team@alchemy.fr>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
 
namespace FFMpeg\Filters\Video;
 
use FFMpeg\Format\VideoInterface;
use FFMpeg\Media\Video;
use FFMpeg\Coordinate\TimeCode;
 
class ClipFilter implements VideoFilterInterface
{
/** @var TimeCode */
private $start;
/** @var TimeCode */
private $duration;
/** @var integer */
private $priority;
 
public function __construct(TimeCode $start, TimeCode $duration = null, $priority = 0)
{
$this->start = $start;
$this->duration = $duration;
$this->priority = $priority;
}
 
/**
* {@inheritdoc}
*/
public function getPriority()
{
return $this->priority;
}
 
/**
* @return TimeCode
*/
public function getStart()
{
return $this->start;
}
 
/**
* @return TimeCode
*/
public function getDuration()
{
return $this->duration;
}
 
/**
* {@inheritdoc}
*/
public function apply(Video $video, VideoInterface $format)
{
$commands = array('-ss', (string) $this->start);
 
if ($this->duration !== null) {
$commands[] = '-t';
$commands[] = (string) $this->duration;
}
 
return $commands;
}
}
/vendor/php-ffmpeg/php-ffmpeg/src/FFMpeg/Filters/Video/CropFilter.php
@@ -0,0 +1,60 @@
<?php
/*
* This file is part of PHP-FFmpeg.
*
* (c) Alchemy <dev.team@alchemy.fr>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
 
namespace FFMpeg\Filters\Video;
 
use FFMpeg\Coordinate\Dimension;
use FFMpeg\Coordinate\Point;
use FFMpeg\Format\VideoInterface;
use FFMpeg\Media\Video;
 
class CropFilter implements VideoFilterInterface
{
/** @var integer */
protected $priority;
/** @var Dimension */
protected $dimension;
/** @var Point */
protected $point;
 
public function __construct(Point $point, Dimension $dimension, $priority = 0)
{
$this->priority = $priority;
$this->dimension = $dimension;
$this->point = $point;
}
 
/**
* {@inheritdoc}
*/
public function getPriority()
{
return $this->priority;
}
 
/**
* {@inheritdoc}
*/
public function apply(Video $video, VideoInterface $format)
{
foreach ($video->getStreams()->videos() as $stream) {
if ($stream->has('width') && $stream->has('height')) {
$stream->set('width', $this->dimension->getWidth());
$stream->set('height', $this->dimension->getHeight());
}
}
 
return array(
'-filter:v',
'crop=' .
$this->dimension->getWidth() .':' . $this->dimension->getHeight() . ':' . $this->point->getX() . ':' . $this->point->getY()
);
}
}
/vendor/php-ffmpeg/php-ffmpeg/src/FFMpeg/Filters/Video/CustomFilter.php
@@ -0,0 +1,52 @@
<?php
 
/*
* This file is part of PHP-FFmpeg.
*
* (c) Alchemy <dev.team@alchemy.fr>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace FFMpeg\Filters\Video;
 
use FFMpeg\Format\VideoInterface;
use FFMpeg\Media\Video;
 
class CustomFilter implements VideoFilterInterface
{
/** @var string */
private $filter;
/** @var integer */
private $priority;
 
/**
* A custom filter, useful if you want to build complex filters
*
* @param string $filter
* @param int $priority
*/
public function __construct($filter, $priority = 0)
{
$this->filter = $filter;
$this->priority = $priority;
}
 
/**
* {@inheritdoc}
*/
public function getPriority()
{
return $this->priority;
}
 
/**
* {@inheritdoc}
*/
public function apply(Video $video, VideoInterface $format)
{
$commands = array('-vf', $this->filter);
 
return $commands;
}
}
/vendor/php-ffmpeg/php-ffmpeg/src/FFMpeg/Filters/Video/ExtractMultipleFramesFilter.php
@@ -0,0 +1,128 @@
<?php
 
/*
* This file is part of PHP-FFmpeg.
*
* (c) Strime <romain@strime.io>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
 
namespace FFMpeg\Filters\Video;
 
use FFMpeg\Exception\InvalidArgumentException;
use FFMpeg\Exception\RuntimeException;
use FFMpeg\Media\Video;
use FFMpeg\Format\VideoInterface;
 
class ExtractMultipleFramesFilter implements VideoFilterInterface
{
/** will extract a frame every second */
const FRAMERATE_EVERY_SEC = '1/1';
/** will extract a frame every 2 seconds */
const FRAMERATE_EVERY_2SEC = '1/2';
/** will extract a frame every 5 seconds */
const FRAMERATE_EVERY_5SEC = '1/5';
/** will extract a frame every 10 seconds */
const FRAMERATE_EVERY_10SEC = '1/10';
/** will extract a frame every 30 seconds */
const FRAMERATE_EVERY_30SEC = '1/30';
/** will extract a frame every minute */
const FRAMERATE_EVERY_60SEC = '1/60';
 
/** @var integer */
private $priority;
private $frameRate;
private $destinationFolder;
 
public function __construct($frameRate = self::FRAMERATE_EVERY_SEC, $destinationFolder = __DIR__, $priority = 0)
{
$this->priority = $priority;
$this->frameRate = $frameRate;
 
// Make sure that the destination folder has a trailing slash
if(strcmp( substr($destinationFolder, -1), "/") != 0)
$destinationFolder .= "/";
 
// Set the destination folder
$this->destinationFolder = $destinationFolder;
}
 
/**
* {@inheritdoc}
*/
public function getPriority()
{
return $this->priority;
}
 
/**
* {@inheritdoc}
*/
public function getFrameRate()
{
return $this->frameRate;
}
 
/**
* {@inheritdoc}
*/
public function getDestinationFolder()
{
return $this->destinationFolder;
}
 
/**
* {@inheritdoc}
*/
public function apply(Video $video, VideoInterface $format)
{
$commands = array();
$duration = 0;
 
try {
// Get the duration of the video
foreach ($video->getStreams()->videos() as $stream) {
if ($stream->has('duration')) {
$duration = $stream->get('duration');
}
}
 
// Get the number of frames per second we have to extract.
if(preg_match('/(\d+)(?:\s*)([\+\-\*\/])(?:\s*)(\d+)/', $this->frameRate, $matches) !== FALSE){
$operator = $matches[2];
 
switch($operator){
case '/':
$nbFramesPerSecond = $matches[1] / $matches[3];
break;
 
default:
throw new InvalidArgumentException('The frame rate is not a proper division: ' . $this->frameRate);
break;
}
}
 
// Set the number of digits to use in the exported filenames
$nbImages = ceil( $duration * $nbFramesPerSecond );
 
if($nbImages < 100)
$nbDigitsInFileNames = "02";
elseif($nbImages < 1000)
$nbDigitsInFileNames = "03";
else
$nbDigitsInFileNames = "06";
 
// Set the parameters
$commands[] = '-vf';
$commands[] = 'fps=' . $this->frameRate;
$commands[] = $this->destinationFolder . 'frame-%'.$nbDigitsInFileNames.'d.jpg';
}
catch (RuntimeException $e) {
throw new RuntimeException('An error occured while extracting the frames: ' . $e->getMessage() . '. The code: ' . $e->getCode());
}
 
return $commands;
}
}
/vendor/php-ffmpeg/php-ffmpeg/src/FFMpeg/Filters/Video/FrameRateFilter.php
@@ -0,0 +1,82 @@
<?php
 
/*
* This file is part of PHP-FFmpeg.
*
* (c) Alchemy <dev.team@alchemy.fr>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
 
namespace FFMpeg\Filters\Video;
 
use FFMpeg\Coordinate\FrameRate;
use FFMpeg\Media\Video;
use FFMpeg\Format\VideoInterface;
 
class FrameRateFilter implements VideoFilterInterface
{
private $rate;
private $gop;
private $priority;
 
public function __construct(FrameRate $rate, $gop, $priority = 0)
{
$this->rate = $rate;
$this->gop = $gop;
$this->priority = $priority;
}
 
/**
* {@inheritdoc}
*/
public function getPriority()
{
return $this->priority;
}
 
/**
* Returns the frame rate.
*
* @return FrameRate
*/
public function getFrameRate()
{
return $this->rate;
}
 
/**
* Returns the GOP size.
*
* @see https://wikipedia.org/wiki/Group_of_pictures
*
* @return Integer
*/
public function getGOP()
{
return $this->gop;
}
 
/**
* {@inheritdoc}
*/
public function apply(Video $video, VideoInterface $format)
{
$commands = array('-r', $this->rate->getValue());
 
/**
* @see http://sites.google.com/site/linuxencoding/x264-ffmpeg-mapping
*/
if ($format->supportBFrames()) {
$commands[] = '-b_strategy';
$commands[] = '1';
$commands[] = '-bf';
$commands[] = '3';
$commands[] = '-g';
$commands[] = $this->gop;
}
 
return $commands;
}
}
/vendor/php-ffmpeg/php-ffmpeg/src/FFMpeg/Filters/Video/PadFilter.php
@@ -0,0 +1,59 @@
<?php
 
/*
* This file is part of PHP-FFmpeg.
*
* (c) Strime <contact@strime.io>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
 
namespace FFMpeg\Filters\Video;
 
use FFMpeg\Coordinate\Dimension;
use FFMpeg\Media\Video;
use FFMpeg\Format\VideoInterface;
 
class PadFilter implements VideoFilterInterface
{
/** @var Dimension */
private $dimension;
/** @var integer */
private $priority;
 
public function __construct(Dimension $dimension, $priority = 0)
{
$this->dimension = $dimension;
$this->priority = $priority;
}
 
/**
* {@inheritdoc}
*/
public function getPriority()
{
return $this->priority;
}
 
/**
* @return Dimension
*/
public function getDimension()
{
return $this->dimension;
}
 
/**
* {@inheritdoc}
*/
public function apply(Video $video, VideoInterface $format)
{
$commands = array();
 
$commands[] = '-vf';
$commands[] = 'scale=iw*min(' . $this->dimension->getWidth() . '/iw\,' . $this->dimension->getHeight() .'/ih):ih*min(' . $this->dimension->getWidth() . '/iw\,' . $this->dimension->getHeight() .'/ih),pad=' . $this->dimension->getWidth() . ':' . $this->dimension->getHeight() . ':(' . $this->dimension->getWidth() . '-iw)/2:(' . $this->dimension->getHeight() .'-ih)/2';
 
return $commands;
}
}
/vendor/php-ffmpeg/php-ffmpeg/src/FFMpeg/Filters/Video/ResizeFilter.php
@@ -0,0 +1,143 @@
<?php
 
/*
* This file is part of PHP-FFmpeg.
*
* (c) Alchemy <dev.team@alchemy.fr>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
 
namespace FFMpeg\Filters\Video;
 
use FFMpeg\Coordinate\Dimension;
use FFMpeg\Exception\RuntimeException;
use FFMpeg\Media\Video;
use FFMpeg\Format\VideoInterface;
 
class ResizeFilter implements VideoFilterInterface
{
/** fits to the dimensions, might introduce anamorphosis */
const RESIZEMODE_FIT = 'fit';
/** resizes the video inside the given dimension, no anamorphosis */
const RESIZEMODE_INSET = 'inset';
/** resizes the video to fit the dimension width, no anamorphosis */
const RESIZEMODE_SCALE_WIDTH = 'width';
/** resizes the video to fit the dimension height, no anamorphosis */
const RESIZEMODE_SCALE_HEIGHT = 'height';
 
/** @var Dimension */
private $dimension;
/** @var string */
private $mode;
/** @var Boolean */
private $forceStandards;
/** @var integer */
private $priority;
 
public function __construct(Dimension $dimension, $mode = self::RESIZEMODE_FIT, $forceStandards = true, $priority = 0)
{
$this->dimension = $dimension;
$this->mode = $mode;
$this->forceStandards = $forceStandards;
$this->priority = $priority;
}
 
/**
* {@inheritdoc}
*/
public function getPriority()
{
return $this->priority;
}
 
/**
* @return Dimension
*/
public function getDimension()
{
return $this->dimension;
}
 
/**
* @return string
*/
public function getMode()
{
return $this->mode;
}
 
/**
* @return Boolean
*/
public function areStandardsForced()
{
return $this->forceStandards;
}
 
/**
* {@inheritdoc}
*/
public function apply(Video $video, VideoInterface $format)
{
$dimensions = null;
$commands = array();
 
foreach ($video->getStreams() as $stream) {
if ($stream->isVideo()) {
try {
$dimensions = $stream->getDimensions();
break;
} catch (RuntimeException $e) {
 
}
}
}
 
if (null !== $dimensions) {
$dimensions = $this->getComputedDimensions($dimensions, $format->getModulus());
 
// Using Filter to have ordering
$commands[] = '-vf';
$commands[] = '[in]scale=' . $dimensions->getWidth() . ':' . $dimensions->getHeight() . ' [out]';
}
 
return $commands;
}
 
private function getComputedDimensions(Dimension $dimension, $modulus)
{
$originalRatio = $dimension->getRatio($this->forceStandards);
 
switch ($this->mode) {
case self::RESIZEMODE_SCALE_WIDTH:
$height = $this->dimension->getHeight();
$width = $originalRatio->calculateWidth($height, $modulus);
break;
case self::RESIZEMODE_SCALE_HEIGHT:
$width = $this->dimension->getWidth();
$height = $originalRatio->calculateHeight($width, $modulus);
break;
case self::RESIZEMODE_INSET:
$targetRatio = $this->dimension->getRatio($this->forceStandards);
 
if ($targetRatio->getValue() > $originalRatio->getValue()) {
$height = $this->dimension->getHeight();
$width = $originalRatio->calculateWidth($height, $modulus);
} else {
$width = $this->dimension->getWidth();
$height = $originalRatio->calculateHeight($width, $modulus);
}
break;
case self::RESIZEMODE_FIT:
default:
$width = $this->dimension->getWidth();
$height = $this->dimension->getHeight();
break;
}
 
return new Dimension($width, $height);
}
}
/vendor/php-ffmpeg/php-ffmpeg/src/FFMpeg/Filters/Video/RotateFilter.php
@@ -0,0 +1,82 @@
<?php
 
/*
* This file is part of PHP-FFmpeg.
*
* (c) Alchemy <dev.team@alchemy.fr>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
 
namespace FFMpeg\Filters\Video;
 
use FFMpeg\Coordinate\Dimension;
use FFMpeg\Exception\InvalidArgumentException;
use FFMpeg\Media\Video;
use FFMpeg\Format\VideoInterface;
 
class RotateFilter implements VideoFilterInterface
{
const ROTATE_90 = 'transpose=1';
const ROTATE_180 = 'hflip,vflip';
const ROTATE_270 = 'transpose=2';
 
/** @var string */
private $angle;
/** @var integer */
private $priority;
 
public function __construct($angle, $priority = 0)
{
$this->setAngle($angle);
$this->priority = (int) $priority;
}
 
/**
* {@inheritdoc}
*/
public function getPriority()
{
return $this->priority;
}
 
/**
* @return Dimension
*/
public function getAngle()
{
return $this->angle;
}
 
/**
* {@inheritdoc}
*/
public function apply(Video $video, VideoInterface $format)
{
if (in_array($this->angle, array(self::ROTATE_90, self::ROTATE_270), true)) {
foreach ($video->getStreams()->videos() as $stream) {
if ($stream->has('width') && $stream->has('height')) {
$width = $stream->get('width');
$stream->set('width', $stream->get('height'));
$stream->set('height', $width);
}
}
}
 
return array('-vf', $this->angle, '-metadata:s:v:0', 'rotate=0');
}
 
private function setAngle($angle)
{
switch ($angle) {
case self::ROTATE_90:
case self::ROTATE_180:
case self::ROTATE_270:
$this->angle = $angle;
break;
default:
throw new InvalidArgumentException('Invalid angle value.');
}
}
}
/vendor/php-ffmpeg/php-ffmpeg/src/FFMpeg/Filters/Video/SynchronizeFilter.php
@@ -0,0 +1,44 @@
<?php
 
/*
* This file is part of PHP-FFmpeg.
*
* (c) Alchemy <dev.team@alchemy.fr>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
 
namespace FFMpeg\Filters\Video;
 
use FFMpeg\Format\VideoInterface;
use FFMpeg\Media\Video;
 
/**
* Synchronizes audio and video in case of desynchronized movies.
*/
class SynchronizeFilter implements VideoFilterInterface
{
private $priority;
 
public function __construct($priority = 12)
{
$this->priority = $priority;
}
 
/**
* {@inheritdoc}
*/
public function getPriority()
{
return $this->priority;
}
 
/**
* {@inheritdoc}
*/
public function apply(Video $video, VideoInterface $format)
{
return array('-async', '1', '-metadata:s:v:0', 'start_time=0');
}
}
/vendor/php-ffmpeg/php-ffmpeg/src/FFMpeg/Filters/Video/VideoFilterInterface.php
@@ -0,0 +1,29 @@
<?php
 
/*
* This file is part of PHP-FFmpeg.
*
* (c) Alchemy <dev.team@alchemy.fr>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
 
namespace FFMpeg\Filters\Video;
 
use FFMpeg\Filters\FilterInterface;
use FFMpeg\Format\VideoInterface;
use FFMpeg\Media\Video;
 
interface VideoFilterInterface extends FilterInterface
{
/**
* Applies the filter on the the Video media given an format.
*
* @param Video $video
* @param VideoInterface $format
*
* @return array An array of arguments
*/
public function apply(Video $video, VideoInterface $format);
}
/vendor/php-ffmpeg/php-ffmpeg/src/FFMpeg/Filters/Video/VideoFilters.php
@@ -0,0 +1,178 @@
<?php
 
/*
* This file is part of PHP-FFmpeg.
*
* (c) Alchemy <dev.team@alchemy.fr>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
 
namespace FFMpeg\Filters\Video;
 
use FFMpeg\Coordinate\Point;
use FFMpeg\Media\Video;
use FFMpeg\Coordinate\TimeCode;
use FFMpeg\Coordinate\Dimension;
use FFMpeg\Coordinate\FrameRate;
use FFMpeg\Filters\Audio\AudioResamplableFilter;
use FFMpeg\Filters\Audio\AudioFilters;
 
class VideoFilters extends AudioFilters
{
public function __construct(Video $media)
{
parent::__construct($media);
}
 
/**
* Resizes a video to a given dimension.
*
* @param Dimension $dimension
* @param string $mode
* @param Boolean $forceStandards
*
* @return VideoFilters
*/
public function resize(Dimension $dimension, $mode = ResizeFilter::RESIZEMODE_FIT, $forceStandards = true)
{
$this->media->addFilter(new ResizeFilter($dimension, $mode, $forceStandards));
 
return $this;
}
 
/**
* Changes the video framerate.
*
* @param FrameRate $framerate
* @param Integer $gop
*
* @return VideoFilters
*/
public function framerate(FrameRate $framerate, $gop)
{
$this->media->addFilter(new FrameRateFilter($framerate, $gop));
 
return $this;
}
 
/**
* Extract multiple frames from the video
*
* @param string $frameRate
* @param string $destinationFolder
*
* @return $this
*/
public function extractMultipleFrames($frameRate = ExtractMultipleFramesFilter::FRAMERATE_EVERY_2SEC, $destinationFolder = __DIR__)
{
$this->media->addFilter(new ExtractMultipleFramesFilter($frameRate, $destinationFolder));
 
return $this;
}
 
/**
* Synchronizes audio and video.
*
* @return VideoFilters
*/
public function synchronize()
{
$this->media->addFilter(new SynchronizeFilter());
 
return $this;
}
 
/**
* Clips (cuts) the video.
*
* @param TimeCode $start
* @param TimeCode $duration
*
* @return VideoFilters
*/
public function clip($start, $duration = null)
{
$this->media->addFilter(new ClipFilter($start, $duration));
 
return $this;
}
 
/**
* Resamples the audio file.
*
* @param Integer $rate
*
* @return AudioFilters
*/
public function audioResample($rate)
{
$this->media->addFilter(new AudioResamplableFilter($rate));
 
return $this;
}
 
/**
* Adds padding (black bars) to a video.
*
* @param Dimension $dimension
*
* @return VideoFilters
*/
public function pad(Dimension $dimension)
{
$this->media->addFilter(new PadFilter($dimension));
 
return $this;
}
 
public function rotate($angle)
{
$this->media->addFilter(new RotateFilter($angle, 30));
 
return $this;
}
 
/**
* Crops the video
*
* @param Point $point
* @param Dimension $dimension
*
* @return VideoFilters
*/
public function crop(Point $point, Dimension $dimension)
{
$this->media->addFilter(new CropFilter($point, $dimension));
 
return $this;
}
 
/**
* @param string $imagePath
* @param array $coordinates
*
* @return $this
*/
public function watermark($imagePath, array $coordinates = array())
{
$this->media->addFilter(new WatermarkFilter($imagePath, $coordinates));
 
return $this;
}
 
/**
* Applies a custom filter: -vf foo bar
*
* @param string $parameters
*
* @return VideoFilters
*/
public function custom($parameters)
{
$this->media->addFilter(new CustomFilter($parameters));
 
return $this;
}
}
/vendor/php-ffmpeg/php-ffmpeg/src/FFMpeg/Filters/Video/WatermarkFilter.php
@@ -0,0 +1,80 @@
<?php
 
/*
* This file is part of PHP-FFmpeg.
*
* (c) Alchemy <dev.team@alchemy.fr>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
 
namespace FFMpeg\Filters\Video;
 
use FFMpeg\Exception\InvalidArgumentException;
use FFMpeg\Format\VideoInterface;
use FFMpeg\Media\Video;
 
class WatermarkFilter implements VideoFilterInterface
{
/** @var string */
private $watermarkPath;
/** @var array */
private $coordinates;
/** @var integer */
private $priority;
 
public function __construct($watermarkPath, array $coordinates = array(), $priority = 0)
{
if (!file_exists($watermarkPath)) {
throw new InvalidArgumentException(sprintf('File %s does not exist', $watermarkPath));
}
 
$this->watermarkPath = $watermarkPath;
$this->coordinates = $coordinates;
$this->priority = $priority;
}
 
/**
* {@inheritdoc}
*/
public function getPriority()
{
return $this->priority;
}
 
/**
* {@inheritdoc}
*/
public function apply(Video $video, VideoInterface $format)
{
$position = isset($this->coordinates['position']) ? $this->coordinates['position'] : 'absolute';
 
switch ($position) {
case 'relative':
if (isset($this->coordinates['top'])) {
$y = $this->coordinates['top'];
} elseif (isset($this->coordinates['bottom'])) {
$y = sprintf('main_h - %d - overlay_h', $this->coordinates['bottom']);
} else {
$y = 0;
}
 
if (isset($this->coordinates['left'])) {
$x = $this->coordinates['left'];
} elseif (isset($this->coordinates['right'])) {
$x = sprintf('main_w - %d - overlay_w', $this->coordinates['right']);
} else {
$x = 0;
}
 
break;
default:
$x = isset($this->coordinates['x']) ? $this->coordinates['x'] : 0;
$y = isset($this->coordinates['y']) ? $this->coordinates['y'] : 0;
break;
}
 
return array('-vf', sprintf('movie=%s [watermark]; [in][watermark] overlay=%s:%s [out]', $this->watermarkPath, $x, $y));
}
}
/vendor/php-ffmpeg/php-ffmpeg/src/FFMpeg/Filters/Waveform/WaveformDownmixFilter.php
@@ -0,0 +1,74 @@
<?php
 
/*
* This file is part of PHP-FFmpeg.
*
* (c) Strime <contact@strime.io>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
 
namespace FFMpeg\Filters\Waveform;
 
use FFMpeg\Exception\RuntimeException;
use FFMpeg\Media\Waveform;
 
class WaveformDownmixFilter implements WaveformFilterInterface
{
 
/** @var boolean */
private $downmix;
/** @var integer */
private $priority;
 
// By default, the downmix value is set to FALSE.
public function __construct($downmix = FALSE, $priority = 0)
{
$this->downmix = $downmix;
$this->priority = $priority;
}
 
/**
* {@inheritdoc}
*/
public function getDownmix()
{
return $this->downmix;
}
 
/**
* {@inheritdoc}
*/
public function getPriority()
{
return $this->priority;
}
 
/**
* {@inheritdoc}
*/
public function apply(Waveform $waveform)
{
$commands = array();
 
foreach ($waveform->getAudio()->getStreams() as $stream) {
if ($stream->isAudio()) {
try {
// If the downmix parameter is set to TRUE, we add an option to the FFMPEG command
if($this->downmix == TRUE) {
$commands[] = '"aformat=channel_layouts=mono"';
}
break;
 
} catch (RuntimeException $e) {
 
}
}
}
 
return $commands;
}
}
/vendor/php-ffmpeg/php-ffmpeg/src/FFMpeg/Filters/Waveform/WaveformFilterInterface.php
@@ -0,0 +1,20 @@
<?php
 
/*
* This file is part of PHP-FFmpeg.
*
* (c) Strime <contact@strime.io>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
 
namespace FFMpeg\Filters\Waveform;
 
use FFMpeg\Filters\FilterInterface;
use FFMpeg\Media\Waveform;
 
interface WaveformFilterInterface extends FilterInterface
{
public function apply(Waveform $waveform);
}
/vendor/php-ffmpeg/php-ffmpeg/src/FFMpeg/Filters/Waveform/WaveformFilters.php
@@ -0,0 +1,38 @@
<?php
 
/*
* This file is part of PHP-FFmpeg.
*
* (c) Strime <contact@strime.io>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
 
namespace FFMpeg\Filters\Waveform;
 
use FFMpeg\Media\Waveform;
 
class WaveformFilters
{
private $waveform;
 
public function __construct(Waveform $waveform)
{
$this->waveform = $waveform;
}
 
/**
* Sets the downmix of the output waveform.
*
* If you want a simpler waveform, sets the downmix to TRUE.
*
* @return WaveformFilters
*/
public function setDownmix()
{
$this->waveform->addFilter(new WaveformDownmixFilter());
 
return $this;
}
}
/vendor/php-ffmpeg/php-ffmpeg/src/FFMpeg/Format/Audio/Aac.php
@@ -0,0 +1,31 @@
<?php
 
/*
* This file is part of PHP-FFmpeg.
*
* (c) Alchemy <info@alchemy.fr>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
 
namespace FFMpeg\Format\Audio;
 
/**
* The AAC audio format
*/
class Aac extends DefaultAudio
{
public function __construct()
{
$this->audioCodec = 'libfdk_aac';
}
 
/**
* {@inheritDoc}
*/
public function getAvailableAudioCodecs()
{
return array('libfdk_aac');
}
}
/vendor/php-ffmpeg/php-ffmpeg/src/FFMpeg/Format/Audio/DefaultAudio.php
@@ -0,0 +1,142 @@
<?php
 
/*
* This file is part of PHP-FFmpeg.
*
* (c) Alchemy <info@alchemy.fr>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
 
namespace FFMpeg\Format\Audio;
 
use Evenement\EventEmitter;
use FFMpeg\Exception\InvalidArgumentException;
use FFMpeg\Format\AudioInterface;
use FFMpeg\Media\MediaTypeInterface;
use FFMpeg\Format\ProgressableInterface;
use FFMpeg\Format\ProgressListener\AudioProgressListener;
use FFMpeg\FFProbe;
 
abstract class DefaultAudio extends EventEmitter implements AudioInterface, ProgressableInterface
{
/** @var string */
protected $audioCodec;
 
/** @var integer */
protected $audioKiloBitrate = 128;
 
/** @var integer */
protected $audioChannels = null;
 
/**
* {@inheritdoc}
*/
public function getExtraParams()
{
return array();
}
 
/**
* {@inheritdoc}
*/
public function getAudioCodec()
{
return $this->audioCodec;
}
 
/**
* Sets the audio codec, Should be in the available ones, otherwise an
* exception is thrown.
*
* @param string $audioCodec
*
* @throws InvalidArgumentException
*/
public function setAudioCodec($audioCodec)
{
if ( ! in_array($audioCodec, $this->getAvailableAudioCodecs())) {
throw new InvalidArgumentException(sprintf(
'Wrong audiocodec value for %s, available formats are %s'
, $audioCodec, implode(', ', $this->getAvailableAudioCodecs())
));
}
 
$this->audioCodec = $audioCodec;
 
return $this;
}
 
/**
* {@inheritdoc}
*/
public function getAudioKiloBitrate()
{
return $this->audioKiloBitrate;
}
 
/**
* Sets the kiloBitrate value.
*
* @param integer $kiloBitrate
* @throws InvalidArgumentException
*/
public function setAudioKiloBitrate($kiloBitrate)
{
if ($kiloBitrate < 1) {
throw new InvalidArgumentException('Wrong kiloBitrate value');
}
 
$this->audioKiloBitrate = (int) $kiloBitrate;
 
return $this;
}
 
/**
* {@inheritdoc}
*/
public function getAudioChannels()
{
return $this->audioChannels;
}
 
/**
* Sets the channels value.
*
* @param integer $channels
* @throws InvalidArgumentException
*/
public function setAudioChannels($channels)
{
if ($channels < 1) {
throw new InvalidArgumentException('Wrong channels value');
}
 
$this->audioChannels = (int) $channels;
 
return $this;
}
 
/**
* {@inheritdoc}
*/
public function createProgressListener(MediaTypeInterface $media, FFProbe $ffprobe, $pass, $total)
{
$format = $this;
$listener = new AudioProgressListener($ffprobe, $media->getPathfile(), $pass, $total);
$listener->on('progress', function () use ($media, $format) {
$format->emit('progress', array_merge(array($media, $format), func_get_args()));
});
 
return array($listener);
}
 
/**
* {@inheritDoc}
*/
public function getPasses()
{
return 1;
}
}
/vendor/php-ffmpeg/php-ffmpeg/src/FFMpeg/Format/Audio/Flac.php
@@ -0,0 +1,31 @@
<?php
 
/*
* This file is part of PHP-FFmpeg.
*
* (c) Alchemy <info@alchemy.fr>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
 
namespace FFMpeg\Format\Audio;
 
/**
* The Flac audio format
*/
class Flac extends DefaultAudio
{
public function __construct()
{
$this->audioCodec = 'flac';
}
 
/**
* {@inheritDoc}
*/
public function getAvailableAudioCodecs()
{
return array('flac');
}
}
/vendor/php-ffmpeg/php-ffmpeg/src/FFMpeg/Format/Audio/Mp3.php
@@ -0,0 +1,31 @@
<?php
 
/*
* This file is part of PHP-FFmpeg.
*
* (c) Alchemy <info@alchemy.fr>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
 
namespace FFMpeg\Format\Audio;
 
/**
* The MP3 audio format
*/
class Mp3 extends DefaultAudio
{
public function __construct()
{
$this->audioCodec = 'libmp3lame';
}
 
/**
* {@inheritDoc}
*/
public function getAvailableAudioCodecs()
{
return array('libmp3lame');
}
}
/vendor/php-ffmpeg/php-ffmpeg/src/FFMpeg/Format/Audio/Vorbis.php
@@ -0,0 +1,39 @@
<?php
 
/*
* This file is part of PHP-FFmpeg.
*
* (c) Alchemy <info@alchemy.fr>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
 
namespace FFMpeg\Format\Audio;
 
/**
* The Vorbis audio format
*/
class Vorbis extends DefaultAudio
{
public function __construct()
{
$this->audioCodec = 'vorbis';
}
 
/**
* {@inheritdoc}
*/
public function getExtraParams()
{
return array('-strict', '-2');
}
 
/**
* {@inheritDoc}
*/
public function getAvailableAudioCodecs()
{
return array('vorbis');
}
}
/vendor/php-ffmpeg/php-ffmpeg/src/FFMpeg/Format/Audio/Wav.php
@@ -0,0 +1,31 @@
<?php
 
/*
* This file is part of PHP-FFmpeg.
*
* (c) Alchemy <info@alchemy.fr>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
 
namespace FFMpeg\Format\Audio;
 
/**
* The WAV audio format
*/
class Wav extends DefaultAudio
{
public function __construct()
{
$this->audioCodec = 'pcm_s16le';
}
 
/**
* {@inheritDoc}
*/
public function getAvailableAudioCodecs()
{
return array('pcm_s16le');
}
}
/vendor/php-ffmpeg/php-ffmpeg/src/FFMpeg/Format/AudioInterface.php
@@ -0,0 +1,42 @@
<?php
 
/*
* This file is part of PHP-FFmpeg.
*
* (c) Alchemy <info@alchemy.fr>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace FFMpeg\Format;
 
interface AudioInterface extends FormatInterface
{
/**
* Gets the audio kiloBitrate value.
*
* @return integer
*/
public function getAudioKiloBitrate();
 
/**
* Gets the audio channels value.
*
* @return integer
*/
public function getAudioChannels();
 
/**
* Returns the audio codec.
*
* @return string
*/
public function getAudioCodec();
 
/**
* Returns the list of available audio codecs for this format.
*
* @return array
*/
public function getAvailableAudioCodecs();
}
/vendor/php-ffmpeg/php-ffmpeg/src/FFMpeg/Format/FormatInterface.php
@@ -0,0 +1,28 @@
<?php
 
/*
* This file is part of PHP-FFmpeg.
*
* (c) Alchemy <info@alchemy.fr>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace FFMpeg\Format;
 
interface FormatInterface
{
/**
* Returns the number of passes.
*
* @return string
*/
public function getPasses();
 
/**
* Returns an array of extra parameters to add to ffmpeg commandline.
*
* @return array()
*/
public function getExtraParams();
}
/vendor/php-ffmpeg/php-ffmpeg/src/FFMpeg/Format/FrameInterface.php
@@ -0,0 +1,16 @@
<?php
 
/*
* This file is part of PHP-FFmpeg.
*
* (c) Alchemy <dev.team@alchemy.fr>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
 
namespace FFMpeg\Format;
 
interface FrameInterface extends FormatInterface
{
}
/vendor/php-ffmpeg/php-ffmpeg/src/FFMpeg/Format/ProgressListener/AbstractProgressListener.php
@@ -0,0 +1,262 @@
<?php
 
/*
* This file is part of PHP-FFmpeg.
*
* (c) Alchemy <info@alchemy.fr>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
 
namespace FFMpeg\Format\ProgressListener;
 
use Alchemy\BinaryDriver\Listeners\ListenerInterface;
use Evenement\EventEmitter;
use FFMpeg\FFProbe;
use FFMpeg\Exception\RuntimeException;
 
/**
* @author Robert Gruendler <r.gruendler@gmail.com>
*/
abstract class AbstractProgressListener extends EventEmitter implements ListenerInterface
{
/** @var integer */
private $duration;
 
/** @var integer */
private $totalSize;
 
/** @var integer */
private $currentSize;
 
/** @var integer */
private $currentTime;
 
/** @var double */
private $lastOutput = null;
 
/** @var FFProbe */
private $ffprobe;
 
/** @var string */
private $pathfile;
 
/** @var Boolean */
private $initialized = false;
 
/** @var integer */
private $currentPass;
 
/** @var integer */
private $totalPass;
 
/**
* Transcoding rate in kb/s
*
* @var integer
*/
private $rate;
 
/**
* Percentage of transcoding progress (0 - 100)
*
* @var integer
*/
private $percent = 0;
 
/**
* Time remaining (seconds)
*
* @var integer
*/
private $remaining = null;
 
/**
* @param FFProbe $ffprobe
* @param string $pathfile
* @param integer $currentPass The cureent pass number
* @param integer $totalPass The total number of passes
*
* @throws RuntimeException
*/
public function __construct(FFProbe $ffprobe, $pathfile, $currentPass, $totalPass)
{
$this->ffprobe = $ffprobe;
$this->pathfile = $pathfile;
$this->currentPass = $currentPass;
$this->totalPass = $totalPass;
}
 
/**
* @return FFProbe
*/
public function getFFProbe()
{
return $this->ffprobe;
}
 
/**
* @return string
*/
public function getPathfile()
{
return $this->pathfile;
}
 
/**
* @return integer
*/
public function getCurrentPass()
{
return $this->currentPass;
}
 
/**
* @return integer
*/
public function getTotalPass()
{
return $this->totalPass;
}
 
/**
* @return int
*/
public function getCurrentTime()
{
return $this->currentTime;
}
 
/**
* {@inheritdoc}
*/
public function handle($type, $data)
{
if (null !== $progress = $this->parseProgress($data)) {
$this->emit('progress', array_values($progress));
}
}
 
/**
* {@inheritdoc}
*/
public function forwardedEvents()
{
return array();
}
 
/**
* Get the regex pattern to match a ffmpeg stderr status line
*/
abstract protected function getPattern();
 
/**
* @param string $progress A ffmpeg stderr progress output
*
* @return array the progressinfo array or null if there's no progress available yet.
*/
private function parseProgress($progress)
{
if (!$this->initialized) {
$this->initialize();
}
 
if (null === $this->totalSize || null === $this->duration) {
return;
}
 
$matches = array();
 
if (preg_match($this->getPattern(), $progress, $matches) !== 1) {
return null;
}
 
$currentDuration = $this->convertDuration($matches[2]);
$currentTime = microtime(true);
$currentSize = trim(str_replace('kb', '', strtolower(($matches[1]))));
$percent = max(0, min(1, $currentDuration / $this->duration));
 
if ($this->lastOutput !== null) {
$delta = $currentTime - $this->lastOutput;
 
// Check the type of the currentSize variable and convert it to an integer if needed.
if(!is_numeric($currentSize)) {
$currentSize = (int)$currentSize;
}
 
$deltaSize = $currentSize - $this->currentSize;
$rate = $deltaSize * $delta;
if ($rate > 0) {
$totalDuration = $this->totalSize / $rate;
$this->remaining = floor($totalDuration - ($totalDuration * $percent));
$this->rate = floor($rate);
} else {
$this->remaining = 0;
$this->rate = 0;
}
}
 
$percent = $percent / $this->totalPass + ($this->currentPass - 1) / $this->totalPass;
 
$this->percent = floor($percent * 100);
$this->lastOutput = $currentTime;
$this->currentSize = (int) $currentSize;
$this->currentTime = $currentDuration;
 
return $this->getProgressInfo();
}
 
/**
*
* @param string $rawDuration in the format 00:00:00.00
* @return number
*/
private function convertDuration($rawDuration)
{
$ar = array_reverse(explode(":", $rawDuration));
$duration = floatval($ar[0]);
if (!empty($ar[1])) {
$duration += intval($ar[1]) * 60;
}
if (!empty($ar[2])) {
$duration += intval($ar[2]) * 60 * 60;
}
 
return $duration;
}
 
/**
* @return array
*/
private function getProgressInfo()
{
if ($this->remaining === null) {
return null;
}
 
return array(
'percent' => $this->percent,
'remaining' => $this->remaining,
'rate' => $this->rate
);
}
 
private function initialize()
{
try {
$format = $this->ffprobe->format($this->pathfile);
} catch (RuntimeException $e) {
return;
}
 
if (false === $format->has('size') || false === $format->has('duration')) {
return;
}
 
$this->totalSize = $format->get('size') / 1024;
$this->duration = $format->get('duration');
 
$this->initialized = true;
}
}
/vendor/php-ffmpeg/php-ffmpeg/src/FFMpeg/Format/ProgressListener/AudioProgressListener.php
@@ -0,0 +1,29 @@
<?php
 
/*
* This file is part of PHP-FFmpeg.
*
* (c) Alchemy <info@alchemy.fr>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
 
namespace FFMpeg\Format\ProgressListener;
 
/**
* Parses ffmpeg stderr progress information. An example:
*
* <pre>
* size= 3552kB time=00:03:47.29 bitrate= 128.0kbits/s
* </pre>
*
* @author Robert Gruendler <r.gruendler@gmail.com>
*/
class AudioProgressListener extends AbstractProgressListener
{
public function getPattern()
{
return '/size=(.*?) time=(.*?) /';
}
}
/vendor/php-ffmpeg/php-ffmpeg/src/FFMpeg/Format/ProgressListener/VideoProgressListener.php
@@ -0,0 +1,29 @@
<?php
 
/*
* This file is part of PHP-FFmpeg.
*
* (c) Alchemy <info@alchemy.fr>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
 
namespace FFMpeg\Format\ProgressListener;
 
/**
* Parses ffmpeg stderr progress information for video files. An example:
*
* <pre>
* frame= 171 fps=0.0 q=10.0 size= 18kB time=00:00:05.72 bitrate= 26.4kbits/s dup=8 drop=0
* </pre>
*
* @author Robert Gruendler <r.gruendler@gmail.com>
*/
class VideoProgressListener extends AbstractProgressListener
{
public function getPattern()
{
return '/size=(.*?) time=(.*?) /';
}
}
/vendor/php-ffmpeg/php-ffmpeg/src/FFMpeg/Format/ProgressableInterface.php
@@ -0,0 +1,31 @@
<?php
 
/*
* This file is part of PHP-FFmpeg.
*
* (c) Alchemy <dev.team@alchemy.fr>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
 
namespace FFMpeg\Format;
 
use Evenement\EventEmitterInterface;
use FFMpeg\FFProbe;
use FFMpeg\Media\MediaTypeInterface;
 
interface ProgressableInterface extends EventEmitterInterface
{
/**
* Creates the progress listener.
*
* @param MediaTypeInterface $media
* @param FFProbe $ffprobe
* @param Integer $pass The current pas snumber
* @param Integer $total The total pass number
*
* @return array An array of listeners
*/
public function createProgressListener(MediaTypeInterface $media, FFProbe $ffprobe, $pass, $total);
}
/vendor/php-ffmpeg/php-ffmpeg/src/FFMpeg/Format/Video/DefaultVideo.php
@@ -0,0 +1,141 @@
<?php
 
/*
* This file is part of PHP-FFmpeg.
*
* (c) Alchemy <info@alchemy.fr>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
 
namespace FFMpeg\Format\Video;
 
use FFMpeg\FFProbe;
use FFMpeg\Exception\InvalidArgumentException;
use FFMpeg\Format\Audio\DefaultAudio;
use FFMpeg\Format\VideoInterface;
use FFMpeg\Media\MediaTypeInterface;
use FFMpeg\Format\ProgressListener\VideoProgressListener;
 
/**
* The abstract default Video format
*/
abstract class DefaultVideo extends DefaultAudio implements VideoInterface
{
/** @var string */
protected $videoCodec;
 
/** @var Integer */
protected $kiloBitrate = 1000;
 
/** @var Integer */
protected $modulus = 16;
 
/** @var Array */
protected $additionalParamaters;
 
/**
* {@inheritdoc}
*/
public function getKiloBitrate()
{
return $this->kiloBitrate;
}
 
/**
* Sets the kiloBitrate value.
*
* @param integer $kiloBitrate
* @throws InvalidArgumentException
*/
public function setKiloBitrate($kiloBitrate)
{
if ($kiloBitrate < 1) {
throw new InvalidArgumentException('Wrong kiloBitrate value');
}
 
$this->kiloBitrate = (int) $kiloBitrate;
 
return $this;
}
 
/**
* {@inheritdoc}
*/
public function getVideoCodec()
{
return $this->videoCodec;
}
 
/**
* Sets the video codec, Should be in the available ones, otherwise an
* exception is thrown.
*
* @param string $videoCodec
* @throws InvalidArgumentException
*/
public function setVideoCodec($videoCodec)
{
if ( ! in_array($videoCodec, $this->getAvailableVideoCodecs())) {
throw new InvalidArgumentException(sprintf(
'Wrong videocodec value for %s, available formats are %s'
, $videoCodec, implode(', ', $this->getAvailableVideoCodecs())
));
}
 
$this->videoCodec = $videoCodec;
 
return $this;
}
 
/**
* @return integer
*/
public function getModulus()
{
return $this->modulus;
}
 
/**
* {@inheritdoc}
*/
public function getAdditionalParameters()
{
return $this->additionalParamaters;
}
 
/**
* Sets additional parameters.
*
* @param array $additionalParamaters
* @throws InvalidArgumentException
*/
public function setAdditionalParameters($additionalParamaters)
{
if (!is_array($additionalParamaters)) {
throw new InvalidArgumentException('Wrong additionalParamaters value');
}
 
$this->additionalParamaters = $additionalParamaters;
 
return $this;
}
 
/**
* {@inheritdoc}
*/
public function createProgressListener(MediaTypeInterface $media, FFProbe $ffprobe, $pass, $total)
{
$format = $this;
$listeners = array(new VideoProgressListener($ffprobe, $media->getPathfile(), $pass, $total));
 
foreach ($listeners as $listener) {
$listener->on('progress', function () use ($format, $media) {
$format->emit('progress', array_merge(array($media, $format), func_get_args()));
});
}
 
return $listeners;
}
}
/vendor/php-ffmpeg/php-ffmpeg/src/FFMpeg/Format/Video/Ogg.php
@@ -0,0 +1,49 @@
<?php
 
/*
* This file is part of PHP-FFmpeg.
*
* (c) Alchemy <info@alchemy.fr>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
 
namespace FFMpeg\Format\Video;
 
/**
* The Ogg video format
*/
class Ogg extends DefaultVideo
{
public function __construct($audioCodec = 'libvorbis', $videoCodec = 'libtheora')
{
$this
->setAudioCodec($audioCodec)
->setVideoCodec($videoCodec);
}
 
/**
* {@inheritDoc}
*/
public function supportBFrames()
{
return true;
}
 
/**
* {@inheritDoc}
*/
public function getAvailableAudioCodecs()
{
return array('libvorbis');
}
 
/**
* {@inheritDoc}
*/
public function getAvailableVideoCodecs()
{
return array('libtheora');
}
}
/vendor/php-ffmpeg/php-ffmpeg/src/FFMpeg/Format/Video/WMV.php
@@ -0,0 +1,49 @@
<?php
 
/*
* This file is part of PHP-FFmpeg.
*
* (c) Alchemy <info@alchemy.fr>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
 
namespace FFMpeg\Format\Video;
 
/**
* The WMV video format
*/
class WMV extends DefaultVideo
{
public function __construct($audioCodec = 'wmav2', $videoCodec = 'wmv2')
{
$this
->setAudioCodec($audioCodec)
->setVideoCodec($videoCodec);
}
 
/**
* {@inheritDoc}
*/
public function supportBFrames()
{
return false;
}
 
/**
* {@inheritDoc}
*/
public function getAvailableAudioCodecs()
{
return array('wmav2');
}
 
/**
* {@inheritDoc}
*/
public function getAvailableVideoCodecs()
{
return array('wmv2');
}
}
/vendor/php-ffmpeg/php-ffmpeg/src/FFMpeg/Format/Video/WMV3.php
@@ -0,0 +1,49 @@
<?php
 
/*
* This file is part of PHP-FFmpeg.
*
* (c) Alchemy <info@alchemy.fr>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
 
namespace FFMpeg\Format\Video;
 
/**
* The WMV video format
*/
class WMV3 extends DefaultVideo
{
public function __construct($audioCodec = 'wmav3', $videoCodec = 'wmv3')
{
$this
->setAudioCodec($audioCodec)
->setVideoCodec($videoCodec);
}
 
/**
* {@inheritDoc}
*/
public function supportBFrames()
{
return false;
}
 
/**
* {@inheritDoc}
*/
public function getAvailableAudioCodecs()
{
return array('wmav3');
}
 
/**
* {@inheritDoc}
*/
public function getAvailableVideoCodecs()
{
return array('wmv3');
}
}
/vendor/php-ffmpeg/php-ffmpeg/src/FFMpeg/Format/Video/WebM.php
@@ -0,0 +1,57 @@
<?php
 
/*
* This file is part of PHP-FFmpeg.
*
* (c) Alchemy <info@alchemy.fr>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
 
namespace FFMpeg\Format\Video;
 
/**
* The WebM video format
*/
class WebM extends DefaultVideo
{
public function __construct($audioCodec = 'libvorbis', $videoCodec = 'libvpx')
{
$this
->setAudioCodec($audioCodec)
->setVideoCodec($videoCodec);
}
 
/**
* {@inheritDoc}
*/
public function supportBFrames()
{
return true;
}
 
/**
* {@inheritDoc}
*/
public function getExtraParams()
{
return array('-f', 'webm');
}
 
/**
* {@inheritDoc}
*/
public function getAvailableAudioCodecs()
{
return array('libvorbis');
}
 
/**
* {@inheritDoc}
*/
public function getAvailableVideoCodecs()
{
return array('libvpx');
}
}
/vendor/php-ffmpeg/php-ffmpeg/src/FFMpeg/Format/Video/X264.php
@@ -0,0 +1,94 @@
<?php
 
/*
* This file is part of PHP-FFmpeg.
*
* (c) Alchemy <info@alchemy.fr>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
 
namespace FFMpeg\Format\Video;
 
/**
* The X264 video format
*/
class X264 extends DefaultVideo
{
/** @var boolean */
private $bframesSupport = true;
 
/** @var integer */
private $passes = 2;
 
public function __construct($audioCodec = 'libfaac', $videoCodec = 'libx264')
{
$this
->setAudioCodec($audioCodec)
->setVideoCodec($videoCodec);
}
 
/**
* {@inheritDoc}
*/
public function supportBFrames()
{
return $this->bframesSupport;
}
 
/**
* @param $support
*
* @return X264
*/
public function setBFramesSupport($support)
{
$this->bframesSupport = $support;
 
return $this;
}
 
/**
* {@inheritDoc}
*/
public function getAvailableAudioCodecs()
{
return array('aac', 'libvo_aacenc', 'libfaac', 'libmp3lame', 'libfdk_aac');
}
 
/**
* {@inheritDoc}
*/
public function getAvailableVideoCodecs()
{
return array('libx264');
}
 
/**
* @param $passes
*
* @return X264
*/
public function setPasses($passes)
{
$this->passes = $passes;
return $this;
}
 
/**
* {@inheritDoc}
*/
public function getPasses()
{
return $this->passes;
}
 
/**
* @return int
*/
public function getModulus()
{
return 2;
}
}
/vendor/php-ffmpeg/php-ffmpeg/src/FFMpeg/Format/VideoInterface.php
@@ -0,0 +1,64 @@
<?php
 
/*
* This file is part of PHP-FFmpeg.
*
* (c) Alchemy <info@alchemy.fr>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
 
namespace FFMpeg\Format;
 
interface VideoInterface extends AudioInterface
{
/**
* Gets the kiloBitrate value.
*
* @return integer
*/
public function getKiloBitrate();
 
/**
* Returns the modulus used by the Resizable video.
*
* This used to calculate the target dimensions while maintaining the best
* aspect ratio.
*
* @see http://www.undeadborn.net/tools/rescalculator.php
*
* @return integer
*/
public function getModulus();
 
/**
* Returns the video codec.
*
* @return string
*/
public function getVideoCodec();
 
/**
* Returns true if the current format supports B-Frames.
*
* @see https://wikipedia.org/wiki/Video_compression_picture_types
*
* @return Boolean
*/
public function supportBFrames();
 
/**
* Returns the list of available video codecs for this format.
*
* @return array
*/
public function getAvailableVideoCodecs();
 
/**
* Returns the list of available video codecs for this format.
*
* @return array
*/
public function getAdditionalParameters();
}
/vendor/php-ffmpeg/php-ffmpeg/src/FFMpeg/Media/AbstractMediaType.php
@@ -0,0 +1,113 @@
<?php
 
/*
* This file is part of PHP-FFmpeg.
*
* (c) Alchemy <dev.team@alchemy.fr>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
 
namespace FFMpeg\Media;
 
use FFMpeg\Driver\FFMpegDriver;
use FFMpeg\FFProbe;
use FFMpeg\Filters\FiltersCollection;
 
abstract class AbstractMediaType implements MediaTypeInterface
{
/** @var string */
protected $pathfile;
/** @var FFMpegDriver */
protected $driver;
/** @var FFProbe */
protected $ffprobe;
/** @var FiltersCollection */
protected $filters;
 
public function __construct($pathfile, FFMpegDriver $driver, FFProbe $ffprobe)
{
$this->pathfile = $pathfile;
$this->driver = $driver;
$this->ffprobe = $ffprobe;
$this->filters = new FiltersCollection();
}
 
/**
* @return FFMpegDriver
*/
public function getFFMpegDriver()
{
return $this->driver;
}
 
/**
* @param FFMpegDriver $driver
*
* @return MediaTypeInterface
*/
public function setFFMpegDriver(FFMpegDriver $driver)
{
$this->driver = $driver;
 
return $this;
}
 
/**
* @return FFProbe
*/
public function getFFProbe()
{
return $this->ffprobe;
}
 
/**
* @param FFProbe $ffprobe
*
* @return MediaTypeInterface
*/
public function setFFProbe(FFProbe $ffprobe)
{
$this->ffprobe = $ffprobe;
 
return $this;
}
 
/**
* @return string
*/
public function getPathfile()
{
return $this->pathfile;
}
 
/**
* @param FiltersCollection $filters
*
* @return MediaTypeInterface
*/
public function setFiltersCollection(FiltersCollection $filters)
{
$this->filters = $filters;
 
return $this;
}
 
/**
* @return MediaTypeInterface
*/
public function getFiltersCollection()
{
return $this->filters;
}
 
protected function cleanupTemporaryFile($filename)
{
if (file_exists($filename) && is_writable($filename)) {
unlink($filename);
}
 
return $this;
}
}
/vendor/php-ffmpeg/php-ffmpeg/src/FFMpeg/Media/AbstractStreamableMedia.php
@@ -0,0 +1,40 @@
<?php
 
/*
* This file is part of PHP-FFmpeg.
*
* (c) Alchemy <info@alchemy.fr>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
 
namespace FFMpeg\Media;
 
use FFMpeg\FFProbe\DataMapping\Format;
use FFMpeg\FFProbe\DataMapping\StreamCollection;
 
abstract class AbstractStreamableMedia extends AbstractMediaType
{
private $streams;
 
/**
* @return StreamCollection
*/
public function getStreams()
{
if (null === $this->streams) {
$this->streams = $this->ffprobe->streams($this->pathfile);
}
 
return $this->streams;
}
 
/**
* @return Format
*/
public function getFormat()
{
return $this->ffprobe->format($this->pathfile);
}
}
/vendor/php-ffmpeg/php-ffmpeg/src/FFMpeg/Media/Audio.php
@@ -0,0 +1,117 @@
<?php
 
/*
* This file is part of PHP-FFmpeg.
*
* (c) Alchemy <info@alchemy.fr>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
 
namespace FFMpeg\Media;
 
use Alchemy\BinaryDriver\Exception\ExecutionFailureException;
use FFMpeg\Filters\Audio\AudioFilters;
use FFMpeg\Format\FormatInterface;
use FFMpeg\Filters\Audio\SimpleFilter;
use FFMpeg\Exception\RuntimeException;
use FFMpeg\Exception\InvalidArgumentException;
use FFMpeg\Filters\Audio\AudioFilterInterface;
use FFMpeg\Filters\FilterInterface;
use FFMpeg\Format\ProgressableInterface;
 
class Audio extends AbstractStreamableMedia
{
/**
* {@inheritdoc}
*
* @return AudioFilters
*/
public function filters()
{
return new AudioFilters($this);
}
 
/**
* {@inheritdoc}
*
* @return Audio
*/
public function addFilter(FilterInterface $filter)
{
if (!$filter instanceof AudioFilterInterface) {
throw new InvalidArgumentException('Audio only accepts AudioFilterInterface filters');
}
 
$this->filters->add($filter);
 
return $this;
}
 
/**
* Exports the audio in the desired format, applies registered filters.
*
* @param FormatInterface $format
* @param string $outputPathfile
*
* @return Audio
*
* @throws RuntimeException
*/
public function save(FormatInterface $format, $outputPathfile)
{
$listeners = null;
 
if ($format instanceof ProgressableInterface) {
$listeners = $format->createProgressListener($this, $this->ffprobe, 1, 1);
}
 
$commands = array('-y', '-i', $this->pathfile);
 
$filters = clone $this->filters;
$filters->add(new SimpleFilter($format->getExtraParams(), 10));
 
if ($this->driver->getConfiguration()->has('ffmpeg.threads')) {
$filters->add(new SimpleFilter(array('-threads', $this->driver->getConfiguration()->get('ffmpeg.threads'))));
}
if (null !== $format->getAudioCodec()) {
$filters->add(new SimpleFilter(array('-acodec', $format->getAudioCodec())));
}
 
foreach ($filters as $filter) {
$commands = array_merge($commands, $filter->apply($this, $format));
}
 
if (null !== $format->getAudioKiloBitrate()) {
$commands[] = '-b:a';
$commands[] = $format->getAudioKiloBitrate() . 'k';
}
if (null !== $format->getAudioChannels()) {
$commands[] = '-ac';
$commands[] = $format->getAudioChannels();
}
$commands[] = $outputPathfile;
 
try {
$this->driver->command($commands, false, $listeners);
} catch (ExecutionFailureException $e) {
$this->cleanupTemporaryFile($outputPathfile);
throw new RuntimeException('Encoding failed', $e->getCode(), $e);
}
 
return $this;
}
 
/**
* Gets the waveform of the video.
*
* @param integer $width
* @param integer $height
* @return Waveform
*/
public function waveform($width = 640, $height = 120)
{
return new Waveform($this, $this->driver, $this->ffprobe, $width, $height);
}
}
/vendor/php-ffmpeg/php-ffmpeg/src/FFMpeg/Media/Concat.php
@@ -0,0 +1,264 @@
<?php
 
/*
* This file is part of PHP-FFmpeg.
*
* (c) Strime <contact@strime.io>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
 
namespace FFMpeg\Media;
 
use Alchemy\BinaryDriver\Exception\ExecutionFailureException;
use Alchemy\BinaryDriver\Exception\InvalidArgumentException;
use FFMpeg\Filters\Concat\ConcatFilterInterface;
use FFMpeg\Filters\Concat\ConcatFilters;
use FFMpeg\Driver\FFMpegDriver;
use FFMpeg\FFProbe;
use FFMpeg\Filters\Audio\SimpleFilter;
use FFMpeg\Exception\RuntimeException;
use FFMpeg\Format\FormatInterface;
use FFMpeg\Filters\FilterInterface;
use FFMpeg\Format\ProgressableInterface;
use FFMpeg\Format\AudioInterface;
use FFMpeg\Format\VideoInterface;
use Neutron\TemporaryFilesystem\Manager as FsManager;
 
class Concat extends AbstractMediaType
{
/** @var array */
private $sources;
 
public function __construct($sources, FFMpegDriver $driver, FFProbe $ffprobe)
{
parent::__construct($sources, $driver, $ffprobe);
$this->sources = $sources;
}
 
/**
* Returns the path to the sources.
*
* @return string
*/
public function getSources()
{
return $this->sources;
}
 
/**
* {@inheritdoc}
*
* @return ConcatFilters
*/
public function filters()
{
return new ConcatFilters($this);
}
 
/**
* {@inheritdoc}
*
* @return Concat
*/
public function addFilter(ConcatFilterInterface $filter)
{
$this->filters->add($filter);
 
return $this;
}
 
/**
* Saves the concatenated video in the given array, considering that the sources videos are all encoded with the same codec.
*
* @param array $outputPathfile
* @param string $streamCopy
*
* @return Concat
*
* @throws RuntimeException
*/
public function saveFromSameCodecs($outputPathfile, $streamCopy = TRUE)
{
/**
* @see https://ffmpeg.org/ffmpeg-formats.html#concat
* @see https://trac.ffmpeg.org/wiki/Concatenate
*/
 
// Create the file which will contain the list of videos
$fs = FsManager::create();
$sourcesFile = $fs->createTemporaryFile('ffmpeg-concat');
 
// Set the content of this file
$fileStream = @fopen($sourcesFile, 'w');
 
if($fileStream === false) {
throw new ExecutionFailureException('Cannot open the temporary file.');
}
 
$count_videos = 0;
if(is_array($this->sources) && (count($this->sources) > 0)) {
foreach ($this->sources as $videoPath) {
$line = "";
 
if($count_videos != 0)
$line .= "\n";
 
$line .= "file ".$videoPath;
 
fwrite($fileStream, $line);
 
$count_videos++;
}
}
else {
throw new InvalidArgumentException('The list of videos is not a valid array.');
}
fclose($fileStream);
 
 
$commands = array(
'-f', 'concat', '-safe', '0',
'-i', $sourcesFile
);
 
// Check if stream copy is activated
if($streamCopy === TRUE) {
$commands[] = '-c';
$commands[] = 'copy';
}
 
// If not, we can apply filters
else {
foreach ($this->filters as $filter) {
$commands = array_merge($commands, $filter->apply($this));
}
}
 
// Set the output file in the command
$commands = array_merge($commands, array($outputPathfile));
 
// Execute the command
try {
$this->driver->command($commands);
} catch (ExecutionFailureException $e) {
$this->cleanupTemporaryFile($outputPathfile);
$this->cleanupTemporaryFile($sourcesFile);
throw new RuntimeException('Unable to save concatenated video', $e->getCode(), $e);
}
 
$this->cleanupTemporaryFile($sourcesFile);
return $this;
}
 
/**
* Saves the concatenated video in the given filename, considering that the sources videos are all encoded with the same codec.
*
* @param string $outputPathfile
*
* @return Concat
*
* @throws RuntimeException
*/
public function saveFromDifferentCodecs(FormatInterface $format, $outputPathfile)
{
/**
* @see https://ffmpeg.org/ffmpeg-formats.html#concat
* @see https://trac.ffmpeg.org/wiki/Concatenate
*/
 
// Check the validity of the parameter
if(!is_array($this->sources) || (count($this->sources) == 0)) {
throw new InvalidArgumentException('The list of videos is not a valid array.');
}
 
// Create the commands variable
$commands = array();
 
// Prepare the parameters
$nbSources = 0;
$files = array();
 
// For each source, check if this is a legit file
// and prepare the parameters
foreach ($this->sources as $videoPath) {
$files[] = '-i';
$files[] = $videoPath;
$nbSources++;
}
 
$commands = array_merge($commands, $files);
 
// Set the parameters of the request
$commands[] = '-filter_complex';
 
$complex_filter = '';
for($i=0; $i<$nbSources; $i++) {
$complex_filter .= '['.$i.':v:0] ['.$i.':a:0] ';
}
$complex_filter .= 'concat=n='.$nbSources.':v=1:a=1 [v] [a]';
 
$commands[] = $complex_filter;
$commands[] = '-map';
$commands[] = '[v]';
$commands[] = '-map';
$commands[] = '[a]';
 
// Prepare the filters
$filters = clone $this->filters;
$filters->add(new SimpleFilter($format->getExtraParams(), 10));
 
if ($this->driver->getConfiguration()->has('ffmpeg.threads')) {
$filters->add(new SimpleFilter(array('-threads', $this->driver->getConfiguration()->get('ffmpeg.threads'))));
}
if ($format instanceof VideoInterface) {
if (null !== $format->getVideoCodec()) {
$filters->add(new SimpleFilter(array('-vcodec', $format->getVideoCodec())));
}
}
if ($format instanceof AudioInterface) {
if (null !== $format->getAudioCodec()) {
$filters->add(new SimpleFilter(array('-acodec', $format->getAudioCodec())));
}
}
 
// Add the filters
foreach ($this->filters as $filter) {
$commands = array_merge($commands, $filter->apply($this));
}
 
if ($format instanceof AudioInterface) {
if (null !== $format->getAudioKiloBitrate()) {
$commands[] = '-b:a';
$commands[] = $format->getAudioKiloBitrate() . 'k';
}
if (null !== $format->getAudioChannels()) {
$commands[] = '-ac';
$commands[] = $format->getAudioChannels();
}
}
 
// If the user passed some additional parameters
if ($format instanceof VideoInterface) {
if (null !== $format->getAdditionalParameters()) {
foreach ($format->getAdditionalParameters() as $additionalParameter) {
$commands[] = $additionalParameter;
}
}
}
 
// Set the output file in the command
$commands[] = $outputPathfile;
 
$failure = null;
 
try {
$this->driver->command($commands);
} catch (ExecutionFailureException $e) {
throw new RuntimeException('Encoding failed', $e->getCode(), $e);
}
 
return $this;
}
}
/vendor/php-ffmpeg/php-ffmpeg/src/FFMpeg/Media/Frame.php
@@ -0,0 +1,133 @@
<?php
 
/*
* This file is part of PHP-FFmpeg.
*
* (c) Alchemy <info@alchemy.fr>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
 
namespace FFMpeg\Media;
 
use Alchemy\BinaryDriver\Exception\ExecutionFailureException;
use FFMpeg\Filters\Frame\FrameFilterInterface;
use FFMpeg\Filters\Frame\FrameFilters;
use FFMpeg\Driver\FFMpegDriver;
use FFMpeg\FFProbe;
use FFMpeg\Exception\RuntimeException;
use FFMpeg\Coordinate\TimeCode;
 
class Frame extends AbstractMediaType
{
/** @var TimeCode */
private $timecode;
/** @var Video */
private $video;
 
public function __construct(Video $video, FFMpegDriver $driver, FFProbe $ffprobe, TimeCode $timecode)
{
parent::__construct($video->getPathfile(), $driver, $ffprobe);
$this->timecode = $timecode;
$this->video = $video;
}
 
/**
* Returns the video related to the frame.
*
* @return Video
*/
public function getVideo()
{
return $this->video;
}
 
/**
* {@inheritdoc}
*
* @return FrameFilters
*/
public function filters()
{
return new FrameFilters($this);
}
 
/**
* {@inheritdoc}
*
* @return Frame
*/
public function addFilter(FrameFilterInterface $filter)
{
$this->filters->add($filter);
 
return $this;
}
 
/**
* @return TimeCode
*/
public function getTimeCode()
{
return $this->timecode;
}
 
/**
* Saves the frame in the given filename.
*
* Uses the `unaccurate method by default.`
*
* @param string $pathfile
* @param Boolean $accurate
*
* @return Frame
*
* @throws RuntimeException
*/
public function save($pathfile, $accurate = false, $returnBase64 = false)
{
/**
* might be optimized with http://ffmpeg.org/trac/ffmpeg/wiki/Seeking%20with%20FFmpeg
* @see http://ffmpeg.org/ffmpeg.html#Main-options
*/
$outputFormat = $returnBase64 ? "image2pipe" : "image2";
if (!$accurate) {
$commands = array(
'-y', '-ss', (string) $this->timecode,
'-i', $this->pathfile,
'-vframes', '1',
'-f', $outputFormat
);
} else {
$commands = array(
'-y', '-i', $this->pathfile,
'-vframes', '1', '-ss', (string) $this->timecode,
'-f', $outputFormat
);
}
if($returnBase64) {
array_push($commands, "-");
}
 
foreach ($this->filters as $filter) {
$commands = array_merge($commands, $filter->apply($this));
}
 
$commands = array_merge($commands, array($pathfile));
 
try {
if(!$returnBase64) {
$this->driver->command($commands);
return $this;
}
else {
return $this->driver->command($commands);
}
} catch (ExecutionFailureException $e) {
$this->cleanupTemporaryFile($pathfile);
throw new RuntimeException('Unable to save frame', $e->getCode(), $e);
}
}
}
/vendor/php-ffmpeg/php-ffmpeg/src/FFMpeg/Media/Gif.php
@@ -0,0 +1,137 @@
<?php
 
/*
* This file is part of PHP-FFmpeg.
*
* (c) Strime <contact@strime.io>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
 
namespace FFMpeg\Media;
 
use Alchemy\BinaryDriver\Exception\ExecutionFailureException;
use FFMpeg\Filters\Gif\GifFilterInterface;
use FFMpeg\Filters\Gif\GifFilters;
use FFMpeg\Driver\FFMpegDriver;
use FFMpeg\FFProbe;
use FFMpeg\Exception\RuntimeException;
use FFMpeg\Coordinate\TimeCode;
use FFMpeg\Coordinate\Dimension;
 
class Gif extends AbstractMediaType
{
/** @var TimeCode */
private $timecode;
/** @var Dimension */
private $dimension;
/** @var integer */
private $duration;
/** @var Video */
private $video;
 
public function __construct(Video $video, FFMpegDriver $driver, FFProbe $ffprobe, TimeCode $timecode, Dimension $dimension, $duration = null)
{
parent::__construct($video->getPathfile(), $driver, $ffprobe);
$this->timecode = $timecode;
$this->dimension = $dimension;
$this->duration = $duration;
$this->video = $video;
}
 
/**
* Returns the video related to the gif.
*
* @return Video
*/
public function getVideo()
{
return $this->video;
}
 
/**
* {@inheritdoc}
*
* @return GifFilters
*/
public function filters()
{
return new GifFilters($this);
}
 
/**
* {@inheritdoc}
*
* @return Gif
*/
public function addFilter(GifFilterInterface $filter)
{
$this->filters->add($filter);
 
return $this;
}
 
/**
* @return TimeCode
*/
public function getTimeCode()
{
return $this->timecode;
}
 
/**
* @return Dimension
*/
public function getDimension()
{
return $this->dimension;
}
 
/**
* Saves the gif in the given filename.
*
* @param string $pathfile
*
* @return Gif
*
* @throws RuntimeException
*/
public function save($pathfile)
{
/**
* @see http://ffmpeg.org/ffmpeg.html#Main-options
*/
$commands = array(
'-ss', (string)$this->timecode
);
 
if(null !== $this->duration) {
$commands[] = '-t';
$commands[] = (string)$this->duration;
}
 
$commands[] = '-i';
$commands[] = $this->pathfile;
$commands[] = '-vf';
$commands[] = 'scale=' . $this->dimension->getWidth() . ':-1';
$commands[] = '-gifflags';
$commands[] = '+transdiff';
$commands[] = '-y';
 
foreach ($this->filters as $filter) {
$commands = array_merge($commands, $filter->apply($this));
}
 
$commands = array_merge($commands, array($pathfile));
 
try {
$this->driver->command($commands);
} catch (ExecutionFailureException $e) {
$this->cleanupTemporaryFile($pathfile);
throw new RuntimeException('Unable to save gif', $e->getCode(), $e);
}
 
return $this;
}
}
/vendor/php-ffmpeg/php-ffmpeg/src/FFMpeg/Media/MediaTypeInterface.php
@@ -0,0 +1,25 @@
<?php
 
/*
* This file is part of PHP-FFmpeg.
*
* (c) Alchemy <info@alchemy.fr>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
 
namespace FFMpeg\Media;
 
interface MediaTypeInterface
{
/**
* Returns the available filters.
*/
public function filters();
 
/**
* @return string
*/
public function getPathfile();
}
/vendor/php-ffmpeg/php-ffmpeg/src/FFMpeg/Media/Video.php
@@ -0,0 +1,268 @@
<?php
 
/*
* This file is part of PHP-FFmpeg.
*
* (c) Alchemy <info@alchemy.fr>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
 
namespace FFMpeg\Media;
 
use Alchemy\BinaryDriver\Exception\ExecutionFailureException;
use FFMpeg\Coordinate\TimeCode;
use FFMpeg\Coordinate\Dimension;
use FFMpeg\Filters\Audio\SimpleFilter;
use FFMpeg\Exception\InvalidArgumentException;
use FFMpeg\Exception\RuntimeException;
use FFMpeg\Filters\Video\VideoFilters;
use FFMpeg\Filters\FilterInterface;
use FFMpeg\Format\FormatInterface;
use FFMpeg\Format\ProgressableInterface;
use FFMpeg\Format\AudioInterface;
use FFMpeg\Format\VideoInterface;
use Neutron\TemporaryFilesystem\Manager as FsManager;
 
class Video extends Audio
{
/**
* {@inheritdoc}
*
* @return VideoFilters
*/
public function filters()
{
return new VideoFilters($this);
}
 
/**
* {@inheritdoc}
*
* @return Video
*/
public function addFilter(FilterInterface $filter)
{
$this->filters->add($filter);
 
return $this;
}
 
/**
* Exports the video in the desired format, applies registered filters.
*
* @param FormatInterface $format
* @param string $outputPathfile
*
* @return Video
*
* @throws RuntimeException
*/
public function save(FormatInterface $format, $outputPathfile)
{
$commands = array('-y', '-i', $this->pathfile);
 
$filters = clone $this->filters;
$filters->add(new SimpleFilter($format->getExtraParams(), 10));
 
if ($this->driver->getConfiguration()->has('ffmpeg.threads')) {
$filters->add(new SimpleFilter(array('-threads', $this->driver->getConfiguration()->get('ffmpeg.threads'))));
}
if ($format instanceof VideoInterface) {
if (null !== $format->getVideoCodec()) {
$filters->add(new SimpleFilter(array('-vcodec', $format->getVideoCodec())));
}
}
if ($format instanceof AudioInterface) {
if (null !== $format->getAudioCodec()) {
$filters->add(new SimpleFilter(array('-acodec', $format->getAudioCodec())));
}
}
 
foreach ($filters as $filter) {
$commands = array_merge($commands, $filter->apply($this, $format));
}
 
if ($format instanceof VideoInterface) {
$commands[] = '-b:v';
$commands[] = $format->getKiloBitrate() . 'k';
$commands[] = '-refs';
$commands[] = '6';
$commands[] = '-coder';
$commands[] = '1';
$commands[] = '-sc_threshold';
$commands[] = '40';
$commands[] = '-flags';
$commands[] = '+loop';
$commands[] = '-me_range';
$commands[] = '16';
$commands[] = '-subq';
$commands[] = '7';
$commands[] = '-i_qfactor';
$commands[] = '0.71';
$commands[] = '-qcomp';
$commands[] = '0.6';
$commands[] = '-qdiff';
$commands[] = '4';
$commands[] = '-trellis';
$commands[] = '1';
}
 
if ($format instanceof AudioInterface) {
if (null !== $format->getAudioKiloBitrate()) {
$commands[] = '-b:a';
$commands[] = $format->getAudioKiloBitrate() . 'k';
}
if (null !== $format->getAudioChannels()) {
$commands[] = '-ac';
$commands[] = $format->getAudioChannels();
}
}
 
// If the user passed some additional parameters
if ($format instanceof VideoInterface) {
if (null !== $format->getAdditionalParameters()) {
foreach ($format->getAdditionalParameters() as $additionalParameter) {
$commands[] = $additionalParameter;
}
}
}
 
// Merge Filters into one command
$videoFilterVars = $videoFilterProcesses = [];
for($i=0;$i<count($commands);$i++) {
$command = $commands[$i];
if ( $command == '-vf' ) {
$commandSplits = explode(";", $commands[$i + 1]);
if ( count($commandSplits) == 1 ) {
$commandSplit = $commandSplits[0];
$command = trim($commandSplit);
if ( preg_match("/^\[in\](.*?)\[out\]$/is", $command, $match) ) {
$videoFilterProcesses[] = $match[1];
} else {
$videoFilterProcesses[] = $command;
}
} else {
foreach($commandSplits as $commandSplit) {
$command = trim($commandSplit);
if ( preg_match("/^\[[^\]]+\](.*?)\[[^\]]+\]$/is", $command, $match) ) {
$videoFilterProcesses[] = $match[1];
} else {
$videoFilterVars[] = $command;
}
}
}
unset($commands[$i]);
unset($commands[$i + 1]);
$i++;
}
}
$videoFilterCommands = $videoFilterVars;
$lastInput = 'in';
foreach($videoFilterProcesses as $i => $process) {
$command = '[' . $lastInput .']';
$command .= $process;
$lastInput = 'p' . $i;
if ( $i == count($videoFilterProcesses) - 1 ) {
$command .= '[out]';
} else {
$command .= '[' . $lastInput . ']';
}
$videoFilterCommands[] = $command;
}
$videoFilterCommand = implode(";", $videoFilterCommands);
if ( $videoFilterCommand ) {
$commands[] = '-vf';
$commands[] = $videoFilterCommand;
}
$fs = FsManager::create();
$fsId = uniqid('ffmpeg-passes');
$passPrefix = $fs->createTemporaryDirectory(0777, 50, $fsId) . '/' . uniqid('pass-');
$passes = array();
$totalPasses = $format->getPasses();
 
if (1 > $totalPasses) {
throw new InvalidArgumentException('Pass number should be a positive value.');
}
 
for ($i = 1; $i <= $totalPasses; $i++) {
$pass = $commands;
 
if ($totalPasses > 1) {
$pass[] = '-pass';
$pass[] = $i;
$pass[] = '-passlogfile';
$pass[] = $passPrefix;
}
 
$pass[] = $outputPathfile;
 
$passes[] = $pass;
}
 
$failure = null;
 
foreach ($passes as $pass => $passCommands) {
try {
/** add listeners here */
$listeners = null;
 
if ($format instanceof ProgressableInterface) {
$listeners = $format->createProgressListener($this, $this->ffprobe, $pass + 1, $totalPasses);
}
 
$this->driver->command($passCommands, false, $listeners);
} catch (ExecutionFailureException $e) {
$failure = $e;
break;
}
}
 
$fs->clean($fsId);
 
if (null !== $failure) {
throw new RuntimeException('Encoding failed', $failure->getCode(), $failure);
}
 
return $this;
}
 
/**
* Gets the frame at timecode.
*
* @param TimeCode $at
* @return Frame
*/
public function frame(TimeCode $at)
{
return new Frame($this, $this->driver, $this->ffprobe, $at);
}
 
/**
* Extracts a gif from a sequence of the video.
*
* @param TimeCode $at
* @param Dimension $dimension
* @param integer $duration
* @return Gif
*/
public function gif(TimeCode $at, Dimension $dimension, $duration = null)
{
return new Gif($this, $this->driver, $this->ffprobe, $at, $dimension, $duration);
}
 
/**
* Concatenates a list of videos into one unique video.
*
* @param array $sources
* @return Concat
*/
public function concat($sources)
{
return new Concat($sources, $this->driver, $this->ffprobe);
}
}
/vendor/php-ffmpeg/php-ffmpeg/src/FFMpeg/Media/Waveform.php
@@ -0,0 +1,104 @@
<?php
 
/*
* This file is part of PHP-FFmpeg.
*
* (c) Alchemy <info@alchemy.fr>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
 
namespace FFMpeg\Media;
 
use Alchemy\BinaryDriver\Exception\ExecutionFailureException;
use FFMpeg\Filters\Waveform\WaveformFilterInterface;
use FFMpeg\Filters\Waveform\WaveformFilters;
use FFMpeg\Driver\FFMpegDriver;
use FFMpeg\FFProbe;
use FFMpeg\Exception\RuntimeException;
 
class Waveform extends AbstractMediaType
{
/** @var Video */
private $audio;
private $width;
private $height;
 
public function __construct(Audio $audio, FFMpegDriver $driver, FFProbe $ffprobe, $width, $height)
{
parent::__construct($audio->getPathfile(), $driver, $ffprobe);
$this->audio = $audio;
$this->width = $width;
$this->height = $height;
}
 
/**
* Returns the audio related to the waveform.
*
* @return Audio
*/
public function getAudio()
{
return $this->audio;
}
 
/**
* {@inheritdoc}
*
* @return WaveformFilters
*/
public function filters()
{
return new WaveformFilters($this);
}
 
/**
* {@inheritdoc}
*
* @return Waveform
*/
public function addFilter(WaveformFilterInterface $filter)
{
$this->filters->add($filter);
 
return $this;
}
 
/**
* Saves the waveform in the given filename.
*
* @param string $pathfile
*
* @return Waveform
*
* @throws RuntimeException
*/
public function save($pathfile)
{
/**
* might be optimized with http://ffmpeg.org/trac/ffmpeg/wiki/Seeking%20with%20FFmpeg
* @see http://ffmpeg.org/ffmpeg.html#Main-options
*/
$commands = array(
'-i', $this->pathfile, '-filter_complex',
'showwavespic=s='.$this->width.'x'.$this->height,
'-frames:v', '1'
);
 
foreach ($this->filters as $filter) {
$commands = array_merge($commands, $filter->apply($this));
}
 
$commands = array_merge($commands, array($pathfile));
 
try {
$this->driver->command($commands);
} catch (ExecutionFailureException $e) {
$this->cleanupTemporaryFile($pathfile);
throw new RuntimeException('Unable to save waveform', $e->getCode(), $e);
}
 
return $this;
}
}