🚧 Initial edits

This commit is contained in:
Dan Jones 2022-08-21 17:39:40 -05:00
commit 892265dcec
2 changed files with 24 additions and 158 deletions

View file

@ -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": {

View file

@ -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)];
}
} }