🚧 Initial edits
This commit is contained in:
parent
d187e02d24
commit
892265dcec
2 changed files with 24 additions and 158 deletions
|
|
@ -29,6 +29,7 @@
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"friendsofphp/php-cs-fixer": "^3.0",
|
"friendsofphp/php-cs-fixer": "^3.0",
|
||||||
"pestphp/pest": "^1.20",
|
"pestphp/pest": "^1.20",
|
||||||
|
"psy/psysh": "^0.11.8",
|
||||||
"spatie/ray": "^1.28"
|
"spatie/ray": "^1.28"
|
||||||
},
|
},
|
||||||
"autoload": {
|
"autoload": {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace FFMpeg\Media;
|
namespace Danjones\FFMpeg;
|
||||||
|
|
||||||
use Alchemy\BinaryDriver\Exception\ExecutionFailureException;
|
use Alchemy\BinaryDriver\Exception\ExecutionFailureException;
|
||||||
use FFMpeg\Driver\FFMpegDriver;
|
use FFMpeg\Driver\FFMpegDriver;
|
||||||
|
|
@ -16,6 +16,7 @@ use FFMpeg\Format\FormatInterface;
|
||||||
use FFMpeg\Format\ProgressableInterface;
|
use FFMpeg\Format\ProgressableInterface;
|
||||||
use FFMpeg\Format\ProgressListener\AbstractProgressListener;
|
use FFMpeg\Format\ProgressListener\AbstractProgressListener;
|
||||||
use FFMpeg\Format\VideoInterface;
|
use FFMpeg\Format\VideoInterface;
|
||||||
|
use FFMpeg\Media\AbstractMediaType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* AdvancedMedia may have multiple inputs and multiple outputs.
|
* AdvancedMedia may have multiple inputs and multiple outputs.
|
||||||
|
|
@ -24,111 +25,65 @@ use FFMpeg\Format\VideoInterface;
|
||||||
*
|
*
|
||||||
* @see http://trac.ffmpeg.org/wiki/Creating%20multiple%20outputs
|
* @see http://trac.ffmpeg.org/wiki/Creating%20multiple%20outputs
|
||||||
*/
|
*/
|
||||||
class AdvancedMedia extends AbstractMediaType
|
class MappableMedia extends AbstractMediaType
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* @var string[]
|
* @var string[]
|
||||||
*/
|
*/
|
||||||
private $inputs;
|
protected array $inputs = [];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var string[]
|
* @var string[]
|
||||||
*/
|
*/
|
||||||
private $initialParameters;
|
protected array $initialParameters = [];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var string[]
|
* @var string[]
|
||||||
*/
|
*/
|
||||||
private $additionalParameters;
|
protected array $additionalParameters = [];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var string[]
|
* @var string[]
|
||||||
*/
|
*/
|
||||||
private $mapCommands;
|
protected array $mapCommands = [];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var AbstractProgressListener[]
|
* @var AbstractProgressListener[]
|
||||||
*/
|
*/
|
||||||
private $listeners;
|
protected array $listeners = [];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* AdvancedMedia constructor.
|
* AdvancedMedia constructor.
|
||||||
*
|
*
|
||||||
* @param string[] $inputs array of files to be opened
|
* @param string[] $inputs array of files to be opened
|
||||||
*/
|
*/
|
||||||
public function __construct($inputs, FFMpegDriver $driver, FFProbe $ffprobe)
|
public function __construct(FFMpegDriver $driver, FFProbe $ffprobe)
|
||||||
{
|
{
|
||||||
// In case of error user will see this text in the error log.
|
// In case of error user will see this text in the error log.
|
||||||
// But absence of inputs is a correct situation for some cases.
|
// But absence of inputs is a correct situation for some cases.
|
||||||
// For example, if the user will use filters such as "testsrc".
|
// For example, if the user will use filters such as "testsrc".
|
||||||
$pathfile = 'you_can_pass_empty_inputs_array_only_if_you_use_computed_inputs';
|
$pathfile = 'you_can_pass_empty_inputs_array_only_if_you_use_computed_inputs';
|
||||||
$inputsKeys = array_keys($inputs);
|
|
||||||
if (count($inputsKeys) > 0) {
|
|
||||||
$pathfile = $inputs[$inputsKeys[0]];
|
|
||||||
}
|
|
||||||
|
|
||||||
parent::__construct($pathfile, $driver, $ffprobe);
|
parent::__construct($pathfile, $driver, $ffprobe);
|
||||||
$this->filters = new FiltersCollection();
|
|
||||||
$this->inputs = $inputs;
|
|
||||||
$this->initialParameters = [];
|
|
||||||
$this->additionalParameters = [];
|
|
||||||
$this->mapCommands = [];
|
|
||||||
$this->listeners = [];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the available filters.
|
|
||||||
*
|
|
||||||
* @return ComplexFilters
|
|
||||||
*/
|
|
||||||
public function filters()
|
public function filters()
|
||||||
{
|
{
|
||||||
return new ComplexFilters($this);
|
return $this->filters;
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add complex filter.
|
|
||||||
*
|
|
||||||
* @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}
|
|
||||||
*/
|
|
||||||
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!');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return parent::setFiltersCollection($filters);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return string[]
|
* @return string[]
|
||||||
*/
|
*/
|
||||||
public function getInitialParameters()
|
public function getInitialParameters(): array
|
||||||
{
|
{
|
||||||
return $this->initialParameters;
|
return $this->initialParameters;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string[] $initialParameters
|
* @param string[] $initialParameters
|
||||||
*
|
|
||||||
* @return AdvancedMedia
|
|
||||||
*/
|
*/
|
||||||
public function setInitialParameters(array $initialParameters)
|
public function setInitialParameters(array $initialParameters): self
|
||||||
{
|
{
|
||||||
$this->initialParameters = $initialParameters;
|
$this->initialParameters = $initialParameters;
|
||||||
|
|
||||||
|
|
@ -138,17 +93,15 @@ class AdvancedMedia extends AbstractMediaType
|
||||||
/**
|
/**
|
||||||
* @return string[]
|
* @return string[]
|
||||||
*/
|
*/
|
||||||
public function getAdditionalParameters()
|
public function getAdditionalParameters(): array
|
||||||
{
|
{
|
||||||
return $this->additionalParameters;
|
return $this->additionalParameters;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string[] $additionalParameters
|
* @param string[] $additionalParameters
|
||||||
*
|
|
||||||
* @return AdvancedMedia
|
|
||||||
*/
|
*/
|
||||||
public function setAdditionalParameters(array $additionalParameters)
|
public function setAdditionalParameters(array $additionalParameters): self
|
||||||
{
|
{
|
||||||
$this->additionalParameters = $additionalParameters;
|
$this->additionalParameters = $additionalParameters;
|
||||||
|
|
||||||
|
|
@ -158,23 +111,17 @@ class AdvancedMedia extends AbstractMediaType
|
||||||
/**
|
/**
|
||||||
* @return string[]
|
* @return string[]
|
||||||
*/
|
*/
|
||||||
public function getInputs()
|
public function getInputs(): array
|
||||||
{
|
{
|
||||||
return $this->inputs;
|
return $this->inputs;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public function getInputsCount(): int
|
||||||
* @return int
|
|
||||||
*/
|
|
||||||
public function getInputsCount()
|
|
||||||
{
|
{
|
||||||
return count($this->inputs);
|
return count($this->inputs);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public function getFinalCommand(): string
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function getFinalCommand()
|
|
||||||
{
|
{
|
||||||
return implode(' ', $this->buildCommand());
|
return implode(' ', $this->buildCommand());
|
||||||
}
|
}
|
||||||
|
|
@ -189,7 +136,7 @@ class AdvancedMedia extends AbstractMediaType
|
||||||
* @param bool $forceDisableVideo
|
* @param bool $forceDisableVideo
|
||||||
*
|
*
|
||||||
* @return $this
|
* @return $this
|
||||||
*
|
* @todo Redo all of this.
|
||||||
* @see https://ffmpeg.org/ffmpeg.html#Manual-stream-selection
|
* @see https://ffmpeg.org/ffmpeg.html#Manual-stream-selection
|
||||||
*/
|
*/
|
||||||
public function map(
|
public function map(
|
||||||
|
|
@ -228,13 +175,10 @@ class AdvancedMedia extends AbstractMediaType
|
||||||
/**
|
/**
|
||||||
* Apply added filters and execute ffmpeg command.
|
* Apply added filters and execute ffmpeg command.
|
||||||
*
|
*
|
||||||
* @return void
|
|
||||||
*
|
|
||||||
* @throws RuntimeException
|
* @throws RuntimeException
|
||||||
*/
|
*/
|
||||||
public function save()
|
public function save(): void
|
||||||
{
|
{
|
||||||
$this->assertFiltersAreCompatibleToCurrentFFMpegVersion();
|
|
||||||
$command = $this->buildCommand();
|
$command = $this->buildCommand();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
@ -249,8 +193,9 @@ class AdvancedMedia extends AbstractMediaType
|
||||||
* @param bool $forceDisableVideo
|
* @param bool $forceDisableVideo
|
||||||
*
|
*
|
||||||
* @return array
|
* @return array
|
||||||
|
* @todo Redo it all
|
||||||
*/
|
*/
|
||||||
private function applyFormatParams(
|
protected function applyFormatParams(
|
||||||
FormatInterface $format,
|
FormatInterface $format,
|
||||||
$forceDisableAudio = false,
|
$forceDisableAudio = false,
|
||||||
$forceDisableVideo = false
|
$forceDisableVideo = false
|
||||||
|
|
@ -289,64 +234,6 @@ class AdvancedMedia extends AbstractMediaType
|
||||||
|
|
||||||
return $commands;
|
return $commands;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
private function applyComplexFilter(ComplexFilterInterface $filter)
|
|
||||||
{
|
|
||||||
/** @var $format VideoInterface */
|
|
||||||
$filterCommands = $filter->applyComplex($this);
|
|
||||||
foreach ($filterCommands as $index => $command) {
|
|
||||||
if ('-vf' === $command || '-filter:v' === $command || '-filter_complex' === $command) {
|
|
||||||
unset($filterCommands[$index]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$strCommand = implode(' ', $filterCommands);
|
|
||||||
|
|
||||||
// Compatibility with the some existed filters:
|
|
||||||
// If the command contains [in], just replace it to inLabel. If not - to add it manually.
|
|
||||||
if (false !== stripos($strCommand, '[in]')) {
|
|
||||||
$strCommand = str_replace('[in]', $filter->getInLabels(), $strCommand);
|
|
||||||
$in = '';
|
|
||||||
} else {
|
|
||||||
$in = $filter->getInLabels();
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the command contains [out], just replace it to outLabel. If not - to add it manually.
|
|
||||||
if (false !== stripos($strCommand, '[out]')) {
|
|
||||||
$strCommand = str_replace('[out]', $filter->getOutLabels(), $strCommand);
|
|
||||||
$out = '';
|
|
||||||
} else {
|
|
||||||
$out = $filter->getOutLabels();
|
|
||||||
}
|
|
||||||
|
|
||||||
return $in.$strCommand.$out;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return void
|
|
||||||
*
|
|
||||||
* @throws RuntimeException
|
|
||||||
*/
|
|
||||||
protected function assertFiltersAreCompatibleToCurrentFFMpegVersion()
|
|
||||||
{
|
|
||||||
$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';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!empty($messages)) {
|
|
||||||
throw new RuntimeException(implode('; ', $messages).'; your ffmpeg version is '.$currentVersion);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
|
|
@ -359,7 +246,6 @@ class AdvancedMedia extends AbstractMediaType
|
||||||
$this->buildConfiguredGlobalOptions($globalOptions),
|
$this->buildConfiguredGlobalOptions($globalOptions),
|
||||||
$this->getInitialParameters(),
|
$this->getInitialParameters(),
|
||||||
$this->buildInputsPart($this->inputs),
|
$this->buildInputsPart($this->inputs),
|
||||||
$this->buildComplexFilterPart($this->filters),
|
|
||||||
$this->mapCommands,
|
$this->mapCommands,
|
||||||
$this->getAdditionalParameters()
|
$this->getAdditionalParameters()
|
||||||
);
|
);
|
||||||
|
|
@ -370,7 +256,7 @@ class AdvancedMedia extends AbstractMediaType
|
||||||
*
|
*
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
private function buildConfiguredGlobalOptions($optionNames)
|
protected function buildConfiguredGlobalOptions($optionNames)
|
||||||
{
|
{
|
||||||
$commands = [];
|
$commands = [];
|
||||||
foreach ($optionNames as $optionName) {
|
foreach ($optionNames as $optionName) {
|
||||||
|
|
@ -392,7 +278,7 @@ class AdvancedMedia extends AbstractMediaType
|
||||||
*
|
*
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
private function buildInputsPart(array $inputs)
|
protected function buildInputsPart(array $inputs)
|
||||||
{
|
{
|
||||||
$commands = [];
|
$commands = [];
|
||||||
foreach ($inputs as $input) {
|
foreach ($inputs as $input) {
|
||||||
|
|
@ -402,25 +288,4 @@ class AdvancedMedia extends AbstractMediaType
|
||||||
|
|
||||||
return $commands;
|
return $commands;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Build "-filter_complex" part of the ffmpeg command.
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
private function buildComplexFilterPart(FiltersCollection $complexFilters)
|
|
||||||
{
|
|
||||||
$commands = [];
|
|
||||||
/** @var ComplexFilterInterface $filter */
|
|
||||||
foreach ($complexFilters as $filter) {
|
|
||||||
$filterCommand = $this->applyComplexFilter($filter);
|
|
||||||
$commands[] = $filterCommand;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (empty($commands)) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
return ['-filter_complex', implode(';', $commands)];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue