![]() Server : Apache System : Linux server2.corals.io 4.18.0-348.2.1.el8_5.x86_64 #1 SMP Mon Nov 15 09:17:08 EST 2021 x86_64 User : corals ( 1002) PHP Version : 7.4.33 Disable Function : exec,passthru,shell_exec,system Directory : /home/corals/rentpix.corals.io/vendor/php-ffmpeg/php-ffmpeg/src/FFMpeg/Media/ |
<?php namespace FFMpeg\Media; use Alchemy\BinaryDriver\Exception\ExecutionFailureException; use FFMpeg\Driver\FFMpegDriver; use FFMpeg\Exception\RuntimeException; use FFMpeg\FFProbe; use FFMpeg\Filters\AdvancedMedia\ComplexCompatibleFilter; use FFMpeg\Filters\AdvancedMedia\ComplexFilterContainer; use FFMpeg\Filters\AdvancedMedia\ComplexFilterInterface; use FFMpeg\Filters\AdvancedMedia\ComplexFilters; use FFMpeg\Filters\FiltersCollection; use FFMpeg\Format\AudioInterface; use FFMpeg\Format\FormatInterface; use FFMpeg\Format\ProgressableInterface; use FFMpeg\Format\ProgressListener\AbstractProgressListener; use FFMpeg\Format\VideoInterface; /** * AdvancedMedia may have multiple inputs and multiple outputs. * This class accepts only filters for -filter_complex option. * But you can set initial and additional parameters of the ffmpeg command. * * @see http://trac.ffmpeg.org/wiki/Creating%20multiple%20outputs */ class AdvancedMedia extends AbstractMediaType { /** * @var string[] */ private $inputs; /** * @var string[] */ private $initialParameters; /** * @var string[] */ private $additionalParameters; /** * @var string[] */ private $mapCommands; /** * @var AbstractProgressListener[] */ private $listeners; /** * AdvancedMedia constructor. * * @param string[] $inputs array of files to be opened */ public function __construct($inputs, FFMpegDriver $driver, FFProbe $ffprobe) { // In case of error user will see this text in the error log. // But absence of inputs is a correct situation for some cases. // For example, if the user will use filters such as "testsrc". $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); $this->filters = new FiltersCollection(); $this->inputs = $inputs; $this->initialParameters = []; $this->additionalParameters = []; $this->mapCommands = []; $this->listeners = []; } /** * Returns the available filters. * * @return ComplexFilters */ public function filters() { return new ComplexFilters($this); } /** * 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[] */ public function getInitialParameters() { return $this->initialParameters; } /** * @param string[] $initialParameters * * @return AdvancedMedia */ public function setInitialParameters(array $initialParameters) { $this->initialParameters = $initialParameters; return $this; } /** * @return string[] */ public function getAdditionalParameters() { return $this->additionalParameters; } /** * @param string[] $additionalParameters * * @return AdvancedMedia */ public function setAdditionalParameters(array $additionalParameters) { $this->additionalParameters = $additionalParameters; return $this; } /** * @return string[] */ public function getInputs() { return $this->inputs; } /** * @return int */ public function getInputsCount() { return count($this->inputs); } /** * @return string */ public function getFinalCommand() { return implode(' ', $this->buildCommand()); } /** * 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 bool $forceDisableAudio * @param bool $forceDisableVideo * * @return $this * * @see https://ffmpeg.org/ffmpeg.html#Manual-stream-selection */ public function map( array $outs, FormatInterface $format, $outputFilename, $forceDisableAudio = false, $forceDisableVideo = false ) { $commands = []; foreach ($outs as $label) { $commands[] = '-map'; $commands[] = $label; } // Apply format params. $commands = array_merge( $commands, $this->applyFormatParams($format, $forceDisableAudio, $forceDisableVideo) ); // Set output file. $commands[] = $outputFilename; // Create a listener. if ($format instanceof ProgressableInterface) { $listener = $format->createProgressListener($this, $this->ffprobe, 1, 1, 0); $this->listeners = array_merge($this->listeners, $listener); } $this->mapCommands = array_merge($this->mapCommands, $commands); return $this; } /** * Apply added filters and execute ffmpeg command. * * @return void * * @throws RuntimeException */ public function save() { $this->assertFiltersAreCompatibleToCurrentFFMpegVersion(); $command = $this->buildCommand(); try { $this->driver->command($command, false, $this->listeners); } catch (ExecutionFailureException $e) { throw new RuntimeException('Encoding failed', $e->getCode(), $e); } } /** * @param bool $forceDisableAudio * @param bool $forceDisableVideo * * @return array */ private function applyFormatParams( FormatInterface $format, $forceDisableAudio = false, $forceDisableVideo = false ) { // Set format params. $commands = []; if (!$forceDisableVideo && $format instanceof VideoInterface) { if (null !== $format->getVideoCodec()) { $commands[] = '-vcodec'; $commands[] = $format->getVideoCodec(); } // If the user passed some additional format parameters. if (null !== $format->getAdditionalParameters()) { $commands = array_merge($commands, $format->getAdditionalParameters()); } } if (!$forceDisableAudio && $format instanceof AudioInterface) { if (null !== $format->getAudioCodec()) { $commands[] = '-acodec'; $commands[] = $format->getAudioCodec(); } if (null !== $format->getAudioKiloBitrate()) { $commands[] = '-b:a'; $commands[] = $format->getAudioKiloBitrate().'k'; } if (null !== $format->getAudioChannels()) { $commands[] = '-ac'; $commands[] = $format->getAudioChannels(); } } // If the user passed some extra parameters. if ($format->getExtraParams()) { $commands = array_merge($commands, $format->getExtraParams()); } 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 */ protected function buildCommand() { $globalOptions = ['threads', 'filter_threads', 'filter_complex_threads']; return array_merge( ['-y'], $this->buildConfiguredGlobalOptions($globalOptions), $this->getInitialParameters(), $this->buildInputsPart($this->inputs), $this->buildComplexFilterPart($this->filters), $this->mapCommands, $this->getAdditionalParameters() ); } /** * @param string[] $optionNames * * @return array */ private function buildConfiguredGlobalOptions($optionNames) { $commands = []; foreach ($optionNames as $optionName) { if (!$this->driver->getConfiguration()->has('ffmpeg.'.$optionName)) { continue; } $commands[] = '-'.$optionName; $commands[] = $this->driver->getConfiguration()->get('ffmpeg.'.$optionName); } return $commands; } /** * Build inputs part of the ffmpeg command. * * @param string[] $inputs * * @return array */ private function buildInputsPart(array $inputs) { $commands = []; foreach ($inputs as $input) { $commands[] = '-i'; $commands[] = $input; } 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)]; } }