[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:
parent
72c946dc7d
commit
111c153428
335 changed files with 4394 additions and 28116 deletions
218
src/Alchemy/BinaryDriver/AbstractBinary.php
Normal file
218
src/Alchemy/BinaryDriver/AbstractBinary.php
Normal 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;
|
||||
}
|
||||
}
|
||||
77
src/Alchemy/BinaryDriver/BinaryDriverTestCase.php
Normal file
77
src/Alchemy/BinaryDriver/BinaryDriverTestCase.php
Normal 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();
|
||||
}
|
||||
}
|
||||
67
src/Alchemy/BinaryDriver/BinaryInterface.php
Normal file
67
src/Alchemy/BinaryDriver/BinaryInterface.php
Normal 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());
|
||||
}
|
||||
109
src/Alchemy/BinaryDriver/Configuration.php
Normal file
109
src/Alchemy/BinaryDriver/Configuration.php
Normal 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);
|
||||
}
|
||||
}
|
||||
29
src/Alchemy/BinaryDriver/ConfigurationAwareInterface.php
Normal file
29
src/Alchemy/BinaryDriver/ConfigurationAwareInterface.php
Normal 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);
|
||||
}
|
||||
58
src/Alchemy/BinaryDriver/ConfigurationInterface.php
Normal file
58
src/Alchemy/BinaryDriver/ConfigurationInterface.php
Normal 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();
|
||||
}
|
||||
16
src/Alchemy/BinaryDriver/Exception/ExceptionInterface.php
Normal file
16
src/Alchemy/BinaryDriver/Exception/ExceptionInterface.php
Normal 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
|
||||
{
|
||||
}
|
||||
|
|
@ -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
|
||||
{
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
{
|
||||
}
|
||||
58
src/Alchemy/BinaryDriver/Listeners/DebugListener.php
Normal file
58
src/Alchemy/BinaryDriver/Listeners/DebugListener.php
Normal 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));
|
||||
}
|
||||
}
|
||||
}
|
||||
32
src/Alchemy/BinaryDriver/Listeners/ListenerInterface.php
Normal file
32
src/Alchemy/BinaryDriver/Listeners/ListenerInterface.php
Normal 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();
|
||||
}
|
||||
88
src/Alchemy/BinaryDriver/Listeners/Listeners.php
Normal file
88
src/Alchemy/BinaryDriver/Listeners/Listeners.php
Normal 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());
|
||||
};
|
||||
}
|
||||
}
|
||||
186
src/Alchemy/BinaryDriver/ProcessBuilderFactory.php
Normal file
186
src/Alchemy/BinaryDriver/ProcessBuilderFactory.php
Normal 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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
65
src/Alchemy/BinaryDriver/ProcessBuilderFactoryInterface.php
Normal file
65
src/Alchemy/BinaryDriver/ProcessBuilderFactoryInterface.php
Normal 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();
|
||||
}
|
||||
107
src/Alchemy/BinaryDriver/ProcessRunner.php
Normal file
107
src/Alchemy/BinaryDriver/ProcessRunner.php
Normal 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);
|
||||
}
|
||||
}
|
||||
29
src/Alchemy/BinaryDriver/ProcessRunnerAwareInterface.php
Normal file
29
src/Alchemy/BinaryDriver/ProcessRunnerAwareInterface.php
Normal 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);
|
||||
}
|
||||
33
src/Alchemy/BinaryDriver/ProcessRunnerInterface.php
Normal file
33
src/Alchemy/BinaryDriver/ProcessRunnerInterface.php
Normal 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);
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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];
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
))
|
||||
);
|
||||
]),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 '';
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,6 +38,6 @@ class CustomComplexFilter extends AbstractComplexFilter
|
|||
*/
|
||||
public function applyComplex(AdvancedMedia $media)
|
||||
{
|
||||
return array('-filter_complex', $this->filter);
|
||||
return ['-filter_complex', $this->filter];
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
))
|
||||
);
|
||||
]),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
]),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
]),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -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];
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,8 +11,8 @@
|
|||
|
||||
namespace FFMpeg\Filters\Audio;
|
||||
|
||||
use FFMpeg\Media\Audio;
|
||||
use FFMpeg\Format\AudioInterface;
|
||||
use FFMpeg\Media\Audio;
|
||||
|
||||
class SimpleFilter implements AudioFilterInterface
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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)) {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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(),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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()) {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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'];
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -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]',
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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'];
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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];
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -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'];
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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'];
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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'];
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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'];
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -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()));
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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'];
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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'];
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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'];
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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'];
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -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
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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)];
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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';
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue