[BC] Upgraded dependencies, dropped support for anything below PHP 8.0. (#849)

* GitHub actions + style fixes + updated packages

* Fixed workflows dir

* Support for PHP 8.1 (#1)

* Update README.md

* Revert some changes from upstream
This commit is contained in:
Pascal Baljet 2022-02-09 14:32:43 +01:00 committed by GitHub
commit 111c153428
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
335 changed files with 4394 additions and 28116 deletions

View file

@ -0,0 +1,218 @@
<?php
/*
* This file is part of Alchemy\BinaryDriver.
*
* (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 Alchemy\BinaryDriver;
use Alchemy\BinaryDriver\Exception\ExecutableNotFoundException;
use Alchemy\BinaryDriver\Exception\ExecutionFailureException;
use Alchemy\BinaryDriver\Listeners\Listeners;
use Alchemy\BinaryDriver\Listeners\ListenerInterface;
use Evenement\EventEmitter;
use Psr\Log\LoggerInterface;
use Psr\Log\NullLogger;
use Symfony\Component\Process\ExecutableFinder;
use Symfony\Component\Process\Process;
abstract class AbstractBinary extends EventEmitter implements BinaryInterface
{
/** @var ConfigurationInterface */
protected $configuration;
/** @var ProcessBuilderFactoryInterface */
protected $factory;
/** @var ProcessRunner */
private $processRunner;
/** @var Listeners */
private $listenersManager;
public function __construct(ProcessBuilderFactoryInterface $factory, LoggerInterface $logger, ConfigurationInterface $configuration)
{
$this->factory = $factory;
$this->configuration = $configuration;
$this->processRunner = new ProcessRunner($logger, $this->getName());
$this->listenersManager = new Listeners();
$this->applyProcessConfiguration();
}
/**
* {@inheritdoc}
*/
public function listen(ListenerInterface $listener)
{
$this->listenersManager->register($listener, $this);
return $this;
}
/**
* {@inheritdoc}
*/
public function unlisten(ListenerInterface $listener)
{
$this->listenersManager->unregister($listener, $this);
return $this;
}
/**
* {@inheritdoc}
*/
public function getConfiguration()
{
return $this->configuration;
}
/**
* {@inheritdoc}
*
* @return BinaryInterface
*/
public function setConfiguration(ConfigurationInterface $configuration)
{
$this->configuration = $configuration;
$this->applyProcessConfiguration();
return $this;
}
/**
* {@inheritdoc}
*/
public function getProcessBuilderFactory()
{
return $this->factory;
}
/**
* {@inheritdoc}
*
* @return BinaryInterface
*/
public function setProcessBuilderFactory(ProcessBuilderFactoryInterface $factory)
{
$this->factory = $factory;
$this->applyProcessConfiguration();
return $this;
}
/**
* {@inheritdoc}
*/
public function getProcessRunner()
{
return $this->processRunner;
}
/**
* {@inheritdoc}
*/
public function setProcessRunner(ProcessRunnerInterface $runner)
{
$this->processRunner = $runner;
return $this;
}
/**
* {@inheritdoc}
*/
public function command($command, $bypassErrors = false, $listeners = null)
{
if (!is_array($command)) {
$command = array($command);
}
return $this->run($this->factory->create($command), $bypassErrors, $listeners);
}
/**
* {@inheritdoc}
*/
public static function load($binaries, LoggerInterface $logger = null, $configuration = array())
{
$finder = new ExecutableFinder();
$binary = null;
$binaries = is_array($binaries) ? $binaries : array($binaries);
foreach ($binaries as $candidate) {
if (file_exists($candidate) && is_executable($candidate)) {
$binary = $candidate;
break;
}
if (null !== $binary = $finder->find($candidate)) {
break;
}
}
if (null === $binary) {
throw new ExecutableNotFoundException(sprintf(
'Executable not found, proposed : %s', implode(', ', $binaries)
));
}
if (null === $logger) {
$logger = new NullLogger();
}
$configuration = $configuration instanceof ConfigurationInterface ? $configuration : new Configuration($configuration);
return new static(new ProcessBuilderFactory($binary), $logger, $configuration);
}
/**
* Returns the name of the driver
*
* @return string
*/
abstract public function getName();
/**
* Executes a process, logs events
*
* @param Process $process
* @param Boolean $bypassErrors Set to true to disable throwing ExecutionFailureExceptions
* @param ListenerInterface|array $listeners A listener or an array of listener to register for this unique run
*
* @return string The Process output
*
* @throws ExecutionFailureException in case of process failure.
*/
protected function run(Process $process, $bypassErrors = false, $listeners = null)
{
if (null !== $listeners) {
if (!is_array($listeners)) {
$listeners = array($listeners);
}
$listenersManager = clone $this->listenersManager;
foreach ($listeners as $listener) {
$listenersManager->register($listener, $this);
}
} else {
$listenersManager = $this->listenersManager;
}
return $this->processRunner->run($process, $listenersManager->storage, $bypassErrors);
}
private function applyProcessConfiguration()
{
if ($this->configuration->has('timeout')) {
$this->factory->setTimeout($this->configuration->get('timeout'));
}
return $this;
}
}

View file

@ -0,0 +1,77 @@
<?php
namespace Alchemy\BinaryDriver;
use PHPUnit\Framework\TestCase;
use Psr\Log\LoggerInterface;
use Symfony\Component\Process\Process;
/**
* Convenient PHPUnit methods for testing BinaryDriverInterface implementations.
*/
class BinaryDriverTestCase extends TestCase
{
/**
* @return ProcessBuilderFactoryInterface
*/
public function createProcessBuilderFactoryMock()
{
return $this->getMockBuilder('Alchemy\BinaryDriver\ProcessBuilderFactoryInterface')->getMock();
}
/**
* @param integer $runs The number of runs expected
* @param Boolean $success True if the process expects to be successfull
* @param string $commandLine The commandline executed
* @param string $output The process output
* @param string $error The process error output
*
* @return Process
*/
public function createProcessMock($runs = 1, $success = true, $commandLine = null, $output = null, $error = null, $callback = false)
{
$process = $this->getMockBuilder('Symfony\Component\Process\Process')
->disableOriginalConstructor()
->getMock();
$builder = $process->expects($this->exactly($runs))
->method('run');
if (true === $callback) {
$builder->with($this->isInstanceOf('Closure'));
}
$process->expects($this->any())
->method('isSuccessful')
->will($this->returnValue($success));
foreach ([
'getOutput' => $output,
'getErrorOutput' => $error ?: "",
'getCommandLine' => $commandLine,
] as $command => $value) {
$process
->expects($this->any())
->method($command)
->will($this->returnValue($value));
}
return $process;
}
/**
* @return LoggerInterface
*/
public function createLoggerMock()
{
return $this->getMockBuilder('Psr\Log\LoggerInterface')->getMock();
}
/**
* @return ConfigurationInterface
*/
public function createConfigurationMock()
{
return $this->getMockBuilder('Alchemy\BinaryDriver\ConfigurationInterface')->getMock();
}
}

View file

@ -0,0 +1,67 @@
<?php
/*
* This file is part of Alchemy\BinaryDriver.
*
* (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 Alchemy\BinaryDriver;
use Alchemy\BinaryDriver\Exception\ExecutableNotFoundException;
use Alchemy\BinaryDriver\Exception\ExecutionFailureException;
use Alchemy\BinaryDriver\Listeners\ListenerInterface;
use Psr\Log\LoggerInterface;
use Evenement\EventEmitterInterface;
interface BinaryInterface extends ConfigurationAwareInterface, ProcessBuilderFactoryAwareInterface, ProcessRunnerAwareInterface, EventEmitterInterface
{
/**
* Adds a listener to the binary driver
*
* @param ListenerInterface $listener
*
* @return BinaryInterface
*/
public function listen(ListenerInterface $listener);
/**
* Removes a listener from the binary driver
*
* @param ListenerInterface $listener
*
* @return BinaryInterface
*/
public function unlisten(ListenerInterface $listener);
/**
* Runs a command against the driver.
*
* Calling this method on a `ls` driver with the command `-a` would run `ls -a`.
*
* @param array|string $command A command or an array of command
* @param Boolean $bypassErrors If set to true, an erronous process will not throw an exception
* @param ListenerInterface|array $listeners A listener or an array of listeners to register for this unique run
*
* @return string The command output
*
* @throws ExecutionFailureException in case of process failure.
*/
public function command($command, $bypassErrors = false, $listeners = null);
/**
* Loads a binary
*
* @param string|array $binaries A binary name or an array of binary names
* @param null|LoggerInterface $logger A Logger
* @param array|ConfigurationInterface $configuration The configuration
*
* @throws ExecutableNotFoundException In case none of the binaries were found
*
* @return BinaryInterface
*/
public static function load($binaries, LoggerInterface $logger = null, $configuration = array());
}

View file

@ -0,0 +1,109 @@
<?php
/*
* This file is part of Alchemy\BinaryDriver.
*
* (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 Alchemy\BinaryDriver;
use Traversable;
class Configuration implements ConfigurationInterface
{
private $data;
public function __construct(array $data = [])
{
$this->data = $data;
}
/**
* {@inheritdoc}
*/
public function getIterator(): Traversable
{
return new \ArrayIterator($this->data);
}
/**
* {@inheritdoc}
*/
public function get($key, $default = null)
{
return isset($this->data[$key]) ? $this->data[$key] : $default;
}
/**
* {@inheritdoc}
*/
public function set($key, $value)
{
$this->data[$key] = $value;
return $this;
}
/**
* {@inheritdoc}
*/
public function has($key)
{
return array_key_exists($key, $this->data);
}
/**
* {@inheritdoc}
*/
public function remove($key)
{
$value = $this->get($key);
unset($this->data[$key]);
return $value;
}
/**
* {@inheritdoc}
*/
public function all()
{
return $this->data;
}
/**
* {@inheritdoc}
*/
public function offsetExists($offset): bool
{
return $this->has($offset);
}
/**
* {@inheritdoc}
*/
public function offsetGet($offset): mixed
{
return $this->get($offset);
}
/**
* {@inheritdoc}
*/
public function offsetSet($offset, $value): void
{
$this->set($offset, $value);
}
/**
* {@inheritdoc}
*/
public function offsetUnset($offset): void
{
$this->remove($offset);
}
}

View file

@ -0,0 +1,29 @@
<?php
/*
* This file is part of Alchemy\BinaryDriver.
*
* (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 Alchemy\BinaryDriver;
interface ConfigurationAwareInterface
{
/**
* Returns the configuration
*
* @return ConfigurationInterface
*/
public function getConfiguration();
/**
* Set the configuration
*
* @param ConfigurationInterface $configuration
*/
public function setConfiguration(ConfigurationInterface $configuration);
}

View file

@ -0,0 +1,58 @@
<?php
/*
* This file is part of Alchemy\BinaryDriver.
*
* (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 Alchemy\BinaryDriver;
interface ConfigurationInterface extends \ArrayAccess, \IteratorAggregate
{
/**
* Returns the value given a key from configuration
*
* @param string $key
* @param mixed $default The default value in case the key does not exist
*
* @return mixed
*/
public function get($key, $default = null);
/**
* Set a value to configuration
*
* @param string $key The key
* @param mixed $value The value corresponding to the key
*/
public function set($key, $value);
/**
* Tells if Configuration contains `$key`
*
* @param string $key
*
* @return Boolean
*/
public function has($key);
/**
* Removes a value given a key
*
* @param string $key
*
* @return mixed The previous value
*/
public function remove($key);
/**
* Returns all values set in the configuration
*
* @return array
*/
public function all();
}

View file

@ -0,0 +1,16 @@
<?php
/*
* This file is part of Alchemy\BinaryDriver.
*
* (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 Alchemy\BinaryDriver\Exception;
interface ExceptionInterface
{
}

View file

@ -0,0 +1,16 @@
<?php
/*
* This file is part of Alchemy\BinaryDriver.
*
* (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 Alchemy\BinaryDriver\Exception;
class ExecutableNotFoundException extends \RuntimeException implements ExceptionInterface
{
}

View file

@ -0,0 +1,37 @@
<?php
/*
* This file is part of Alchemy\BinaryDriver.
*
* (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 Alchemy\BinaryDriver\Exception;
class ExecutionFailureException extends \RuntimeException implements ExceptionInterface
{
/** @var string */
protected $command;
/** @var string */
protected $errorOutput;
public function __construct($binaryName, $command, $errorOutput = null, $code = 0, $previous = null)
{
$message = sprintf("%s failed to execute command %s:\n\nError Output:\n\n %s", $binaryName, $command, $errorOutput);
parent::__construct($message, $code, $previous);
$this->command = $command;
$this->errorOutput = $errorOutput;
}
public function getCommand(){
return $this->command;
}
public function getErrorOutput(){
return $this->errorOutput;
}
}

View file

@ -0,0 +1,16 @@
<?php
/*
* This file is part of Alchemy\BinaryDriver.
*
* (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 Alchemy\BinaryDriver\Exception;
class InvalidArgumentException extends \InvalidArgumentException implements ExceptionInterface
{
}

View file

@ -0,0 +1,58 @@
<?php
/*
* This file is part of Alchemy\BinaryDriver.
*
* (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 Alchemy\BinaryDriver\Listeners;
use Evenement\EventEmitter;
use Symfony\Component\Process\Process;
class DebugListener extends EventEmitter implements ListenerInterface
{
private $prefixOut;
private $prefixErr;
private $eventOut;
private $eventErr;
public function __construct($prefixOut = '[OUT] ', $prefixErr = '[ERROR] ', $eventOut = 'debug', $eventErr = 'debug')
{
$this->prefixOut = $prefixOut;
$this->prefixErr = $prefixErr;
$this->eventOut = $eventOut;
$this->eventErr = $eventErr;
}
/**
* {@inheritdoc}
*/
public function handle($type, $data)
{
if (Process::ERR === $type) {
$this->emitLines($this->eventErr, $this->prefixErr, $data);
} elseif (Process::OUT === $type) {
$this->emitLines($this->eventOut, $this->prefixOut, $data);
}
}
/**
* {@inheritdoc}
*/
public function forwardedEvents()
{
return array_unique(array($this->eventErr, $this->eventOut));
}
private function emitLines($event, $prefix, $lines)
{
foreach (explode("\n", $lines) as $line) {
$this->emit($event, array($prefix . $line));
}
}
}

View file

@ -0,0 +1,32 @@
<?php
/*
* This file is part of Alchemy\BinaryDriver.
*
* (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 Alchemy\BinaryDriver\Listeners;
use Evenement\EventEmitterInterface;
interface ListenerInterface extends EventEmitterInterface
{
/**
* Handle the output of a ProcessRunner
*
* @param string $type The data type, one of Process::ERR, Process::OUT constants
* @param string $data The output
*/
public function handle($type, $data);
/**
* An array of events that should be forwarded to BinaryInterface
*
* @return array
*/
public function forwardedEvents();
}

View file

@ -0,0 +1,88 @@
<?php
namespace Alchemy\BinaryDriver\Listeners;
use SplObjectStorage;
use Evenement\EventEmitter;
class Listeners extends EventEmitter
{
/** @var SplObjectStorage */
public $storage;
public function __construct()
{
$this->storage = new SplObjectStorage();
}
public function __clone()
{
$storage = $this->storage;
$this->storage = new SplObjectStorage();
$this->storage->addAll($storage);
}
/**
* Registers a listener, pass the listener events to the target.
*
* @param ListenerInterface $listener
* @param null|EventEmitter $target
*
* @return ListenersInterface
*/
public function register(ListenerInterface $listener, EventEmitter $target = null)
{
$EElisteners = array();
if (null !== $target) {
$EElisteners = $this->forwardEvents($listener, $target, $listener->forwardedEvents());
}
$this->storage->attach($listener, $EElisteners);
return $this;
}
/**
* Unregisters a listener, removes the listener events from the target.
*
* @param ListenerInterface $listener
*
* @return ListenersInterface
*
* @throws InvalidArgumentException In case the listener is not registered
*/
public function unregister(ListenerInterface $listener)
{
if (!isset($this->storage[$listener])) {
throw new InvalidArgumentException('Listener is not registered.');
}
foreach ($this->storage[$listener] as $event => $EElistener) {
$listener->removeListener($event, $EElistener);
}
$this->storage->detach($listener);
return $this;
}
private function forwardEvents($source, $target, array $events)
{
$EElisteners = array();
foreach ($events as $event) {
$listener = $this->createListener($event, $target);
$source->on($event, $EElisteners[$event] = $listener);
}
return $EElisteners;
}
private function createListener($event, $target)
{
return function () use ($event, $target) {
$target->emit($event, func_get_args());
};
}
}

View file

@ -0,0 +1,186 @@
<?php
/*
* This file is part of Alchemy\BinaryDriver.
*
* (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 Alchemy\BinaryDriver;
use Alchemy\BinaryDriver\Exception\InvalidArgumentException;
use Symfony\Component\Process\Process;
use Symfony\Component\Process\ProcessBuilder;
class ProcessBuilderFactory implements ProcessBuilderFactoryInterface
{
/**
* The binary path
*
* @var String
*/
protected $binary;
/**
* The timeout for the generated processes
*
* @var integer|float
*/
private $timeout;
/**
* An internal ProcessBuilder.
*
* Note that this one is used only if Symfony ProcessBuilder has method
* setPrefix (2.3)
*
* @var ProcessBuilder
*/
private $builder;
/**
* Tells whether Symfony LTS ProcessBuilder should be emulated or not.
*
* This symfony version provided a brand new ::setPrefix method.
*
* @var Boolean
*/
public static $emulateSfLTS;
/**
* Constructor
*
* @param String $binary The path to the binary
*
* @throws InvalidArgumentException In case binary path is invalid
*/
public function __construct($binary)
{
$this->detectEmulation();
if (!self::$emulateSfLTS) {
$this->builder = new ProcessBuilder();
}
$this->useBinary($binary);
}
/**
* Covenient method for unit testing
*
* @return type
*/
public function getBuilder()
{
return $this->builder;
}
/**
* Covenient method for unit testing
*
* @param ProcessBuilder $builder
* @return ProcessBuilderFactory
*/
public function setBuilder(ProcessBuilder $builder)
{
$this->builder = $builder;
return $this;
}
/**
* @inheritdoc
*/
public function getBinary()
{
return $this->binary;
}
/**
* @inheritdoc
*/
public function useBinary($binary)
{
if (!is_executable($binary)) {
throw new InvalidArgumentException(sprintf('`%s` is not an executable binary', $binary));
}
$this->binary = $binary;
if (!static::$emulateSfLTS) {
$this->builder->setPrefix($binary);
}
return $this;
}
/**
* @inheritdoc
*/
public function setTimeout($timeout)
{
$this->timeout = $timeout;
if (!static::$emulateSfLTS) {
$this->builder->setTimeout($this->timeout);
}
return $this;
}
/**
* @inheritdoc
*/
public function getTimeout()
{
return $this->timeout;
}
/**
* @inheritdoc
*/
public function create($arguments = array())
{
if (null === $this->binary) {
throw new InvalidArgumentException('No binary set');
}
if (!is_array($arguments)) {
$arguments = array($arguments);
}
if (static::$emulateSfLTS) {
array_unshift($arguments, $this->binary);
if (method_exists('Symfony\Component\Process\ProcessUtils', 'escapeArgument')) {
$script = implode(' ', array_map(array('Symfony\Component\Process\ProcessUtils', 'escapeArgument'), $arguments));
} else {
$script = $arguments;
}
$env = array_replace($_ENV, $_SERVER);
$env = array_filter($env, function ($value) {
return !is_array($value);
});
return new Process($script, null, $env, null, $this->timeout);
} else {
return $this->builder
->setArguments($arguments)
->getProcess();
}
}
private function detectEmulation()
{
if (null !== static::$emulateSfLTS) {
return $this;
}
static::$emulateSfLTS = !method_exists('Symfony\Component\Process\ProcessBuilder', 'setPrefix');
return $this;
}
}

View file

@ -0,0 +1,29 @@
<?php
/*
* This file is part of Alchemy\BinaryDriver.
*
* (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 Alchemy\BinaryDriver;
interface ProcessBuilderFactoryAwareInterface
{
/**
* Returns the current process builder factory
*
* @return ProcessBuilderFactoryInterface
*/
public function getProcessBuilderFactory();
/**
* Set a process builder factory
*
* @param ProcessBuilderFactoryInterface $factory
*/
public function setProcessBuilderFactory(ProcessBuilderFactoryInterface $factory);
}

View file

@ -0,0 +1,65 @@
<?php
/*
* This file is part of Alchemy\BinaryDriver.
*
* (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 Alchemy\BinaryDriver;
use Alchemy\BinaryDriver\Exception\InvalidArgumentException;
use Symfony\Component\Process\Process;
interface ProcessBuilderFactoryInterface
{
/**
* Returns a new instance of Symfony Process
*
* @param string|array $arguments An argument or an array of arguments
*
* @return Process
*
* @throws InvalidArgumentException
*/
public function create($arguments = array());
/**
* Returns the path to the binary that is used
*
* @return String
*/
public function getBinary();
/**
* Sets the path to the binary
*
* @param String $binary A path to a binary
*
* @return ProcessBuilderFactoryInterface
*
* @throws InvalidArgumentException In case binary is not executable
*/
public function useBinary($binary);
/**
* Set the default timeout to apply on created processes.
*
* @param integer|float $timeout
*
* @return ProcessBuilderFactoryInterface
*
* @throws InvalidArgumentException In case the timeout is not valid
*/
public function setTimeout($timeout);
/**
* Returns the current timeout applied to the created processes.
*
* @return integer|float
*/
public function getTimeout();
}

View file

@ -0,0 +1,107 @@
<?php
/*
* This file is part of Alchemy\BinaryDriver.
*
* (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 Alchemy\BinaryDriver;
use Alchemy\BinaryDriver\Exception\ExecutionFailureException;
use Psr\Log\LoggerInterface;
use SplObjectStorage;
use Symfony\Component\Process\Exception\RuntimeException;
use Symfony\Component\Process\Process;
class ProcessRunner implements ProcessRunnerInterface
{
/** @var LoggerInterface */
private $logger;
/** @var string */
private $name;
public function __construct(LoggerInterface $logger, $name)
{
$this->logger = $logger;
$this->name = $name;
}
/**
* {@inheritdoc}
*
* @return void
*/
public function setLogger(LoggerInterface $logger): void
{
$this->logger = $logger;
}
/**
* @return LoggerInterface
*/
public function getLogger()
{
return $this->logger;
}
/**
* {@inheritdoc}
*/
public function run(Process $process, SplObjectStorage $listeners, $bypassErrors)
{
$this->logger->info(sprintf(
'%s running command %s',
$this->name,
$process->getCommandLine()
));
try {
$process->run($this->buildCallback($listeners));
} catch (RuntimeException $e) {
if (!$bypassErrors) {
$this->doExecutionFailure($process->getCommandLine(), $process->getErrorOutput(), $e);
}
}
if (!$bypassErrors && !$process->isSuccessful()) {
$this->doExecutionFailure($process->getCommandLine(), $process->getErrorOutput());
} elseif (!$process->isSuccessful()) {
$this->logger->error($this->createErrorMessage($process->getCommandLine(), $process->getErrorOutput()));
return;
} else {
$this->logger->info(sprintf('%s executed command successfully', $this->name));
return $process->getOutput();
}
}
private function buildCallback(SplObjectStorage $listeners)
{
return function ($type, $data) use ($listeners) {
foreach ($listeners as $listener) {
$listener->handle($type, $data);
}
};
}
private function doExecutionFailure($command, $errorOutput, \Exception $e = null)
{
$this->logger->error($this->createErrorMessage($command, $errorOutput));
throw new ExecutionFailureException(
$this->name,
$command,
$errorOutput,
$e ? $e->getCode() : 0,
$e ?: null
);
}
private function createErrorMessage($command, $errorOutput)
{
return sprintf('%s failed to execute command %s: %s', $this->name, $command, $errorOutput);
}
}

View file

@ -0,0 +1,29 @@
<?php
/*
* This file is part of Alchemy\BinaryDriver.
*
* (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 Alchemy\BinaryDriver;
interface ProcessRunnerAwareInterface
{
/**
* Returns the current process runner
*
* @return ProcessRunnerInterface
*/
public function getProcessRunner();
/**
* Sets a process runner
*
* @param ProcessRunnerInterface $runner
*/
public function setProcessRunner(ProcessRunnerInterface $runner);
}

View file

@ -0,0 +1,33 @@
<?php
/*
* This file is part of Alchemy\BinaryDriver.
*
* (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 Alchemy\BinaryDriver;
use Alchemy\BinaryDriver\Exception\ExecutionFailureException;
use Psr\Log\LoggerAwareInterface;
use SplObjectStorage;
use Symfony\Component\Process\Process;
interface ProcessRunnerInterface extends LoggerAwareInterface
{
/**
* Executes a process, logs events
*
* @param Process $process
* @param SplObjectStorage $listeners Some listeners
* @param Boolean $bypassErrors Set to true to disable throwing ExecutionFailureExceptions
*
* @return string The Process output
*
* @throws ExecutionFailureException in case of process failure.
*/
public function run(Process $process, SplObjectStorage $listeners, $bypassErrors);
}

View file

@ -17,49 +17,49 @@ use FFMpeg\Exception\InvalidArgumentException;
class AspectRatio
{
// named 4:3 or 1.33:1 Traditional TV
const AR_4_3 = '4/3';
public const AR_4_3 = '4/3';
// named 16:9 or 1.77:1 HD video standard
const AR_16_9 = '16/9';
public const AR_16_9 = '16/9';
// named 8:5 or 16:10 or 1.6:1
const AR_8_5 = '8/5';
public const AR_8_5 = '8/5';
// named 25:16 or 1.56:1
const AR_25_16 = '25/16';
public const AR_25_16 = '25/16';
// named 3:2 or 1.5:1 see http://en.wikipedia.org/wiki/135_film
const AR_3_2 = '3/2';
public 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';
public const AR_5_3 = '5/3';
// mostly used in Photography
const AR_5_4 = '5/4';
const AR_1_1 = '1/1';
public const AR_5_4 = '5/4';
public 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';
public 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';
public const AR_2_DOT_39_1 = '2.39:1';
// Rotated constants
// Rotated 4:3
const AR_ROTATED_3_4 = '3/4';
public const AR_ROTATED_3_4 = '3/4';
// Rotated 16:9
const AR_ROTATED_9_16 = '9/16';
public const AR_ROTATED_9_16 = '9/16';
// Rotated 3:2
const AR_ROTATED_2_3 = '2/3';
public const AR_ROTATED_2_3 = '2/3';
// Rotated 5:3
const AR_ROTATED_3_5 = '3/5';
public const AR_ROTATED_3_5 = '3/5';
// Rotated 5:4
const AR_ROTATED_4_5 = '4/5';
public const AR_ROTATED_4_5 = '4/5';
// Rotated 1.85
const AR_ROTATED_1_DOT_85 = '1/1.85';
public const AR_ROTATED_1_DOT_85 = '1/1.85';
// Rotated 2.39
const AR_ROTATED_2_DOT_39 = '1/2.39';
public const AR_ROTATED_2_DOT_39 = '1/2.39';
/** @var float */
private $ratio;
@ -82,10 +82,10 @@ class AspectRatio
/**
* Computes the best width for given height and modulus.
*
* @param Integer $height
* @param Integer $modulus
* @param int $height
* @param int $modulus
*
* @return Integer
* @return int
*/
public function calculateWidth($height, $modulus = 1)
{
@ -101,10 +101,10 @@ class AspectRatio
/**
* Computes the best height for given width and modulus.
*
* @param Integer $width
* @param Integer $modulus
* @param int $width
* @param int $modulus
*
* @return Integer
* @return int
*/
public function calculateHeight($width, $modulus = 1)
{
@ -120,7 +120,7 @@ class AspectRatio
private function getMultipleUp($value, $multiple)
{
while (0 !== $value % $multiple) {
$value++;
++$value;
}
return $value;
@ -129,7 +129,7 @@ class AspectRatio
private function getMultipleDown($value, $multiple)
{
while (0 !== $value % $multiple) {
$value--;
--$value;
}
return $value;
@ -141,8 +141,7 @@ class AspectRatio
* The strategy parameter forces by default to use standardized ratios. If
* custom ratio need to be used, disable it.
*
* @param Dimension $dimension
* @param bool $forceStandards Whether to force or not standard ratios
* @param bool $forceStandards Whether to force or not standard ratios
*
* @return AspectRatio
*
@ -214,7 +213,7 @@ class AspectRatio
private static function nearestStrategy($incoming)
{
$availables = array(
$availables = [
static::AR_4_3 => static::valueFromName(static::AR_4_3),
static::AR_16_9 => static::valueFromName(static::AR_16_9),
static::AR_8_5 => static::valueFromName(static::AR_8_5),
@ -234,7 +233,7 @@ class AspectRatio
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;

View file

@ -14,7 +14,7 @@ namespace FFMpeg\Coordinate;
use FFMpeg\Exception\InvalidArgumentException;
/**
* Dimension object, used for manipulating width and height couples
* Dimension object, used for manipulating width and height couples.
*/
class Dimension
{

View file

@ -22,8 +22,8 @@ class Point
$this->x = $x;
$this->y = $y;
} else {
$this->x = (int)$x;
$this->y = (int)$y;
$this->x = (int) $x;
$this->y = (int) $y;
}
}

View file

@ -91,10 +91,12 @@ class TimeCode
}
/**
* Returns this timecode in seconds
* Returns this timecode in seconds.
*
* @return int
*/
public function toSeconds() {
public function toSeconds()
{
$seconds = 0;
$seconds += $this->hours * 60 * 60;
@ -107,14 +109,15 @@ class TimeCode
}
/**
* Helper function wether `$timecode` is after this one
* Helper function wether `$timecode` is after this one.
*
* @param TimeCode $timecode The Timecode to compare
*
* @param TimeCode $timecode The Timecode to compare
* @return bool
*/
public function isAfter(TimeCode $timecode) {
public function isAfter(TimeCode $timecode)
{
// convert everything to seconds and compare
return ($this->toSeconds() > $timecode->toSeconds());
return $this->toSeconds() > $timecode->toSeconds();
}
}

View file

@ -37,13 +37,13 @@ class FFMpegDriver extends AbstractBinary
*
* @return FFMpegDriver
*/
public static function create(LoggerInterface $logger = null, $configuration = array())
public static function create(LoggerInterface $logger = null, $configuration = [])
{
if (!$configuration instanceof ConfigurationInterface) {
$configuration = new Configuration($configuration);
}
$binaries = $configuration->get('ffmpeg.binaries', array('avconv', 'ffmpeg'));
$binaries = $configuration->get('ffmpeg.binaries', ['avconv', 'ffmpeg']);
if (!$configuration->has('timeout')) {
$configuration->set('timeout', 300);
@ -60,6 +60,7 @@ class FFMpegDriver extends AbstractBinary
* Get ffmpeg version.
*
* @return string
*
* @throws RuntimeException
*/
public function getVersion()

View file

@ -42,7 +42,7 @@ class FFProbeDriver extends AbstractBinary
$configuration = new Configuration($configuration);
}
$binaries = $configuration->get('ffprobe.binaries', array('avprobe', 'ffprobe'));
$binaries = $configuration->get('ffprobe.binaries', ['avprobe', 'ffprobe']);
try {
return static::load($binaries, $logger, $configuration);

View file

@ -15,8 +15,8 @@ use Alchemy\BinaryDriver\ConfigurationInterface;
use FFMpeg\Driver\FFMpegDriver;
use FFMpeg\Exception\InvalidArgumentException;
use FFMpeg\Exception\RuntimeException;
use FFMpeg\Media\Audio;
use FFMpeg\Media\AdvancedMedia;
use FFMpeg\Media\Audio;
use FFMpeg\Media\Video;
use Psr\Log\LoggerInterface;
@ -60,8 +60,6 @@ class FFMpeg
/**
* Sets the ffmpeg driver.
*
* @param FFMpegDriver $ffmpeg
*
* @return FFMpeg
*/
public function setFFMpegDriver(FFMpegDriver $ffmpeg)
@ -108,7 +106,7 @@ class FFMpeg
/**
* Opens multiple input sources.
*
* @param string[] $inputs Array of files to be opened.
* @param string[] $inputs array of files to be opened
*
* @return AdvancedMedia
*/
@ -126,7 +124,7 @@ class FFMpeg
*
* @return FFMpeg
*/
public static function create($configuration = array(), LoggerInterface $logger = null, FFProbe $probe = null)
public static function create($configuration = [], LoggerInterface $logger = null, FFProbe $probe = null)
{
if (null === $probe) {
$probe = FFProbe::create($configuration, $logger, null);

View file

@ -1,67 +0,0 @@
<?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 Silex\Application;
use Silex\ServiceProviderInterface;
use Symfony\Component\Cache\Adapter\ArrayAdapter;
/**
* @deprecated
*/
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 ArrayAdapter;
});
$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)
{
}
}

View file

@ -30,8 +30,8 @@ use Symfony\Component\Cache\Adapter\ArrayAdapter;
class FFProbe
{
const TYPE_STREAMS = 'streams';
const TYPE_FORMAT = 'format';
public const TYPE_STREAMS = 'streams';
public const TYPE_FORMAT = 'format';
/** @var CacheItemPoolInterface */
private $cache;
@ -46,11 +46,11 @@ class FFProbe
public function __construct(FFProbeDriver $ffprobe, CacheItemPoolInterface $cache)
{
$this->ffprobe = $ffprobe;
$this->ffprobe = $ffprobe;
$this->optionsTester = new OptionsTester($ffprobe, $cache);
$this->parser = new OutputParser();
$this->mapper = new Mapper();
$this->cache = $cache;
$this->parser = new OutputParser();
$this->mapper = new Mapper();
$this->cache = $cache;
}
/**
@ -62,8 +62,6 @@ class FFProbe
}
/**
* @param OutputParserInterface $parser
*
* @return FFProbe
*/
public function setParser(OutputParserInterface $parser)
@ -82,8 +80,6 @@ class FFProbe
}
/**
* @param FFProbeDriver $ffprobe
*
* @return FFProbe
*/
public function setFFProbeDriver(FFProbeDriver $ffprobe)
@ -94,8 +90,6 @@ class FFProbe
}
/**
* @param OptionsTesterInterface $tester
*
* @return FFProbe
*/
public function setOptionsTester(OptionsTesterInterface $tester)
@ -142,8 +136,6 @@ class FFProbe
}
/**
* @param MapperInterface $mapper
*
* @return FFProbe
*/
public function setMapper(MapperInterface $mapper)
@ -176,14 +168,16 @@ class FFProbe
* Checks wether the given `$pathfile` is considered a valid media file.
*
* @param string $pathfile
*
* @return bool
*
* @since 0.10.0
*/
public function isValid($pathfile)
{
try {
return $this->format($pathfile)->get('duration') > 0;
} catch(\Exception $e) {
} catch (\Exception $e) {
// complete invalid data
return false;
}
@ -217,7 +211,7 @@ class FFProbe
*
* @return FFProbe
*/
public static function create($configuration = array(), LoggerInterface $logger = null, CacheItemPoolInterface $cache = null)
public static function create($configuration = [], LoggerInterface $logger = null, CacheItemPoolInterface $cache = null)
{
if (null === $cache) {
$cache = new ArrayAdapter();
@ -235,13 +229,10 @@ class FFProbe
}
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
));
throw new RuntimeException(sprintf('This version of ffprobe is too old and ' . 'does not support `%s` option, please upgrade', $command));
}
$commands = array($pathfile, $command);
$commands = [$pathfile, $command];
$parseIsToDo = false;

View file

@ -23,7 +23,8 @@ abstract class AbstractData implements \Countable
/**
* Returns true if data has property.
*
* @param string $property
* @param string $property
*
* @return bool
*/
public function has($property)
@ -34,8 +35,8 @@ abstract class AbstractData implements \Countable
/**
* Returns the property value given its name.
*
* @param string $property
* @param mixed $default
* @param string $property
* @param mixed $default
*
* @return mixed
*/
@ -86,8 +87,7 @@ abstract class AbstractData implements \Countable
/**
* {@inheritdoc}
*/
#[\ReturnTypeWillChange]
public function count()
public function count(): int
{
return count($this->properties);
}

View file

@ -11,9 +11,9 @@
namespace FFMpeg\FFProbe\DataMapping;
use FFMpeg\Coordinate\Dimension;
use FFMpeg\Exception\LogicException;
use FFMpeg\Exception\RuntimeException;
use FFMpeg\Coordinate\Dimension;
class Stream extends AbstractData
{
@ -24,7 +24,7 @@ class Stream extends AbstractData
*/
public function isAudio()
{
return $this->get('codec_type') === 'audio';
return 'audio' === $this->get('codec_type');
}
/**
@ -34,7 +34,7 @@ class Stream extends AbstractData
*/
public function isVideo()
{
return $this->get('codec_type') === 'video';
return 'video' === $this->get('codec_type');
}
/**
@ -42,8 +42,8 @@ class Stream extends AbstractData
*
* @return Dimension
*
* @throws LogicException In case the stream is not a video stream.
* @throws RuntimeException In case the dimensions can not be extracted.
* @throws LogicException in case the stream is not a video stream
* @throws RuntimeException in case the dimensions can not be extracted
*/
public function getDimensions()
{
@ -68,7 +68,7 @@ class Stream extends AbstractData
}
if (null !== $displayRatio && null !== $sampleRatio) {
if ($sampleRatio[0] !== 1 && $sampleRatio[1] !== 1) {
if (1 !== $sampleRatio[0] && 1 !== $sampleRatio[1]) {
if (null !== $width && null !== $height) {
// stretch video according to pixel sample aspect ratio
$width = round($width * ($sampleRatio[0] / $sampleRatio[1]));
@ -84,9 +84,10 @@ class Stream extends AbstractData
/**
* 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.
* @param Stream $stream the stream where to look for the ratio
* @param string $name the name of the key
*
* @return array|null an array containing the width and the height, null if not found
*/
private function extractRatio(Stream $stream, $name)
{
@ -100,7 +101,9 @@ class Stream extends AbstractData
return $int > 0;
});
if (2 === count($data)) {
return array_map(function ($int) { return (int) $int; }, $data);
return array_map(function ($int) {
return (int) $int;
}, $data);
}
}
}

View file

@ -11,11 +11,13 @@
namespace FFMpeg\FFProbe\DataMapping;
use Traversable;
class StreamCollection implements \Countable, \IteratorAggregate
{
private $streams;
public function __construct(array $streams = array())
public function __construct(array $streams = [])
{
$this->streams = array_values($streams);
}
@ -24,7 +26,7 @@ class StreamCollection implements \Countable, \IteratorAggregate
* Returns the first stream of the collection, null if the collection is
* empty.
*
* @return null|Stream
* @return Stream|null
*/
public function first()
{
@ -36,8 +38,6 @@ class StreamCollection implements \Countable, \IteratorAggregate
/**
* Adds a stream to the collection.
*
* @param Stream $stream
*
* @return StreamCollection
*/
public function add(Stream $stream)
@ -74,8 +74,7 @@ class StreamCollection implements \Countable, \IteratorAggregate
/**
* {@inheritdoc}
*/
#[\ReturnTypeWillChange]
public function count()
public function count(): int
{
return count($this->streams);
}
@ -93,8 +92,7 @@ class StreamCollection implements \Countable, \IteratorAggregate
/**
* {@inheritdoc}
*/
#[\ReturnTypeWillChange]
public function getIterator()
public function getIterator(): Traversable
{
return new \ArrayIterator($this->streams);
}

View file

@ -11,11 +11,11 @@
namespace FFMpeg\FFProbe;
use FFMpeg\Exception\InvalidArgumentException;
use FFMpeg\FFProbe;
use FFMpeg\FFProbe\DataMapping\Format;
use FFMpeg\FFProbe\DataMapping\StreamCollection;
use FFMpeg\FFProbe\DataMapping\Stream;
use FFMpeg\Exception\InvalidArgumentException;
use FFMpeg\FFProbe\DataMapping\StreamCollection;
class Mapper implements MapperInterface
{
@ -30,9 +30,7 @@ class Mapper implements MapperInterface
case FFProbe::TYPE_STREAMS:
return $this->mapStreams($data);
default:
throw new InvalidArgumentException(sprintf(
'Invalid type `%s`.', $type
));
throw new InvalidArgumentException(sprintf('Invalid type `%s`.', $type));
}
}

View file

@ -60,7 +60,7 @@ class OptionsTester implements OptionsTesterInterface
}
try {
$output = $this->ffprobe->command(array('-help', '-loglevel', 'quiet'));
$output = $this->ffprobe->command(['-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);
}

View file

@ -11,8 +11,8 @@
namespace FFMpeg\FFProbe;
use FFMpeg\FFProbe;
use FFMpeg\Exception\InvalidArgumentException;
use FFMpeg\FFProbe;
class OutputParser implements OutputParserInterface
{
@ -35,11 +35,10 @@ class OutputParser implements OutputParserInterface
private function parseFormat($data)
{
$ret = array();
$ret = [];
foreach (explode(PHP_EOL, $data) as $line) {
if (in_array($line, array('[FORMAT]', '[/FORMAT]'))) {
if (in_array($line, ['[FORMAT]', '[/FORMAT]'])) {
continue;
}
@ -58,7 +57,7 @@ class OutputParser implements OutputParserInterface
if (0 === strpos($key, 'TAG:')) {
if (!isset($ret['tags'])) {
$ret['tags'] = array();
$ret['tags'] = [];
}
$ret['tags'][substr($key, 4)] = $value;
} else {
@ -66,22 +65,21 @@ class OutputParser implements OutputParserInterface
}
}
return array('format' => $ret);
return ['format' => $ret];
}
private function parseStreams($data)
{
$ret = array();
$ret = [];
$n = -1;
foreach (explode(PHP_EOL, $data) as $line) {
if ($line == '[STREAM]') {
$n ++;
$ret[$n] = array();
if ('[STREAM]' == $line) {
++$n;
$ret[$n] = [];
continue;
}
if ($line == '[/STREAM]') {
if ('[/STREAM]' == $line) {
continue;
}
@ -101,18 +99,18 @@ class OutputParser implements OutputParserInterface
continue;
}
if (in_array($key, array('index', 'width', 'height', 'channels', 'bits_per_sample', 'has_b_frames', 'level', 'start_pts', 'duration_ts'))) {
if (in_array($key, ['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'] = [];
}
$ret[$n]['tags'][substr($key, 4)] = $value;
} elseif (0 === strpos($key, 'DISPOSITION:')) {
if (!isset($ret[$n]['disposition'])) {
$ret[$n]['disposition'] = array();
$ret[$n]['disposition'] = [];
}
$ret[$n]['disposition'][substr($key, 12)] = $value;
} else {
@ -120,6 +118,6 @@ class OutputParser implements OutputParserInterface
}
}
return array('streams' => $ret);
return ['streams' => $ret];
}
}

View file

@ -59,13 +59,13 @@ class ANullSrcFilter extends AbstractComplexFilter
*/
public function applyComplex(AdvancedMedia $media)
{
return array(
return [
'-filter_complex',
$this->getName() . $this->buildFilterOptions(array(
$this->getName().$this->buildFilterOptions([
'channel_layout' => $this->channelLayout,
'sample_rate' => $this->sampleRate,
'nb_samples' => $this->nbSamples,
))
);
]),
];
}
}

View file

@ -42,19 +42,19 @@ abstract class AbstractComplexFilter implements ComplexCompatibleFilter
*
* @param array $params Associative array of filter options. The options may be null.
*
* @return string The string of the form "=name1=value1:name2=value2" or empty string.
* @return string the string of the form "=name1=value1:name2=value2" or empty string
*/
protected function buildFilterOptions(array $params)
{
$config = array();
$config = [];
foreach ($params as $paramName => $paramValue) {
if ($paramValue !== null) {
$config[] = $paramName . '=' . $paramValue;
if (null !== $paramValue) {
$config[] = $paramName.'='.$paramValue;
}
}
if (!empty($config)) {
return '=' . implode(':', $config);
return '='.implode(':', $config);
}
return '';

View file

@ -27,9 +27,7 @@ interface ComplexCompatibleFilter extends FilterInterface
/**
* Apply the complex filter to the given media.
*
* @param AdvancedMedia $media
*
* @return string[] An array of arguments.
* @return string[] an array of arguments
*/
public function applyComplex(AdvancedMedia $media);
}

View file

@ -32,9 +32,8 @@ class ComplexFilterContainer implements ComplexFilterInterface
/**
* ComplexFilter constructor.
*
* @param string $inLabels
* @param ComplexCompatibleFilter $baseFilter
* @param string $outLabels
* @param string $inLabels
* @param string $outLabels
*/
public function __construct($inLabels, ComplexCompatibleFilter $baseFilter, $outLabels)
{

View file

@ -16,8 +16,6 @@ class ComplexFilters
/**
* ComplexFilters constructor.
*
* @param AdvancedMedia $media
*/
public function __construct(AdvancedMedia $media)
{
@ -34,21 +32,22 @@ class ComplexFilters
public function custom($in, $parameters, $out)
{
$this->media->addFilter($in, new CustomComplexFilter($parameters), $out);
return $this;
}
/**
* Adds padding (black bars) to a video.
*
* @param string $in
* @param Dimension $dimension
* @param string $out
* @param string $in
* @param string $out
*
* @return ComplexFilters
*/
public function pad($in, Dimension $dimension, $out)
{
$this->media->addFilter($in, new PadFilter($dimension), $out);
return $this;
}
@ -58,13 +57,13 @@ class ComplexFilters
* @param string $in
* @param string $imagePath
* @param string $out
* @param array $coordinates
*
* @return $this
*/
public function watermark($in, $imagePath, $out, array $coordinates = array())
public function watermark($in, $imagePath, $out, array $coordinates = [])
{
$this->media->addFilter($in, new WatermarkFilter($imagePath, $coordinates), $out);
return $this;
}
@ -78,11 +77,13 @@ class ComplexFilters
* @param string $out
*
* @return ComplexFilters
*
* @see https://ffmpeg.org/ffmpeg-filters.html#xstack
*/
public function xStack($in, $layout, $inputsCount, $out)
{
$this->media->addFilter($in, new XStackFilter($layout, $inputsCount), $out);
return $this;
}
@ -101,6 +102,7 @@ class ComplexFilters
* @param float|null $decimals
*
* @return ComplexFilters
*
* @see https://ffmpeg.org/ffmpeg-filters.html#allrgb_002c-allyuv_002c-color_002c-haldclutsrc_002c-nullsrc_002c-pal75bars_002c-pal100bars_002c-rgbtestsrc_002c-smptebars_002c-smptehdbars_002c-testsrc_002c-testsrc2_002c-yuvtestsrc
*/
public function testSrc(
@ -115,8 +117,12 @@ class ComplexFilters
$alpha = null,
$decimals = null
) {
$this->media->addFilter('',
new TestSrcFilter($type, $size, $duration, $sar, $rate, $level, $color, $alpha, $decimals), $out);
$this->media->addFilter(
'',
new TestSrcFilter($type, $size, $duration, $sar, $rate, $level, $color, $alpha, $decimals),
$out
);
return $this;
}
@ -129,6 +135,7 @@ class ComplexFilters
* @param int|null $nbSamples
*
* @return ComplexFilters
*
* @see https://ffmpeg.org/ffmpeg-filters.html#anullsrc
*/
public function aNullSrc(
@ -138,6 +145,7 @@ class ComplexFilters
$nbSamples = null
) {
$this->media->addFilter('', new ANullSrcFilter($channelLayout, $sampleRate, $nbSamples), $out);
return $this;
}
@ -152,6 +160,7 @@ class ComplexFilters
* @param string|null $samples_per_frame
*
* @return $this
*
* @see https://ffmpeg.org/ffmpeg-filters.html#sine
*/
public function sine(
@ -162,8 +171,12 @@ class ComplexFilters
$sample_rate = null,
$samples_per_frame = null
) {
$this->media->addFilter('',
new SineFilter($duration, $frequency, $beep_factor, $sample_rate, $samples_per_frame), $out);
$this->media->addFilter(
'',
new SineFilter($duration, $frequency, $beep_factor, $sample_rate, $samples_per_frame),
$out
);
return $this;
}
}

View file

@ -38,6 +38,6 @@ class CustomComplexFilter extends AbstractComplexFilter
*/
public function applyComplex(AdvancedMedia $media)
{
return array('-filter_complex', $this->filter);
return ['-filter_complex', $this->filter];
}
}

View file

@ -77,21 +77,19 @@ class SineFilter extends AbstractComplexFilter
/**
* Apply the complex filter to the given media.
*
* @param AdvancedMedia $media
*
* @return string[] An array of arguments.
* @return string[] an array of arguments
*/
public function applyComplex(AdvancedMedia $media)
{
return array(
return [
'-filter_complex',
$this->getName() . $this->buildFilterOptions(array(
$this->getName().$this->buildFilterOptions([
'frequency' => $this->frequency,
'beep_factor' => $this->beep_factor,
'sample_rate' => $this->sample_rate,
'duration' => $this->duration,
'samples_per_frame' => $this->samples_per_frame,
))
);
]),
];
}
}

View file

@ -14,72 +14,72 @@ class TestSrcFilter extends AbstractComplexFilter
/**
* Source returns frames of size 4096x4096 of all rgb colors.
*/
const ALLRGB = 'allrgb';
public const ALLRGB = 'allrgb';
/**
* Source returns frames of size 4096x4096 of all yuv colors.
*/
const ALLYUV = 'allyuv';
public const ALLYUV = 'allyuv';
/**
* Source provides an uniformly colored input.
*/
const COLOR = 'color';
public const COLOR = 'color';
/**
* Source provides an identity Hald CLUT.
*/
const HALDCLUTSRC = 'haldclutsrc';
public const HALDCLUTSRC = 'haldclutsrc';
/**
* Source returns unprocessed video frames.
* It is mainly useful to be employed in analysis / debugging tools,
* or as the source for filters which ignore the input data.
*/
const NULLSRC = 'nullsrc';
public const NULLSRC = 'nullsrc';
/**
* Source generates a color bars pattern, based on EBU PAL recommendations with 75% color levels.
*/
const PAL75BARS = 'pal75bars';
public const PAL75BARS = 'pal75bars';
/**
* Source generates a color bars pattern, based on EBU PAL recommendations with 100% color levels.
*/
const PAL100BARS = 'pal100bars';
public const PAL100BARS = 'pal100bars';
/**
* Source generates an RGB test pattern useful for detecting RGB vs BGR issues.
* You should see a red, green and blue stripe from top to bottom.
*/
const RGBTESTSRC = 'rgbtestsrc';
public const RGBTESTSRC = 'rgbtestsrc';
/**
* Source generates a color bars pattern, based on the SMPTE Engineering Guideline EG 1-1990.
*/
const SMPTEBARS = 'smptebars';
public const SMPTEBARS = 'smptebars';
/**
* Source generates a color bars pattern, based on the SMPTE RP 219-2002.
*/
const SMPTEHDBARS = 'smptehdbars';
public const SMPTEHDBARS = 'smptehdbars';
/**
* Source generates a test video pattern, showing a color pattern, a scrolling gradient and a timestamp.
* This is mainly intended for testing purposes.
*/
const TESTSRC = 'testsrc';
public const TESTSRC = 'testsrc';
/**
* Source is similar to testsrc, but supports more pixel formats instead of just rgb24.
* This allows using it as an input for other tests without requiring a format conversion.
*/
const TESTSRC2 = 'testsrc2';
public const TESTSRC2 = 'testsrc2';
/**
* Source generates an YUV test pattern. You should see a y, cb and cr stripe from top to bottom.
*/
const YUVTESTSRC = 'yuvtestsrc';
public const YUVTESTSRC = 'yuvtestsrc';
/**
* @var string|null
@ -229,9 +229,9 @@ class TestSrcFilter extends AbstractComplexFilter
*/
public function applyComplex(AdvancedMedia $media)
{
return array(
return [
'-filter_complex',
$this->type . $this->buildFilterOptions(array(
$this->type.$this->buildFilterOptions([
'level' => $this->level,
'color' => $this->color,
'size' => $this->size,
@ -239,8 +239,8 @@ class TestSrcFilter extends AbstractComplexFilter
'duration' => $this->duration,
'sar' => $this->sar,
'alpha' => $this->alpha,
'decimals' => $this->decimals
))
);
'decimals' => $this->decimals,
]),
];
}
}

View file

@ -14,10 +14,10 @@ use FFMpeg\Media\AdvancedMedia;
*/
class XStackFilter extends AbstractComplexFilter
{
const LAYOUT_2X2 = '0_0|0_h0|w0_0|w0_h0';
const LAYOUT_1X4 = '0_0|0_h0|0_h0+h1|0_h0+h1+h2';
const LAYOUT_3X3 = '0_0|0_h0|0_h0+h1|w0_0|w0_h0|w0_h0+h1|w0+w3_0|w0+w3_h0|w0+w3_h0+h1';
const LAYOUT_4X4 = '0_0|0_h0|0_h0+h1|0_h0+h1+h2|w0_0|w0_h0|w0_h0+h1|w0_h0+h1+h2|w0+w4_0|w0+w4_h0|w0+w4_h0+h1|w0+w4_h0+h1+h2|w0+w4+w8_0|w0+w4+w8_h0|w0+w4+w8_h0+h1|w0+w4+w8_h0+h1+h2';
public const LAYOUT_2X2 = '0_0|0_h0|w0_0|w0_h0';
public const LAYOUT_1X4 = '0_0|0_h0|0_h0+h1|0_h0+h1+h2';
public const LAYOUT_3X3 = '0_0|0_h0|0_h0+h1|w0_0|w0_h0|w0_h0+h1|w0+w3_0|w0+w3_h0|w0+w3_h0+h1';
public const LAYOUT_4X4 = '0_0|0_h0|0_h0+h1|0_h0+h1+h2|w0_0|w0_h0|w0_h0+h1|w0_h0+h1+h2|w0+w4_0|w0+w4_h0|w0+w4_h0+h1|w0+w4_h0+h1+h2|w0+w4+w8_0|w0+w4+w8_h0|w0+w4+w8_h0+h1|w0+w4+w8_h0+h1+h2';
/**
* @var string
@ -51,9 +51,10 @@ class XStackFilter extends AbstractComplexFilter
public static function getInputByCount($count)
{
$result = '';
for ($i = 0; $i < $count; $i++) {
$result .= '[' . $i . ':v]';
for ($i = 0; $i < $count; ++$i) {
$result .= '['.$i.':v]';
}
return $result;
}
@ -82,12 +83,12 @@ class XStackFilter extends AbstractComplexFilter
*/
public function applyComplex(AdvancedMedia $media)
{
return array(
return [
'-filter_complex',
$this->getName() . $this->buildFilterOptions(array(
$this->getName().$this->buildFilterOptions([
'inputs' => $this->inputsCount,
'layout' => $this->layout
))
);
'layout' => $this->layout,
]),
];
}
}

View file

@ -11,48 +11,47 @@
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;
/** @var array */
private $metaArr;
/** @var int */
private $priority;
function __construct($metaArr = null, $priority = 9)
{
$this->metaArr = $metaArr;
$this->priority = $priority;
}
public 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 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;
public function apply(Audio $audio, AudioInterface $format)
{
$meta = $this->metaArr;
if (is_null($meta)) {
return array('-map_metadata', '-1', '-vn');
}
if (is_null($meta)) {
return ['-map_metadata', '-1', '-vn'];
}
$metadata = array();
$metadata = [];
if (array_key_exists("artwork", $meta)) {
array_push($metadata, "-i", $meta['artwork'], "-map", "0", "-map", "1");
unset($meta['artwork']);
}
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");
}
foreach ($meta as $k => $v) {
array_push($metadata, '-metadata', "$k=$v");
}
return $metadata;
}
return $metadata;
}
}

View file

@ -15,8 +15,8 @@ use FFMpeg\Coordinate\TimeCode;
use FFMpeg\Format\AudioInterface;
use FFMpeg\Media\Audio;
class AudioClipFilter implements AudioFilterInterface {
class AudioClipFilter implements AudioFilterInterface
{
/**
* @var TimeCode
*/
@ -32,53 +32,56 @@ class AudioClipFilter implements AudioFilterInterface {
*/
private $priority;
public function __construct(TimeCode $start, TimeCode $duration = null, $priority = 0) {
public function __construct(TimeCode $start, TimeCode $duration = null, $priority = 0)
{
$this->start = $start;
$this->duration = $duration;
$this->priority = $priority;
}
/**
* @inheritDoc
* {@inheritDoc}
*/
public function getPriority() {
public function getPriority()
{
return $this->priority;
}
/**
* Returns the start position the audio is being cutted
*
* @return TimeCode
*/
public function getStart() {
return $this->start;
}
/**
* 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;
}
/**
* 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);
/**
* {@inheritDoc}
*/
public function apply(Audio $audio, AudioInterface $format)
{
$commands = ['-ss', (string) $this->start];
if ($this->duration !== null) {
if (null !== $this->duration) {
$commands[] = '-t';
$commands[] = (string) $this->duration;
}
}
$commands[] = '-acodec';
$commands[] = 'copy';
$commands[] = '-acodec';
$commands[] = 'copy';
return $commands;
}
}
return $commands;
}
}

View file

@ -20,9 +20,6 @@ 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);

View file

@ -11,9 +11,8 @@
namespace FFMpeg\Filters\Audio;
use FFMpeg\Filters\Audio\AddMetadataFilter;
use FFMpeg\Media\Audio;
use FFMpeg\Coordinate\TimeCode;
use FFMpeg\Media\Audio;
class AudioFilters
{
@ -27,7 +26,7 @@ class AudioFilters
/**
* Resamples the audio file.
*
* @param Integer $rate
* @param int $rate
*
* @return AudioFilters
*/
@ -40,17 +39,18 @@ class AudioFilters
/**
* 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
* 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)
{
@ -60,22 +60,24 @@ class AudioFilters
}
/**
* Cuts the audio at `$start`, optionally define the end
* 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
*
* @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) {
public function clip($start, $duration = null)
{
$this->media->addFilter(new AudioClipFilter($start, $duration));
return $this;
}
/**
* Applies a custom filter
* Applies a custom filter.
*
* @param string $parameters
* @param string $parameters
*
* @return AudioFilters
*/

View file

@ -36,8 +36,7 @@ class AudioResamplableFilter implements AudioFilterInterface
}
/**
*
* @return Integer
* @return int
*/
public function getRate()
{
@ -49,6 +48,6 @@ class AudioResamplableFilter implements AudioFilterInterface
*/
public function apply(Audio $audio, AudioInterface $format)
{
return array('-ac', 2, '-ar', $this->rate);
return ['-ac', 2, '-ar', $this->rate];
}
}

View file

@ -8,6 +8,7 @@
* 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;
@ -21,7 +22,7 @@ class CustomFilter implements AudioFilterInterface
private $priority;
/**
* A custom filter, useful if you want to build complex filters
* A custom filter, useful if you want to build complex filters.
*
* @param string $filter
* @param int $priority
@ -45,7 +46,7 @@ class CustomFilter implements AudioFilterInterface
*/
public function apply(Audio $audio, AudioInterface $format)
{
$commands = array('-af', $this->filter);
$commands = ['-af', $this->filter];
return $commands;
}

View file

@ -11,8 +11,8 @@
namespace FFMpeg\Filters\Audio;
use FFMpeg\Media\Audio;
use FFMpeg\Format\AudioInterface;
use FFMpeg\Media\Audio;
class SimpleFilter implements AudioFilterInterface
{

View file

@ -11,20 +11,20 @@
namespace FFMpeg\Filters;
use Traversable;
class FiltersCollection implements \Countable, \IteratorAggregate
{
private $sorted;
private $filters = array();
private $filters = [];
/**
* @param FilterInterface $filter
*
* @return FiltersCollection
*/
public function add(FilterInterface $filter)
{
$this->filters[$filter->getPriority()][] = $filter;
$this->sorted = null;
$this->sorted = null;
return $this;
}
@ -32,8 +32,7 @@ class FiltersCollection implements \Countable, \IteratorAggregate
/**
* {@inheritdoc}
*/
#[\ReturnTypeWillChange]
public function count()
public function count(): int
{
if (0 === count($this->filters)) {
return 0;
@ -45,8 +44,7 @@ class FiltersCollection implements \Countable, \IteratorAggregate
/**
* {@inheritdoc}
*/
#[\ReturnTypeWillChange]
public function getIterator()
public function getIterator(): Traversable
{
if (null === $this->sorted) {
if (0 === count($this->filters)) {

View file

@ -11,7 +11,6 @@
namespace FFMpeg\Filters\Frame;
use FFMpeg\Exception\RuntimeException;
use FFMpeg\Media\Frame;
class CustomFrameFilter implements FrameFilterInterface
@ -22,7 +21,7 @@ class CustomFrameFilter implements FrameFilterInterface
private $priority;
/**
* A custom filter, useful if you want to build complex filters
* A custom filter, useful if you want to build complex filters.
*
* @param string $filter
* @param int $priority
@ -46,9 +45,8 @@ class CustomFrameFilter implements FrameFilterInterface
*/
public function apply(Frame $frame)
{
$commands = array('-vf', $this->filter);
$commands = ['-vf', $this->filter];
return $commands;
}
}

View file

@ -38,17 +38,16 @@ class DisplayRatioFixerFilter implements FrameFilterInterface
public function apply(Frame $frame)
{
$dimensions = null;
$commands = array();
$commands = [];
foreach ($frame->getVideo()->getStreams() as $stream) {
if ($stream->isVideo()) {
try {
$dimensions = $stream->getDimensions();
$commands[] = '-s';
$commands[] = $dimensions->getWidth() . 'x' . $dimensions->getHeight();
$commands[] = $dimensions->getWidth().'x'.$dimensions->getHeight();
break;
} catch (RuntimeException $e) {
}
}
}

View file

@ -38,9 +38,9 @@ class FrameFilters
}
/**
* Applies a custom filter: -vf foo bar
* Applies a custom filter: -vf foo bar.
*
* @param string $parameters
* @param string $parameters
*
* @return FrameFilters
*/

View file

@ -11,9 +11,9 @@
namespace FFMpeg\Filters\Video;
use FFMpeg\Coordinate\TimeCode;
use FFMpeg\Format\VideoInterface;
use FFMpeg\Media\Video;
use FFMpeg\Coordinate\TimeCode;
class ClipFilter implements VideoFilterInterface
{
@ -60,11 +60,11 @@ class ClipFilter implements VideoFilterInterface
*/
public function apply(Video $video, VideoInterface $format)
{
$commands = array('-ss', (string) $this->start);
$commands = ['-ss', (string) $this->start];
if ($this->duration !== null) {
$commands[] = '-t';
$commands[] = (string) $this->duration;
if (null !== $this->duration) {
$commands[] = '-t';
$commands[] = (string) $this->duration;
}
return $commands;

View file

@ -1,4 +1,5 @@
<?php
/*
* This file is part of PHP-FFmpeg.
*
@ -51,10 +52,10 @@ class CropFilter implements VideoFilterInterface
}
}
return array(
return [
'-filter:v',
'crop=' .
$this->dimension->getWidth() .':' . $this->dimension->getHeight() . ':' . $this->point->getX() . ':' . $this->point->getY()
);
'crop='.
$this->dimension->getWidth().':'.$this->dimension->getHeight().':'.$this->point->getX().':'.$this->point->getY(),
];
}
}

View file

@ -8,6 +8,7 @@
* 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;
@ -21,7 +22,7 @@ class CustomFilter implements VideoFilterInterface
private $priority;
/**
* A custom filter, useful if you want to build complex filters
* A custom filter, useful if you want to build complex filters.
*
* @param string $filter
* @param int $priority
@ -45,7 +46,7 @@ class CustomFilter implements VideoFilterInterface
*/
public function apply(Video $video, VideoInterface $format)
{
$commands = array('-vf', $this->filter);
$commands = ['-vf', $this->filter];
return $commands;
}

View file

@ -13,25 +13,25 @@ namespace FFMpeg\Filters\Video;
use FFMpeg\Exception\InvalidArgumentException;
use FFMpeg\Exception\RuntimeException;
use FFMpeg\Media\Video;
use FFMpeg\Format\VideoInterface;
use FFMpeg\Media\Video;
class ExtractMultipleFramesFilter implements VideoFilterInterface
{
/** will extract a frame every second */
const FRAMERATE_EVERY_SEC = '1/1';
public const FRAMERATE_EVERY_SEC = '1/1';
/** will extract a frame every 2 seconds */
const FRAMERATE_EVERY_2SEC = '1/2';
public const FRAMERATE_EVERY_2SEC = '1/2';
/** will extract a frame every 5 seconds */
const FRAMERATE_EVERY_5SEC = '1/5';
public const FRAMERATE_EVERY_5SEC = '1/5';
/** will extract a frame every 10 seconds */
const FRAMERATE_EVERY_10SEC = '1/10';
public const FRAMERATE_EVERY_10SEC = '1/10';
/** will extract a frame every 30 seconds */
const FRAMERATE_EVERY_30SEC = '1/30';
public const FRAMERATE_EVERY_30SEC = '1/30';
/** will extract a frame every minute */
const FRAMERATE_EVERY_60SEC = '1/60';
public const FRAMERATE_EVERY_60SEC = '1/60';
/** @var integer */
/** @var int */
private $priority;
private $frameRate;
private $destinationFolder;
@ -46,25 +46,30 @@ class ExtractMultipleFramesFilter implements VideoFilterInterface
$this->frameRate = $frameRate;
// Make sure that the destination folder has a trailing slash
if(strcmp( substr($destinationFolder, -1), "/") != 0)
$destinationFolder .= "/";
if (0 != strcmp(substr($destinationFolder, -1), '/')) {
$destinationFolder .= '/';
}
// Set the destination folder
$this->destinationFolder = $destinationFolder;
}
/**
* @param string $frameFileType
* @throws \FFMpeg\Exception\InvalidArgumentException
* @return ExtractMultipleFramesFilter
*/
public function setFrameFileType($frameFileType) {
if (in_array($frameFileType, self::$supportedFrameFileTypes)) {
$this->frameFileType = $frameFileType;
return $this;
}
/**
* @param string $frameFileType
*
* @throws \FFMpeg\Exception\InvalidArgumentException
*
* @return ExtractMultipleFramesFilter
*/
public function setFrameFileType($frameFileType)
{
if (in_array($frameFileType, self::$supportedFrameFileTypes)) {
$this->frameFileType = $frameFileType;
throw new InvalidArgumentException('Invalid frame file type, use: ' . implode(',', self::$supportedFrameFileTypes));
return $this;
}
throw new InvalidArgumentException('Invalid frame file type, use: '.implode(',', self::$supportedFrameFileTypes));
}
/**
@ -96,7 +101,7 @@ class ExtractMultipleFramesFilter implements VideoFilterInterface
*/
public function apply(Video $video, VideoInterface $format)
{
$commands = array();
$commands = [];
$duration = 0;
try {
@ -108,37 +113,37 @@ class ExtractMultipleFramesFilter implements VideoFilterInterface
}
// Get the number of frames per second we have to extract.
if(preg_match('/(\d+)(?:\s*)([\+\-\*\/])(?:\s*)(\d+)/', $this->frameRate, $matches) !== FALSE){
if (false !== preg_match('/(\d+)(?:\s*)([\+\-\*\/])(?:\s*)(\d+)/', $this->frameRate, $matches)) {
$operator = $matches[2];
switch($operator){
switch ($operator) {
case '/':
$nbFramesPerSecond = $matches[1] / $matches[3];
break;
default:
throw new InvalidArgumentException('The frame rate is not a proper division: ' . $this->frameRate);
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 );
$nbImages = ceil($duration * $nbFramesPerSecond);
if($nbImages < 100)
$nbDigitsInFileNames = "02";
elseif($nbImages < 1000)
$nbDigitsInFileNames = "03";
else
$nbDigitsInFileNames = "06";
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.' . $this->frameFileType;
}
catch (RuntimeException $e) {
throw new RuntimeException('An error occured while extracting the frames: ' . $e->getMessage() . '. The code: ' . $e->getCode());
$commands[] = 'fps='.$this->frameRate;
$commands[] = $this->destinationFolder.'frame-%'.$nbDigitsInFileNames.'d.'.$this->frameFileType;
} catch (RuntimeException $e) {
throw new RuntimeException('An error occured while extracting the frames: '.$e->getMessage().'. The code: '.$e->getCode());
}
return $commands;

View file

@ -12,8 +12,8 @@
namespace FFMpeg\Filters\Video;
use FFMpeg\Coordinate\FrameRate;
use FFMpeg\Media\Video;
use FFMpeg\Format\VideoInterface;
use FFMpeg\Media\Video;
class FrameRateFilter implements VideoFilterInterface
{
@ -51,7 +51,7 @@ class FrameRateFilter implements VideoFilterInterface
*
* @see https://wikipedia.org/wiki/Group_of_pictures
*
* @return Integer
* @return int
*/
public function getGOP()
{
@ -63,9 +63,9 @@ class FrameRateFilter implements VideoFilterInterface
*/
public function apply(Video $video, VideoInterface $format)
{
$commands = array('-r', $this->rate->getValue());
$commands = ['-r', $this->rate->getValue()];
/**
/*
* @see http://sites.google.com/site/linuxencoding/x264-ffmpeg-mapping
*/
if ($format->supportBFrames()) {

View file

@ -87,13 +87,13 @@ class PadFilter implements VideoFilterInterface, ComplexCompatibleFilter
*/
protected function getCommands()
{
$commands = array();
$commands = [];
$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';
$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;
}

View file

@ -13,19 +13,19 @@ namespace FFMpeg\Filters\Video;
use FFMpeg\Coordinate\Dimension;
use FFMpeg\Exception\RuntimeException;
use FFMpeg\Media\Video;
use FFMpeg\Format\VideoInterface;
use FFMpeg\Media\Video;
class ResizeFilter implements VideoFilterInterface
{
/** fits to the dimensions, might introduce anamorphosis */
const RESIZEMODE_FIT = 'fit';
public const RESIZEMODE_FIT = 'fit';
/** resizes the video inside the given dimension, no anamorphosis */
const RESIZEMODE_INSET = 'inset';
public const RESIZEMODE_INSET = 'inset';
/** resizes the video to fit the dimension width, no anamorphosis */
const RESIZEMODE_SCALE_WIDTH = 'width';
public const RESIZEMODE_SCALE_WIDTH = 'width';
/** resizes the video to fit the dimension height, no anamorphosis */
const RESIZEMODE_SCALE_HEIGHT = 'height';
public const RESIZEMODE_SCALE_HEIGHT = 'height';
/** @var Dimension */
private $dimension;
@ -82,7 +82,7 @@ class ResizeFilter implements VideoFilterInterface
public function apply(Video $video, VideoInterface $format)
{
$dimensions = null;
$commands = array();
$commands = [];
foreach ($video->getStreams() as $stream) {
if ($stream->isVideo()) {
@ -90,7 +90,6 @@ class ResizeFilter implements VideoFilterInterface
$dimensions = $stream->getDimensions();
break;
} catch (RuntimeException $e) {
}
}
}
@ -100,8 +99,7 @@ class ResizeFilter implements VideoFilterInterface
// Using Filter to have ordering
$commands[] = '-vf';
$commands[] = '[in]scale=' . $dimensions->getWidth() . ':' . $dimensions->getHeight() . ' [out]';
$commands[] = '[in]scale='.$dimensions->getWidth().':'.$dimensions->getHeight().' [out]';
}
return $commands;

View file

@ -13,14 +13,14 @@ namespace FFMpeg\Filters\Video;
use FFMpeg\Coordinate\Dimension;
use FFMpeg\Exception\InvalidArgumentException;
use FFMpeg\Media\Video;
use FFMpeg\Format\VideoInterface;
use FFMpeg\Media\Video;
class RotateFilter implements VideoFilterInterface
{
const ROTATE_90 = 'transpose=1';
const ROTATE_180 = 'hflip,vflip';
const ROTATE_270 = 'transpose=2';
public const ROTATE_90 = 'transpose=1';
public const ROTATE_180 = 'hflip,vflip';
public const ROTATE_270 = 'transpose=2';
/** @var string */
private $angle;
@ -54,7 +54,7 @@ class RotateFilter implements VideoFilterInterface
*/
public function apply(Video $video, VideoInterface $format)
{
if (in_array($this->angle, array(self::ROTATE_90, self::ROTATE_270), true)) {
if (in_array($this->angle, [self::ROTATE_90, self::ROTATE_270], true)) {
foreach ($video->getStreams()->videos() as $stream) {
if ($stream->has('width') && $stream->has('height')) {
$width = $stream->get('width');
@ -64,7 +64,7 @@ class RotateFilter implements VideoFilterInterface
}
}
return array('-vf', $this->angle, '-metadata:s:v:0', 'rotate=0');
return ['-vf', $this->angle, '-metadata:s:v:0', 'rotate=0'];
}
private function setAngle($angle)

View file

@ -39,6 +39,6 @@ class SynchronizeFilter implements VideoFilterInterface
*/
public function apply(Video $video, VideoInterface $format)
{
return array('-async', '1', '-metadata:s:v:0', 'start_time=0');
return ['-async', '1', '-metadata:s:v:0', 'start_time=0'];
}
}

View file

@ -20,9 +20,6 @@ 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);

View file

@ -11,13 +11,13 @@
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\Coordinate\Point;
use FFMpeg\Coordinate\TimeCode;
use FFMpeg\Filters\Audio\AudioFilters;
use FFMpeg\Filters\Audio\AudioResamplableFilter;
use FFMpeg\Media\Video;
class VideoFilters extends AudioFilters
{
@ -29,8 +29,7 @@ class VideoFilters extends AudioFilters
/**
* Resizes a video to a given dimension.
*
* @param Dimension $dimension
* @param string $mode
* @param string $mode
* @param bool $forceStandards
*
* @return VideoFilters
@ -45,8 +44,7 @@ class VideoFilters extends AudioFilters
/**
* Changes the video framerate.
*
* @param FrameRate $framerate
* @param Integer $gop
* @param int $gop
*
* @return VideoFilters
*/
@ -58,10 +56,10 @@ class VideoFilters extends AudioFilters
}
/**
* Extract multiple frames from the video
* Extract multiple frames from the video.
*
* @param string $frameRate
* @param string $destinationFolder
* @param string $destinationFolder
*
* @return $this
*/
@ -102,7 +100,7 @@ class VideoFilters extends AudioFilters
/**
* Resamples the audio file.
*
* @param Integer $rate
* @param int $rate
*
* @return AudioFilters
*/
@ -116,8 +114,6 @@ class VideoFilters extends AudioFilters
/**
* Adds padding (black bars) to a video.
*
* @param Dimension $dimension
*
* @return VideoFilters
*/
public function pad(Dimension $dimension)
@ -135,10 +131,7 @@ class VideoFilters extends AudioFilters
}
/**
* Crops the video
*
* @param Point $point
* @param Dimension $dimension
* Crops the video.
*
* @return VideoFilters
*/
@ -151,11 +144,10 @@ class VideoFilters extends AudioFilters
/**
* @param string $imagePath
* @param array $coordinates
*
* @return $this
*/
public function watermark($imagePath, array $coordinates = array())
public function watermark($imagePath, array $coordinates = [])
{
$this->media->addFilter(new WatermarkFilter($imagePath, $coordinates));
@ -163,9 +155,9 @@ class VideoFilters extends AudioFilters
}
/**
* Applies a custom filter: -vf foo bar
* Applies a custom filter: -vf foo bar.
*
* @param string $parameters
* @param string $parameters
*
* @return VideoFilters
*/

View file

@ -26,7 +26,7 @@ class WatermarkFilter implements VideoFilterInterface, ComplexCompatibleFilter
/** @var int */
private $priority;
public function __construct($watermarkPath, array $coordinates = array(), $priority = 0)
public function __construct($watermarkPath, array $coordinates = [], $priority = 0)
{
if (!file_exists($watermarkPath)) {
throw new InvalidArgumentException(sprintf('File %s does not exist', $watermarkPath));
@ -93,7 +93,7 @@ class WatermarkFilter implements VideoFilterInterface, ComplexCompatibleFilter
if (isset($this->coordinates['top'])) {
$y = $this->coordinates['top'];
} elseif (isset($this->coordinates['bottom'])) {
$y = 'main_h - ' . $this->coordinates['bottom'] . ' - overlay_h';
$y = 'main_h - '.$this->coordinates['bottom'].' - overlay_h';
} else {
$y = 0;
}
@ -101,7 +101,7 @@ class WatermarkFilter implements VideoFilterInterface, ComplexCompatibleFilter
if (isset($this->coordinates['left'])) {
$x = $this->coordinates['left'];
} elseif (isset($this->coordinates['right'])) {
$x = 'main_w - ' . $this->coordinates['right'] . ' - overlay_w';
$x = 'main_w - '.$this->coordinates['right'].' - overlay_w';
} else {
$x = 0;
}
@ -113,9 +113,9 @@ class WatermarkFilter implements VideoFilterInterface, ComplexCompatibleFilter
break;
}
return array(
return [
'-vf',
'movie=' . $this->watermarkPath . ' [watermark]; [in][watermark] overlay=' . $x . ':' . $y . ' [out]',
);
'movie='.$this->watermarkPath.' [watermark]; [in][watermark] overlay='.$x.':'.$y.' [out]',
];
}
}

View file

@ -16,14 +16,13 @@ use FFMpeg\Media\Waveform;
class WaveformDownmixFilter implements WaveformFilterInterface
{
/** @var bool */
private $downmix;
/** @var int */
private $priority;
// By default, the downmix value is set to FALSE.
public function __construct($downmix = FALSE, $priority = 0)
public function __construct($downmix = false, $priority = 0)
{
$this->downmix = $downmix;
$this->priority = $priority;
@ -50,21 +49,18 @@ class WaveformDownmixFilter implements WaveformFilterInterface
*/
public function apply(Waveform $waveform)
{
$commands = array();
$commands = [];
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) {
if (true == $this->downmix) {
$commands[] = '"aformat=channel_layouts=mono"';
}
break;
} catch (RuntimeException $e) {
}
}
}

View file

@ -12,7 +12,7 @@
namespace FFMpeg\Format\Audio;
/**
* The AAC audio format
* The AAC audio format.
*/
class Aac extends DefaultAudio
{
@ -26,6 +26,6 @@ class Aac extends DefaultAudio
*/
public function getAvailableAudioCodecs()
{
return array('libfdk_aac');
return ['libfdk_aac'];
}
}

View file

@ -13,11 +13,11 @@ namespace FFMpeg\Format\Audio;
use Evenement\EventEmitter;
use FFMpeg\Exception\InvalidArgumentException;
use FFMpeg\FFProbe;
use FFMpeg\Format\AudioInterface;
use FFMpeg\Media\MediaTypeInterface;
use FFMpeg\Format\ProgressableInterface;
use FFMpeg\Format\ProgressListener\AudioProgressListener;
use FFMpeg\FFProbe;
use FFMpeg\Media\MediaTypeInterface;
abstract class DefaultAudio extends EventEmitter implements AudioInterface, ProgressableInterface
{
@ -35,7 +35,7 @@ abstract class DefaultAudio extends EventEmitter implements AudioInterface, Prog
*/
public function getExtraParams()
{
return array();
return [];
}
/**
@ -56,11 +56,8 @@ abstract class DefaultAudio extends EventEmitter implements AudioInterface, Prog
*/
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())
));
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;
@ -79,7 +76,8 @@ abstract class DefaultAudio extends EventEmitter implements AudioInterface, Prog
/**
* Sets the kiloBitrate value.
*
* @param int $kiloBitrate
* @param int $kiloBitrate
*
* @throws InvalidArgumentException
*/
public function setAudioKiloBitrate($kiloBitrate)
@ -94,8 +92,8 @@ abstract class DefaultAudio extends EventEmitter implements AudioInterface, Prog
}
/**
* {@inheritdoc}
*/
* {@inheritdoc}
*/
public function getAudioChannels()
{
return $this->audioChannels;
@ -104,7 +102,8 @@ abstract class DefaultAudio extends EventEmitter implements AudioInterface, Prog
/**
* Sets the channels value.
*
* @param int $channels
* @param int $channels
*
* @throws InvalidArgumentException
*/
public function setAudioChannels($channels)
@ -126,10 +125,10 @@ abstract class DefaultAudio extends EventEmitter implements AudioInterface, Prog
$format = $this;
$listener = new AudioProgressListener($ffprobe, $media->getPathfile(), $pass, $total, $duration);
$listener->on('progress', function () use ($media, $format) {
$format->emit('progress', array_merge(array($media, $format), func_get_args()));
$format->emit('progress', array_merge([$media, $format], func_get_args()));
});
return array($listener);
return [$listener];
}
/**

View file

@ -12,7 +12,7 @@
namespace FFMpeg\Format\Audio;
/**
* The Flac audio format
* The Flac audio format.
*/
class Flac extends DefaultAudio
{
@ -26,6 +26,6 @@ class Flac extends DefaultAudio
*/
public function getAvailableAudioCodecs()
{
return array('flac');
return ['flac'];
}
}

View file

@ -12,7 +12,7 @@
namespace FFMpeg\Format\Audio;
/**
* The MP3 audio format
* The MP3 audio format.
*/
class Mp3 extends DefaultAudio
{
@ -26,6 +26,6 @@ class Mp3 extends DefaultAudio
*/
public function getAvailableAudioCodecs()
{
return array('libmp3lame');
return ['libmp3lame'];
}
}

View file

@ -12,7 +12,7 @@
namespace FFMpeg\Format\Audio;
/**
* The Vorbis audio format
* The Vorbis audio format.
*/
class Vorbis extends DefaultAudio
{
@ -26,7 +26,7 @@ class Vorbis extends DefaultAudio
*/
public function getExtraParams()
{
return array('-strict', '-2');
return ['-strict', '-2'];
}
/**
@ -34,6 +34,6 @@ class Vorbis extends DefaultAudio
*/
public function getAvailableAudioCodecs()
{
return array('vorbis');
return ['vorbis'];
}
}

View file

@ -12,7 +12,7 @@
namespace FFMpeg\Format\Audio;
/**
* The WAV audio format
* The WAV audio format.
*/
class Wav extends DefaultAudio
{
@ -26,6 +26,6 @@ class Wav extends DefaultAudio
*/
public function getAvailableAudioCodecs()
{
return array('pcm_s16le');
return ['pcm_s16le'];
}
}

View file

@ -8,6 +8,7 @@
* 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

View file

@ -8,6 +8,7 @@
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace FFMpeg\Format;
interface FormatInterface

View file

@ -13,8 +13,8 @@ namespace FFMpeg\Format\ProgressListener;
use Alchemy\BinaryDriver\Listeners\ListenerInterface;
use Evenement\EventEmitter;
use FFMpeg\FFProbe;
use FFMpeg\Exception\RuntimeException;
use FFMpeg\FFProbe;
/**
* @author Robert Gruendler <r.gruendler@gmail.com>
@ -33,7 +33,7 @@ abstract class AbstractProgressListener extends EventEmitter implements Listener
/** @var int */
private $currentTime;
/** @var double */
/** @var float */
private $lastOutput = null;
/** @var FFProbe */
@ -52,32 +52,31 @@ abstract class AbstractProgressListener extends EventEmitter implements Listener
private $totalPass;
/**
* Transcoding rate in kb/s
* Transcoding rate in kb/s.
*
* @var int
*/
private $rate;
/**
* Percentage of transcoding progress (0 - 100)
* Percentage of transcoding progress (0 - 100).
*
* @var int
*/
private $percent = 0;
/**
* Time remaining (seconds)
* Time remaining (seconds).
*
* @var int
*/
private $remaining = null;
/**
* @param FFProbe $ffprobe
* @param string $pathfile
* @param int $currentPass The current pass number
* @param int $totalPass The total number of passes
* @param int $duration
* @param int $currentPass The current pass number
* @param int $totalPass The total number of passes
* @param int $duration
*/
public function __construct(FFProbe $ffprobe, $pathfile, $currentPass, $totalPass, $duration = 0)
{
@ -143,18 +142,18 @@ abstract class AbstractProgressListener extends EventEmitter implements Listener
*/
public function forwardedEvents()
{
return array();
return [];
}
/**
* Get the regex pattern to match a ffmpeg stderr status line
* 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.
* @return array the progressinfo array or null if there's no progress available yet
*/
private function parseProgress($progress)
{
@ -166,9 +165,9 @@ abstract class AbstractProgressListener extends EventEmitter implements Listener
return;
}
$matches = array();
$matches = [];
if (preg_match($this->getPattern(), $progress, $matches) !== 1) {
if (1 !== preg_match($this->getPattern(), $progress, $matches)) {
return null;
}
@ -177,12 +176,12 @@ abstract class AbstractProgressListener extends EventEmitter implements Listener
$currentSize = trim(str_replace('kb', '', strtolower(($matches[1]))));
$percent = max(0, min(1, $currentDuration / $this->duration));
if ($this->lastOutput !== null) {
if (null !== $this->lastOutput) {
$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;
if (!is_numeric($currentSize)) {
$currentSize = (int) $currentSize;
}
$deltaSize = $currentSize - $this->currentSize;
@ -208,13 +207,13 @@ abstract class AbstractProgressListener extends EventEmitter implements Listener
}
/**
* @param string $rawDuration in the format 00:00:00.00
*
* @param string $rawDuration in the format 00:00:00.00
* @return number
*/
private function convertDuration($rawDuration)
{
$ar = array_reverse(explode(":", $rawDuration));
$ar = array_reverse(explode(':', $rawDuration));
$duration = floatval($ar[0]);
if (!empty($ar[1])) {
$duration += intval($ar[1]) * 60;
@ -231,15 +230,15 @@ abstract class AbstractProgressListener extends EventEmitter implements Listener
*/
private function getProgressInfo()
{
if ($this->remaining === null) {
if (null === $this->remaining) {
return null;
}
return array(
'percent' => $this->percent,
return [
'percent' => $this->percent,
'remaining' => $this->remaining,
'rate' => $this->rate
);
'rate' => $this->rate,
];
}
private function initialize()

View file

@ -12,7 +12,7 @@
namespace FFMpeg\Format\ProgressListener;
/**
* Parses ffmpeg stderr progress information. An example:
* Parses ffmpeg stderr progress information. An example:.
*
* <pre>
* size= 3552kB time=00:03:47.29 bitrate= 128.0kbits/s

View file

@ -12,7 +12,7 @@
namespace FFMpeg\Format\ProgressListener;
/**
* Parses ffmpeg stderr progress information for video files. An example:
* 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

View file

@ -20,11 +20,9 @@ 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
* @param Integer $duration The new video duration
* @param int $pass The current pas snumber
* @param int $total The total pass number
* @param int $duration The new video duration
*
* @return array An array of listeners
*/

View file

@ -11,31 +11,31 @@
namespace FFMpeg\Format\Video;
use FFMpeg\FFProbe;
use FFMpeg\Exception\InvalidArgumentException;
use FFMpeg\FFProbe;
use FFMpeg\Format\Audio\DefaultAudio;
use FFMpeg\Format\ProgressListener\VideoProgressListener;
use FFMpeg\Format\VideoInterface;
use FFMpeg\Media\MediaTypeInterface;
use FFMpeg\Format\ProgressListener\VideoProgressListener;
/**
* The abstract default Video format
* The abstract default Video format.
*/
abstract class DefaultVideo extends DefaultAudio implements VideoInterface
{
/** @var string */
protected $videoCodec;
/** @var Integer */
/** @var int */
protected $kiloBitrate = 1000;
/** @var Integer */
/** @var int */
protected $modulus = 16;
/** @var Array */
/** @var array */
protected $additionalParamaters;
/** @var Array */
/** @var array */
protected $initialParamaters;
/**
@ -49,7 +49,8 @@ abstract class DefaultVideo extends DefaultAudio implements VideoInterface
/**
* Sets the kiloBitrate value.
*
* @param int $kiloBitrate
* @param int $kiloBitrate
*
* @throws InvalidArgumentException
*/
public function setKiloBitrate($kiloBitrate)
@ -75,16 +76,14 @@ abstract class DefaultVideo extends DefaultAudio implements VideoInterface
* Sets the video codec, Should be in the available ones, otherwise an
* exception is thrown.
*
* @param string $videoCodec
* @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())
));
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;
@ -111,7 +110,8 @@ abstract class DefaultVideo extends DefaultAudio implements VideoInterface
/**
* Sets additional parameters.
*
* @param array $additionalParamaters
* @param array $additionalParamaters
*
* @throws InvalidArgumentException
*/
public function setAdditionalParameters($additionalParamaters)
@ -136,7 +136,8 @@ abstract class DefaultVideo extends DefaultAudio implements VideoInterface
/**
* Sets initial parameters.
*
* @param array $initialParamaters
* @param array $initialParamaters
*
* @throws InvalidArgumentException
*/
public function setInitialParameters($initialParamaters)
@ -156,11 +157,11 @@ abstract class DefaultVideo extends DefaultAudio implements VideoInterface
public function createProgressListener(MediaTypeInterface $media, FFProbe $ffprobe, $pass, $total, $duration = 0)
{
$format = $this;
$listeners = array(new VideoProgressListener($ffprobe, $media->getPathfile(), $pass, $total, $duration));
$listeners = [new VideoProgressListener($ffprobe, $media->getPathfile(), $pass, $total, $duration)];
foreach ($listeners as $listener) {
$listener->on('progress', function () use ($format, $media) {
$format->emit('progress', array_merge(array($media, $format), func_get_args()));
$format->emit('progress', array_merge([$media, $format], func_get_args()));
});
}

View file

@ -12,7 +12,7 @@
namespace FFMpeg\Format\Video;
/**
* The Ogg video format
* The Ogg video format.
*/
class Ogg extends DefaultVideo
{
@ -36,7 +36,7 @@ class Ogg extends DefaultVideo
*/
public function getAvailableAudioCodecs()
{
return array('libvorbis');
return ['libvorbis'];
}
/**
@ -44,6 +44,6 @@ class Ogg extends DefaultVideo
*/
public function getAvailableVideoCodecs()
{
return array('libtheora');
return ['libtheora'];
}
}

View file

@ -12,7 +12,7 @@
namespace FFMpeg\Format\Video;
/**
* The WMV video format
* The WMV video format.
*/
class WMV extends DefaultVideo
{
@ -36,7 +36,7 @@ class WMV extends DefaultVideo
*/
public function getAvailableAudioCodecs()
{
return array('wmav2');
return ['wmav2'];
}
/**
@ -44,6 +44,6 @@ class WMV extends DefaultVideo
*/
public function getAvailableVideoCodecs()
{
return array('wmv2');
return ['wmv2'];
}
}

View file

@ -12,7 +12,7 @@
namespace FFMpeg\Format\Video;
/**
* The WMV video format
* The WMV video format.
*/
class WMV3 extends DefaultVideo
{
@ -36,7 +36,7 @@ class WMV3 extends DefaultVideo
*/
public function getAvailableAudioCodecs()
{
return array('wmav3');
return ['wmav3'];
}
/**
@ -44,6 +44,6 @@ class WMV3 extends DefaultVideo
*/
public function getAvailableVideoCodecs()
{
return array('wmv3');
return ['wmv3'];
}
}

View file

@ -12,7 +12,7 @@
namespace FFMpeg\Format\Video;
/**
* The WebM video format
* The WebM video format.
*/
class WebM extends DefaultVideo
{
@ -36,7 +36,7 @@ class WebM extends DefaultVideo
*/
public function getExtraParams()
{
return array('-f', 'webm');
return ['-f', 'webm'];
}
/**
@ -44,7 +44,7 @@ class WebM extends DefaultVideo
*/
public function getAvailableAudioCodecs()
{
return array('copy', 'libvorbis');
return ['copy', 'libvorbis'];
}
/**
@ -52,6 +52,6 @@ class WebM extends DefaultVideo
*/
public function getAvailableVideoCodecs()
{
return array('libvpx', 'libvpx-vp9');
return ['libvpx', 'libvpx-vp9'];
}
}

View file

@ -12,7 +12,7 @@
namespace FFMpeg\Format\Video;
/**
* The X264 video format
* The X264 video format.
*/
class X264 extends DefaultVideo
{
@ -54,7 +54,7 @@ class X264 extends DefaultVideo
*/
public function getAvailableAudioCodecs()
{
return array('copy', 'aac', 'libvo_aacenc', 'libfaac', 'libmp3lame', 'libfdk_aac');
return ['copy', 'aac', 'libvo_aacenc', 'libfaac', 'libmp3lame', 'libfdk_aac'];
}
/**
@ -62,7 +62,7 @@ class X264 extends DefaultVideo
*/
public function getAvailableVideoCodecs()
{
return array('libx264');
return ['libx264'];
}
/**
@ -73,6 +73,7 @@ class X264 extends DefaultVideo
public function setPasses($passes)
{
$this->passes = $passes;
return $this;
}
@ -81,7 +82,7 @@ class X264 extends DefaultVideo
*/
public function getPasses()
{
return $this->getKiloBitrate() === 0 ? 1 : $this->passes;
return 0 === $this->getKiloBitrate() ? 1 : $this->passes;
}
/**

View file

@ -63,7 +63,7 @@ interface VideoInterface extends AudioInterface
public function getAdditionalParameters();
/**
* Returns the list of initial parameters for this format
* Returns the list of initial parameters for this format.
*
* @return array
*/

View file

@ -43,8 +43,6 @@ abstract class AbstractMediaType implements MediaTypeInterface
}
/**
* @param FFMpegDriver $driver
*
* @return MediaTypeInterface
*/
public function setFFMpegDriver(FFMpegDriver $driver)
@ -63,8 +61,6 @@ abstract class AbstractMediaType implements MediaTypeInterface
}
/**
* @param FFProbe $ffprobe
*
* @return MediaTypeInterface
*/
public function setFFProbe(FFProbe $ffprobe)
@ -83,8 +79,6 @@ abstract class AbstractMediaType implements MediaTypeInterface
}
/**
* @param FiltersCollection $filters
*
* @return MediaTypeInterface
*/
public function setFiltersCollection(FiltersCollection $filters)

View file

@ -1,4 +1,5 @@
<?php
/*
* This file is part of PHP-FFmpeg.
*
@ -7,38 +8,41 @@
* 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\SimpleFilter;
use FFMpeg\Exception\InvalidArgumentException;
use FFMpeg\Exception\RuntimeException;
use FFMpeg\Filters\Video\VideoFilters;
use FFMpeg\Filters\Audio\SimpleFilter;
use FFMpeg\Filters\FilterInterface;
use FFMpeg\Filters\Video\ClipFilter;
use FFMpeg\Filters\Video\VideoFilters;
use FFMpeg\Format\AudioInterface;
use FFMpeg\Format\FormatInterface;
use FFMpeg\Format\ProgressableInterface;
use FFMpeg\Format\AudioInterface;
use FFMpeg\Format\VideoInterface;
use Neutron\TemporaryFilesystem\Manager as FsManager;
use FFMpeg\Filters\Video\ClipFilter;
use Spatie\TemporaryDirectory\TemporaryDirectory;
abstract class AbstractVideo extends Audio
{
/**
* FileSystem Manager instance
* FileSystem Manager instance.
*
* @var Manager
*/
protected $fs;
/**
* FileSystem Manager ID
* FileSystem Manager ID.
*
* @var int
*/
protected $fsId;
/**
* @inheritDoc
* {@inheritDoc}
*
* @return VideoFilters
*/
public function filters()
@ -47,7 +51,8 @@ abstract class AbstractVideo extends Audio
}
/**
* @inheritDoc
* {@inheritDoc}
*
* @return Video
*/
public function addFilter(FilterInterface $filter)
@ -60,9 +65,10 @@ abstract class AbstractVideo extends Audio
/**
* Exports the video in the desired format, applies registered filters.
*
* @param FormatInterface $format
* @param string $outputPathfile
* @param string $outputPathfile
*
* @return Video
*
* @throws RuntimeException
*/
public function save(FormatInterface $format, $outputPathfile)
@ -86,10 +92,10 @@ abstract class AbstractVideo extends Audio
// FFMpeg\Format\ProgressListener\AbstractProgressListener class
foreach ($filters as $filter) {
if ($filter instanceof ClipFilter) {
if ($filter->getDuration() === NULL) {
if (null === $filter->getDuration()) {
continue;
}
$duration = $filter->getDuration()->toSeconds();
break;
}
@ -104,7 +110,7 @@ abstract class AbstractVideo extends Audio
}
}
$this->fs->clean($this->fsId);
$this->fs->delete();
if (null !== $failure) {
throw new RuntimeException('Encoding failed', $failure->getCode(), $failure);
@ -115,17 +121,17 @@ abstract class AbstractVideo extends Audio
/**
* NOTE: This method is different to the Audio's one, because Video is using passes.
* @inheritDoc
* {@inheritDoc}
*/
public function getFinalCommand(FormatInterface $format, $outputPathfile)
{
$finalCommands = array();
$finalCommands = [];
foreach ($this->buildCommand($format, $outputPathfile) as $pass => $passCommands) {
$finalCommands[] = implode(' ', $passCommands);
}
$this->fs->clean($this->fsId);
$this->fs->delete();
return $finalCommands;
}
@ -133,7 +139,8 @@ abstract class AbstractVideo extends Audio
/**
* **NOTE:** This creates passes instead of a single command!
*
* @inheritDoc
* {@inheritDoc}
*
* @return string[][]
*/
protected function buildCommand(FormatInterface $format, $outputPathfile)
@ -144,16 +151,16 @@ abstract class AbstractVideo extends Audio
$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'))));
$filters->add(new SimpleFilter(['-threads', $this->driver->getConfiguration()->get('ffmpeg.threads')]));
}
if ($format instanceof VideoInterface) {
if (null !== $format->getVideoCodec()) {
$filters->add(new SimpleFilter(array('-vcodec', $format->getVideoCodec())));
$filters->add(new SimpleFilter(['-vcodec', $format->getVideoCodec()]));
}
}
if ($format instanceof AudioInterface) {
if (null !== $format->getAudioCodec()) {
$filters->add(new SimpleFilter(array('-acodec', $format->getAudioCodec())));
$filters->add(new SimpleFilter(['-acodec', $format->getAudioCodec()]));
}
}
@ -162,9 +169,9 @@ abstract class AbstractVideo extends Audio
}
if ($format instanceof VideoInterface) {
if ($format->getKiloBitrate() !== 0) {
if (0 !== $format->getKiloBitrate()) {
$commands[] = '-b:v';
$commands[] = $format->getKiloBitrate() . 'k';
$commands[] = $format->getKiloBitrate().'k';
}
$commands[] = '-refs';
@ -192,7 +199,7 @@ abstract class AbstractVideo extends Audio
if ($format instanceof AudioInterface) {
if (null !== $format->getAudioKiloBitrate()) {
$commands[] = '-b:a';
$commands[] = $format->getAudioKiloBitrate() . 'k';
$commands[] = $format->getAudioKiloBitrate().'k';
}
if (null !== $format->getAudioChannels()) {
$commands[] = '-ac';
@ -210,12 +217,12 @@ abstract class AbstractVideo extends Audio
}
// Merge Filters into one command
$videoFilterVars = $videoFilterProcesses = array();
for ($i = 0; $i < count($commands); $i++) {
$videoFilterVars = $videoFilterProcesses = [];
for ($i = 0; $i < count($commands); ++$i) {
$command = $commands[$i];
if ($command === '-vf') {
$commandSplits = explode(";", $commands[$i + 1]);
if (count($commandSplits) == 1) {
if ('-vf' === $command) {
$commandSplits = explode(';', $commands[$i + 1]);
if (1 == count($commandSplits)) {
$commandSplit = $commandSplits[0];
$command = trim($commandSplit);
if (preg_match("/^\[in\](.*?)\[out\]$/is", $command, $match)) {
@ -235,19 +242,19 @@ abstract class AbstractVideo extends Audio
}
unset($commands[$i]);
unset($commands[$i + 1]);
$i++;
++$i;
}
}
$videoFilterCommands = $videoFilterVars;
$lastInput = 'in';
foreach ($videoFilterProcesses as $i => $process) {
$command = '[' . $lastInput . ']';
$command = '['.$lastInput.']';
$command .= $process;
$lastInput = 'p' . $i;
$lastInput = 'p'.$i;
if ($i === (count($videoFilterProcesses) - 1)) {
$command .= '[out]';
} else {
$command .= '[' . $lastInput . ']';
$command .= '['.$lastInput.']';
}
$videoFilterCommands[] = $command;
@ -259,17 +266,18 @@ abstract class AbstractVideo extends Audio
$commands[] = $videoFilterCommand;
}
$this->fs = FsManager::create();
$this->fsId = uniqid('ffmpeg-passes');
$passPrefix = $this->fs->createTemporaryDirectory(0777, 50, $this->fsId) . '/' . uniqid('pass-');
$passes = array();
$this->fs = (new TemporaryDirectory($this->fsId))->create();
$passPrefix = $this->fs->path(uniqid('pass-'));
touch($passPrefix);
$passes = [];
$totalPasses = $format->getPasses();
if (!$totalPasses) {
throw new InvalidArgumentException('Pass number should be a positive value.');
}
for ($i = 1; $i <= $totalPasses; $i++) {
for ($i = 1; $i <= $totalPasses; ++$i) {
$pass = $commands;
if ($totalPasses > 1) {
@ -290,12 +298,11 @@ abstract class AbstractVideo extends Audio
/**
* Return base part of command.
*
* @param FormatInterface $format
* @return array
*/
protected function basePartOfCommand(FormatInterface $format)
{
$commands = array('-y');
$commands = ['-y'];
// If the user passed some initial parameters
if ($format instanceof VideoInterface) {

View file

@ -54,9 +54,7 @@ class AdvancedMedia extends AbstractMediaType
/**
* AdvancedMedia constructor.
*
* @param string[] $inputs Array of files to be opened.
* @param FFMpegDriver $driver
* @param FFProbe $ffprobe
* @param string[] $inputs array of files to be opened
*/
public function __construct($inputs, FFMpegDriver $driver, FFProbe $ffprobe)
{
@ -72,10 +70,10 @@ class AdvancedMedia extends AbstractMediaType
parent::__construct($pathfile, $driver, $ffprobe);
$this->filters = new FiltersCollection();
$this->inputs = $inputs;
$this->initialParameters = array();
$this->additionalParameters = array();
$this->mapCommands = array();
$this->listeners = array();
$this->initialParameters = [];
$this->additionalParameters = [];
$this->mapCommands = [];
$this->listeners = [];
}
/**
@ -91,27 +89,26 @@ class AdvancedMedia extends AbstractMediaType
/**
* Add complex filter.
*
* @param string $in
* @param ComplexCompatibleFilter $filter
* @param string $out
* @param string $in
* @param string $out
*
* @return $this
*/
public function addFilter($in, ComplexCompatibleFilter $filter, $out)
{
$this->filters->add(new ComplexFilterContainer($in, $filter, $out));
return $this;
}
/**
* @inheritDoc
* {@inheritDoc}
*/
public function setFiltersCollection(FiltersCollection $filters)
{
foreach ($filters as $filter) {
if (!($filter instanceof ComplexFilterInterface)) {
throw new RuntimeException ('For AdvancedMedia you can set filters collection'
. ' contains only objects that implement ComplexFilterInterface!');
throw new RuntimeException('For AdvancedMedia you can set filters collection'.' contains only objects that implement ComplexFilterInterface!');
}
}
@ -134,6 +131,7 @@ class AdvancedMedia extends AbstractMediaType
public function setInitialParameters(array $initialParameters)
{
$this->initialParameters = $initialParameters;
return $this;
}
@ -153,6 +151,7 @@ class AdvancedMedia extends AbstractMediaType
public function setAdditionalParameters(array $additionalParameters)
{
$this->additionalParameters = $additionalParameters;
return $this;
}
@ -183,13 +182,14 @@ class AdvancedMedia extends AbstractMediaType
/**
* Select the streams for output.
*
* @param string[] $outs Output labels of the -filter_complex part.
* @param FormatInterface $format Format of the output file.
* @param string $outputFilename Output filename.
* @param string[] $outs output labels of the -filter_complex part
* @param FormatInterface $format format of the output file
* @param string $outputFilename output filename
* @param bool $forceDisableAudio
* @param bool $forceDisableVideo
*
* @return $this
*
* @see https://ffmpeg.org/ffmpeg.html#Manual-stream-selection
*/
public function map(
@ -199,15 +199,17 @@ class AdvancedMedia extends AbstractMediaType
$forceDisableAudio = false,
$forceDisableVideo = false
) {
$commands = array();
$commands = [];
foreach ($outs as $label) {
$commands[] = '-map';
$commands[] = $label;
}
// Apply format params.
$commands = array_merge($commands,
$this->applyFormatParams($format, $forceDisableAudio, $forceDisableVideo));
$commands = array_merge(
$commands,
$this->applyFormatParams($format, $forceDisableAudio, $forceDisableVideo)
);
// Set output file.
$commands[] = $outputFilename;
@ -219,6 +221,7 @@ class AdvancedMedia extends AbstractMediaType
}
$this->mapCommands = array_merge($this->mapCommands, $commands);
return $this;
}
@ -226,6 +229,7 @@ class AdvancedMedia extends AbstractMediaType
* Apply added filters and execute ffmpeg command.
*
* @return void
*
* @throws RuntimeException
*/
public function save()
@ -241,9 +245,8 @@ class AdvancedMedia extends AbstractMediaType
}
/**
* @param FormatInterface $format
* @param bool $forceDisableAudio
* @param bool $forceDisableVideo
* @param bool $forceDisableAudio
* @param bool $forceDisableVideo
*
* @return array
*/
@ -253,27 +256,27 @@ class AdvancedMedia extends AbstractMediaType
$forceDisableVideo = false
) {
// Set format params.
$commands = array();
$commands = [];
if (!$forceDisableVideo && $format instanceof VideoInterface) {
if ($format->getVideoCodec() !== null) {
if (null !== $format->getVideoCodec()) {
$commands[] = '-vcodec';
$commands[] = $format->getVideoCodec();
}
// If the user passed some additional format parameters.
if ($format->getAdditionalParameters() !== null) {
if (null !== $format->getAdditionalParameters()) {
$commands = array_merge($commands, $format->getAdditionalParameters());
}
}
if (!$forceDisableAudio && $format instanceof AudioInterface) {
if ($format->getAudioCodec() !== null) {
if (null !== $format->getAudioCodec()) {
$commands[] = '-acodec';
$commands[] = $format->getAudioCodec();
}
if ($format->getAudioKiloBitrate() !== null) {
if (null !== $format->getAudioKiloBitrate()) {
$commands[] = '-b:a';
$commands[] = $format->getAudioKiloBitrate() . 'k';
$commands[] = $format->getAudioKiloBitrate().'k';
}
if ($format->getAudioChannels() !== null) {
if (null !== $format->getAudioChannels()) {
$commands[] = '-ac';
$commands[] = $format->getAudioChannels();
}
@ -288,8 +291,6 @@ class AdvancedMedia extends AbstractMediaType
}
/**
* @param ComplexFilterInterface $filter
*
* @return string
*/
private function applyComplexFilter(ComplexFilterInterface $filter)
@ -297,8 +298,8 @@ class AdvancedMedia extends AbstractMediaType
/** @var $format VideoInterface */
$filterCommands = $filter->applyComplex($this);
foreach ($filterCommands as $index => $command) {
if ($command === '-vf' || $command === '-filter:v' || $command === '-filter_complex') {
unset ($filterCommands[$index]);
if ('-vf' === $command || '-filter:v' === $command || '-filter_complex' === $command) {
unset($filterCommands[$index]);
}
}
@ -306,7 +307,7 @@ class AdvancedMedia extends AbstractMediaType
// Compatibility with the some existed filters:
// If the command contains [in], just replace it to inLabel. If not - to add it manually.
if (stripos($strCommand, '[in]') !== false) {
if (false !== stripos($strCommand, '[in]')) {
$strCommand = str_replace('[in]', $filter->getInLabels(), $strCommand);
$in = '';
} else {
@ -314,35 +315,35 @@ class AdvancedMedia extends AbstractMediaType
}
// If the command contains [out], just replace it to outLabel. If not - to add it manually.
if (stripos($strCommand, '[out]') !== false) {
if (false !== stripos($strCommand, '[out]')) {
$strCommand = str_replace('[out]', $filter->getOutLabels(), $strCommand);
$out = '';
} else {
$out = $filter->getOutLabels();
}
return $in . $strCommand . $out;
return $in.$strCommand.$out;
}
/**
* @return void
*
* @throws RuntimeException
*/
protected function assertFiltersAreCompatibleToCurrentFFMpegVersion()
{
$messages = array();
$messages = [];
$currentVersion = $this->getFFMpegDriver()->getVersion();
/** @var ComplexFilterInterface $filter */
foreach ($this->filters as $filter) {
if (version_compare($currentVersion, $filter->getMinimalFFMpegVersion(), '<')) {
$messages[] = $filter->getName() . ' filter is supported starting from '
. $filter->getMinimalFFMpegVersion() . ' ffmpeg version';
$messages[] = $filter->getName().' filter is supported starting from '
.$filter->getMinimalFFMpegVersion().' ffmpeg version';
}
}
if (!empty($messages)) {
throw new RuntimeException(implode('; ', $messages)
. '; your ffmpeg version is ' . $currentVersion);
throw new RuntimeException(implode('; ', $messages).'; your ffmpeg version is '.$currentVersion);
}
}
@ -351,8 +352,10 @@ class AdvancedMedia extends AbstractMediaType
*/
protected function buildCommand()
{
$globalOptions = array('threads', 'filter_threads', 'filter_complex_threads');
return array_merge(array('-y'),
$globalOptions = ['threads', 'filter_threads', 'filter_complex_threads'];
return array_merge(
['-y'],
$this->buildConfiguredGlobalOptions($globalOptions),
$this->getInitialParameters(),
$this->buildInputsPart($this->inputs),
@ -369,14 +372,14 @@ class AdvancedMedia extends AbstractMediaType
*/
private function buildConfiguredGlobalOptions($optionNames)
{
$commands = array();
$commands = [];
foreach ($optionNames as $optionName) {
if (!$this->driver->getConfiguration()->has('ffmpeg.' . $optionName)) {
if (!$this->driver->getConfiguration()->has('ffmpeg.'.$optionName)) {
continue;
}
$commands[] = '-' . $optionName;
$commands[] = $this->driver->getConfiguration()->get('ffmpeg.' . $optionName);
$commands[] = '-'.$optionName;
$commands[] = $this->driver->getConfiguration()->get('ffmpeg.'.$optionName);
}
return $commands;
@ -391,7 +394,7 @@ class AdvancedMedia extends AbstractMediaType
*/
private function buildInputsPart(array $inputs)
{
$commands = array();
$commands = [];
foreach ($inputs as $input) {
$commands[] = '-i';
$commands[] = $input;
@ -403,13 +406,11 @@ class AdvancedMedia extends AbstractMediaType
/**
* Build "-filter_complex" part of the ffmpeg command.
*
* @param FiltersCollection $complexFilters
*
* @return array
*/
private function buildComplexFilterPart(FiltersCollection $complexFilters)
{
$commands = array();
$commands = [];
/** @var ComplexFilterInterface $filter */
foreach ($complexFilters as $filter) {
$filterCommand = $this->applyComplexFilter($filter);
@ -417,8 +418,9 @@ class AdvancedMedia extends AbstractMediaType
}
if (empty($commands)) {
return array();
return [];
}
return array('-filter_complex', implode(';', $commands));
return ['-filter_complex', implode(';', $commands)];
}
}

View file

@ -12,13 +12,13 @@
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\Exception\RuntimeException;
use FFMpeg\Filters\Audio\AudioFilterInterface;
use FFMpeg\Filters\Audio\AudioFilters;
use FFMpeg\Filters\Audio\SimpleFilter;
use FFMpeg\Filters\FilterInterface;
use FFMpeg\Format\FormatInterface;
use FFMpeg\Format\ProgressableInterface;
class Audio extends AbstractStreamableMedia
@ -52,9 +52,10 @@ class Audio extends AbstractStreamableMedia
/**
* Exports the audio in the desired format, applies registered filters.
*
* @param FormatInterface $format
* @param string $outputPathfile
* @param string $outputPathfile
*
* @return Audio
*
* @throws RuntimeException
*/
public function save(FormatInterface $format, $outputPathfile)
@ -80,34 +81,38 @@ class Audio extends AbstractStreamableMedia
/**
* Returns the final command as a string, useful for debugging purposes.
*
* @param FormatInterface $format
* @param string $outputPathfile
* @param string $outputPathfile
*
* @return string
*
* @since 0.11.0
*/
public function getFinalCommand(FormatInterface $format, $outputPathfile) {
public function getFinalCommand(FormatInterface $format, $outputPathfile)
{
return implode(' ', $this->buildCommand($format, $outputPathfile));
}
/**
* Builds the command which will be executed with the provided format
* Builds the command which will be executed with the provided format.
*
* @param string $outputPathfile
*
* @param FormatInterface $format
* @param string $outputPathfile
* @return string[] An array which are the components of the command
*
* @since 0.11.0
*/
protected function buildCommand(FormatInterface $format, $outputPathfile) {
$commands = array('-y', '-i', $this->pathfile);
protected function buildCommand(FormatInterface $format, $outputPathfile)
{
$commands = ['-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'))));
$filters->add(new SimpleFilter(['-threads', $this->driver->getConfiguration()->get('ffmpeg.threads')]));
}
if (null !== $format->getAudioCodec()) {
$filters->add(new SimpleFilter(array('-acodec', $format->getAudioCodec())));
$filters->add(new SimpleFilter(['-acodec', $format->getAudioCodec()]));
}
foreach ($filters as $filter) {
@ -116,7 +121,7 @@ class Audio extends AbstractStreamableMedia
if (null !== $format->getAudioKiloBitrate()) {
$commands[] = '-b:a';
$commands[] = $format->getAudioKiloBitrate() . 'k';
$commands[] = $format->getAudioKiloBitrate().'k';
}
if (null !== $format->getAudioChannels()) {
$commands[] = '-ac';
@ -130,12 +135,13 @@ class Audio extends AbstractStreamableMedia
/**
* Gets the waveform of the video.
*
* @param int $width
* @param int $height
* @param int $width
* @param int $height
* @param array $colors Array of colors for ffmpeg to use. Color format is #000000 (RGB hex string with #)
*
* @return Waveform
*/
public function waveform($width = 640, $height = 120, $colors = array(Waveform::DEFAULT_COLOR))
public function waveform($width = 640, $height = 120, $colors = [Waveform::DEFAULT_COLOR])
{
return new Waveform($this, $this->driver, $this->ffprobe, $width, $height, $colors);
}
@ -143,7 +149,8 @@ class Audio extends AbstractStreamableMedia
/**
* Concatenates a list of audio files into one unique audio file.
*
* @param array $sources
* @param array $sources
*
* @return Concat
*/
public function concat($sources)

View file

@ -1,9 +1,10 @@
<?php
namespace FFMpeg\Media;
use FFMpeg\Coordinate\TimeCode;
use FFMpeg\Driver\FFMpegDriver;
use FFMpeg\FFProbe;
use FFMpeg\Coordinate\TimeCode;
use FFMpeg\Format\FormatInterface;
/**
@ -13,7 +14,6 @@ use FFMpeg\Format\FormatInterface;
*/
class Clip extends Video
{
/** @var TimeCode Start time */
private $start;
@ -49,9 +49,9 @@ class Clip extends Video
*/
protected function basePartOfCommand(FormatInterface $format)
{
$arr = array('-y', '-ss', (string) $this->start, '-i', $this->pathfile);
$arr = ['-y', '-ss', (string) $this->start, '-i', $this->pathfile];
if (is_null($this->duration) === false) {
if (false === is_null($this->duration)) {
$arr[] = '-t';
$arr[] = (string) $this->duration;
}

View file

@ -13,18 +13,16 @@ 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\Exception\RuntimeException;
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\Filters\Concat\ConcatFilterInterface;
use FFMpeg\Filters\Concat\ConcatFilters;
use FFMpeg\Format\AudioInterface;
use FFMpeg\Format\FormatInterface;
use FFMpeg\Format\VideoInterface;
use Neutron\TemporaryFilesystem\Manager as FsManager;
use Spatie\TemporaryDirectory\TemporaryDirectory;
class Concat extends AbstractMediaType
{
@ -72,14 +70,14 @@ class Concat extends AbstractMediaType
/**
* Saves the concatenated video in the given array, considering that the sources videos are all encoded with the same codec.
*
* @param string $outputPathfile
* @param bool $streamCopy
* @param string $outputPathfile
* @param bool $streamCopy
*
* @return Concat
*
* @throws RuntimeException
*/
public function saveFromSameCodecs($outputPathfile, $streamCopy = TRUE)
public function saveFromSameCodecs($outputPathfile, $streamCopy = true)
{
/**
* @see https://ffmpeg.org/ffmpeg-formats.html#concat
@ -87,44 +85,43 @@ class Concat extends AbstractMediaType
*/
// Create the file which will contain the list of videos
$fs = FsManager::create();
$sourcesFile = $fs->createTemporaryFile('ffmpeg-concat');
$fs = (new TemporaryDirectory())->create();
$sourcesFile = $fs->path('ffmpeg.concat');
// Set the content of this file
$fileStream = @fopen($sourcesFile, 'w');
if($fileStream === false) {
if (false === $fileStream) {
throw new RuntimeException('Cannot open the temporary file.');
}
$count_videos = 0;
if(is_array($this->sources) && (count($this->sources) > 0)) {
if (is_array($this->sources) && (count($this->sources) > 0)) {
foreach ($this->sources as $videoPath) {
$line = "";
$line = '';
if($count_videos != 0)
if (0 != $count_videos) {
$line .= "\n";
}
$line .= "file " . addcslashes($videoPath, '\'"\\\0 ');
$line .= 'file '.addcslashes($videoPath, '\'"\\\0 ');
fwrite($fileStream, $line);
$count_videos++;
++$count_videos;
}
}
else {
} else {
throw new InvalidArgumentException('The list of videos is not a valid array.');
}
fclose($fileStream);
$commands = array(
$commands = [
'-f', 'concat', '-safe', '0',
'-i', $sourcesFile
);
'-i', $sourcesFile,
];
// Check if stream copy is activated
if($streamCopy === TRUE) {
if (true === $streamCopy) {
$commands[] = '-c';
$commands[] = 'copy';
}
@ -137,7 +134,7 @@ class Concat extends AbstractMediaType
}
// Set the output file in the command
$commands = array_merge($commands, array($outputPathfile));
$commands = array_merge($commands, [$outputPathfile]);
// Execute the command
try {
@ -150,42 +147,42 @@ class Concat extends AbstractMediaType
}
$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 FormatInterface $format
* @param string $outputPathfile
*
* @return Concat
*/
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)) {
if (!is_array($this->sources) || (0 == count($this->sources))) {
throw new InvalidArgumentException('The list of videos is not a valid array.');
}
// Create the commands variable
$commands = array();
$commands = [];
// Prepare the parameters
$nbSources = 0;
$files = array();
$files = [];
// For each source, check if this is a legit file
// and prepare the parameters
foreach ($this->sources as $videoPath) {
$files[] = '-i';
$files[] = $videoPath;
$nbSources++;
++$nbSources;
}
$commands = array_merge($commands, $files);
@ -194,7 +191,7 @@ class Concat extends AbstractMediaType
$commands[] = '-filter_complex';
$complex_filter = '';
for($i=0; $i<$nbSources; $i++) {
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]';
@ -210,16 +207,16 @@ class Concat extends AbstractMediaType
$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'))));
$filters->add(new SimpleFilter(['-threads', $this->driver->getConfiguration()->get('ffmpeg.threads')]));
}
if ($format instanceof VideoInterface) {
if (null !== $format->getVideoCodec()) {
$filters->add(new SimpleFilter(array('-vcodec', $format->getVideoCodec())));
$filters->add(new SimpleFilter(['-vcodec', $format->getVideoCodec()]));
}
}
if ($format instanceof AudioInterface) {
if (null !== $format->getAudioCodec()) {
$filters->add(new SimpleFilter(array('-acodec', $format->getAudioCodec())));
$filters->add(new SimpleFilter(['-acodec', $format->getAudioCodec()]));
}
}
@ -231,7 +228,7 @@ class Concat extends AbstractMediaType
if ($format instanceof AudioInterface) {
if (null !== $format->getAudioKiloBitrate()) {
$commands[] = '-b:a';
$commands[] = $format->getAudioKiloBitrate() . 'k';
$commands[] = $format->getAudioKiloBitrate().'k';
}
if (null !== $format->getAudioChannels()) {
$commands[] = '-ac';

View file

@ -12,12 +12,12 @@
namespace FFMpeg\Media;
use Alchemy\BinaryDriver\Exception\ExecutionFailureException;
use FFMpeg\Coordinate\TimeCode;
use FFMpeg\Driver\FFMpegDriver;
use FFMpeg\Exception\RuntimeException;
use FFMpeg\FFProbe;
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
{
@ -79,8 +79,8 @@ class Frame extends AbstractMediaType
* Uses the `unaccurate method by default.`
*
* @param string $pathfile
* @param bool $accurate
* @param bool $returnBase64
* @param bool $accurate
* @param bool $returnBase64
*
* @return Frame
*
@ -89,27 +89,28 @@ class Frame extends AbstractMediaType
public function save($pathfile, $accurate = false, $returnBase64 = false)
{
/**
* might be optimized with http://ffmpeg.org/trac/ffmpeg/wiki/Seeking%20with%20FFmpeg
* 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";
$outputFormat = $returnBase64 ? 'image2pipe' : 'image2';
if (!$accurate) {
$commands = array(
$commands = [
'-y', '-ss', (string) $this->timecode,
'-i', $this->pathfile,
'-vframes', '1',
'-f', $outputFormat
);
'-f', $outputFormat,
];
} else {
$commands = array(
$commands = [
'-y', '-i', $this->pathfile,
'-vframes', '1', '-ss', (string) $this->timecode,
'-f', $outputFormat
);
'-f', $outputFormat,
];
}
if($returnBase64) {
array_push($commands, "-");
if ($returnBase64) {
array_push($commands, '-');
}
foreach ($this->filters as $filter) {
@ -117,15 +118,15 @@ class Frame extends AbstractMediaType
}
if (!$returnBase64) {
$commands = array_merge($commands, array($pathfile));
$commands = array_merge($commands, [$pathfile]);
}
try {
if(!$returnBase64) {
if (!$returnBase64) {
$this->driver->command($commands);
return $this;
}
else {
} else {
return $this->driver->command($commands);
}
} catch (ExecutionFailureException $e) {

View file

@ -12,13 +12,13 @@
namespace FFMpeg\Media;
use Alchemy\BinaryDriver\Exception\ExecutionFailureException;
use FFMpeg\Coordinate\Dimension;
use FFMpeg\Coordinate\TimeCode;
use FFMpeg\Driver\FFMpegDriver;
use FFMpeg\Exception\RuntimeException;
use FFMpeg\FFProbe;
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
{
@ -91,7 +91,7 @@ class Gif extends AbstractMediaType
/**
* Saves the gif in the given filename.
*
* @param string $pathfile
* @param string $pathfile
*
* @return Gif
*
@ -102,19 +102,19 @@ class Gif extends AbstractMediaType
/**
* @see http://ffmpeg.org/ffmpeg.html#Main-options
*/
$commands = array(
'-ss', (string)$this->timecode
);
$commands = [
'-ss', (string) $this->timecode,
];
if(null !== $this->duration) {
if (null !== $this->duration) {
$commands[] = '-t';
$commands[] = (string)$this->duration;
$commands[] = (string) $this->duration;
}
$commands[] = '-i';
$commands[] = $this->pathfile;
$commands[] = '-vf';
$commands[] = 'scale=' . $this->dimension->getWidth() . ':-1';
$commands[] = 'scale='.$this->dimension->getWidth().':-1';
$commands[] = '-gifflags';
$commands[] = '+transdiff';
$commands[] = '-y';
@ -123,7 +123,7 @@ class Gif extends AbstractMediaType
$commands = array_merge($commands, $filter->apply($this));
}
$commands = array_merge($commands, array($pathfile));
$commands = array_merge($commands, [$pathfile]);
try {
$this->driver->command($commands);

View file

@ -1,4 +1,5 @@
<?php
/*
* This file is part of PHP-FFmpeg.
*
@ -7,18 +8,17 @@
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace FFMpeg\Media;
use FFMpeg\Coordinate\TimeCode;
use FFMpeg\Coordinate\Dimension;
use FFMpeg\Coordinate\TimeCode;
class Video extends AbstractVideo
{
/**
* Gets the frame at timecode.
*
* @param TimeCode $at
* @return Frame
*/
public function frame(TimeCode $at)
@ -29,9 +29,8 @@ class Video extends AbstractVideo
/**
* Extracts a gif from a sequence of the video.
*
* @param TimeCode $at
* @param Dimension $dimension
* @param int $duration
* @param int $duration
*
* @return Gif
*/
public function gif(TimeCode $at, Dimension $dimension, $duration = null)
@ -42,7 +41,8 @@ class Video extends AbstractVideo
/**
* Concatenates a list of videos into one unique video.
*
* @param array $sources
* @param array $sources
*
* @return Concat
*/
public function concat($sources)
@ -53,8 +53,9 @@ class Video extends AbstractVideo
/**
* Clips the video at the given time(s).
*
* @param TimeCode $start Start time
* @param TimeCode $start Start time
* @param TimeCode $duration Duration
*
* @return \FFMpeg\Media\Clip
*/
public function clip(TimeCode $start, TimeCode $duration = null)

View file

@ -12,16 +12,16 @@
namespace FFMpeg\Media;
use Alchemy\BinaryDriver\Exception\ExecutionFailureException;
use FFMpeg\Driver\FFMpegDriver;
use FFMpeg\Exception\InvalidArgumentException;
use FFMpeg\Exception\RuntimeException;
use FFMpeg\FFProbe;
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
{
const DEFAULT_COLOR = '#000000';
public const DEFAULT_COLOR = '#000000';
/** @var Video */
protected $audio;
@ -33,7 +33,7 @@ class Waveform extends AbstractMediaType
*/
protected $colors;
public function __construct(Audio $audio, FFMpegDriver $driver, FFProbe $ffprobe, $width, $height, $colors = array(self::DEFAULT_COLOR))
public function __construct(Audio $audio, FFMpegDriver $driver, FFProbe $ffprobe, $width, $height, $colors = [self::DEFAULT_COLOR])
{
parent::__construct($audio->getPathfile(), $driver, $ffprobe);
$this->audio = $audio;
@ -80,15 +80,11 @@ class Waveform extends AbstractMediaType
* example #FFFFFF or #000000. By default the color is set to black. Keep in mind that if you save the waveform
* as jpg file, it will appear completely black and to avoid this you can set the waveform color to white (#FFFFFF).
* Saving waveforms to png is strongly suggested.
*
* @param array $colors
*/
public function setColors(array $colors)
{
foreach ($colors as $row => $value)
{
if (!preg_match('/^#(?:[0-9a-fA-F]{6})$/', $value))
{
foreach ($colors as $row => $value) {
if (!preg_match('/^#(?:[0-9a-fA-F]{6})$/', $value)) {
//invalid color
//unset($colors[$row]);
@ -96,8 +92,7 @@ class Waveform extends AbstractMediaType
}
}
if (count($colors))
{
if (count($colors)) {
$this->colors = $colors;
}
}
@ -127,7 +122,7 @@ class Waveform extends AbstractMediaType
/**
* Saves the waveform in the given filename.
*
* @param string $pathfile
* @param string $pathfile
*
* @return Waveform
*
@ -136,20 +131,21 @@ class Waveform extends AbstractMediaType
public function save($pathfile)
{
/**
* might be optimized with http://ffmpeg.org/trac/ffmpeg/wiki/Seeking%20with%20FFmpeg
* might be optimized with http://ffmpeg.org/trac/ffmpeg/wiki/Seeking%20with%20FFmpeg.
*
* @see http://ffmpeg.org/ffmpeg.html#Main-options
*/
$commands = array(
$commands = [
'-y', '-i', $this->pathfile, '-filter_complex',
'showwavespic=colors='.$this->compileColors().':s='.$this->width.'x'.$this->height,
'-frames:v', '1'
);
'-frames:v', '1',
];
foreach ($this->filters as $filter) {
$commands = array_merge($commands, $filter->apply($this));
}
$commands = array_merge($commands, array($pathfile));
$commands = array_merge($commands, [$pathfile]);
try {
$this->driver->command($commands);