Minor improvements of the ComplexMedia
This commit is contained in:
parent
71766fed47
commit
4469847d46
4 changed files with 75 additions and 36 deletions
|
|
@ -576,8 +576,8 @@ Then saves audios from the original videos into the 4 different formats and save
|
|||
|
||||
As you can see, you can take multiple input sources, perform the complicated processing for them and produce multiple output files in the same time, in the one ffmpeg command.
|
||||
|
||||
#### Just give me map!
|
||||
You do not have to use `-filter_complex`. For example, just extract the audio from the video:
|
||||
#### Just give me a map!
|
||||
You do not have to use `-filter_complex`. You can use only `-map` options. For example, just extract the audio from the video:
|
||||
|
||||
```php
|
||||
$complexMedia = $ffmpeg->openComplex(array('video.mp4'));
|
||||
|
|
|
|||
|
|
@ -14,11 +14,12 @@ 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;
|
||||
|
||||
/**
|
||||
* Complex media may have multiple inputs and multiple outputs.
|
||||
* This class accepts only filters for -filter_complex.
|
||||
* 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
|
||||
|
|
@ -46,7 +47,7 @@ class ComplexMedia extends AbstractMediaType
|
|||
private $mapCommands;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
* @var AbstractProgressListener[]
|
||||
*/
|
||||
private $listeners;
|
||||
|
||||
|
|
@ -88,6 +89,8 @@ class ComplexMedia extends AbstractMediaType
|
|||
}
|
||||
|
||||
/**
|
||||
* Add complex filter.
|
||||
*
|
||||
* @param string $in
|
||||
* @param ComplexCompatibleFilter $filter
|
||||
* @param string $out
|
||||
|
|
@ -117,7 +120,6 @@ class ComplexMedia extends AbstractMediaType
|
|||
|
||||
/**
|
||||
* @return string[]
|
||||
* @return void
|
||||
*/
|
||||
public function getInitialParameters()
|
||||
{
|
||||
|
|
@ -137,7 +139,6 @@ class ComplexMedia extends AbstractMediaType
|
|||
|
||||
/**
|
||||
* @return string[]
|
||||
* @return void
|
||||
*/
|
||||
public function getAdditionalParameters()
|
||||
{
|
||||
|
|
@ -180,18 +181,21 @@ class ComplexMedia extends AbstractMediaType
|
|||
}
|
||||
|
||||
/**
|
||||
* @param string[] $outs Output labels of the -filter_complex part.
|
||||
* @param FormatInterface $format
|
||||
* @param string $outputPathfile
|
||||
* 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,
|
||||
$outputPathfile,
|
||||
$outputFilename,
|
||||
$forceDisableAudio = false,
|
||||
$forceDisableVideo = false
|
||||
) {
|
||||
|
|
@ -202,12 +206,13 @@ class ComplexMedia extends AbstractMediaType
|
|||
}
|
||||
|
||||
// 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[] = $outputPathfile;
|
||||
$commands[] = $outputFilename;
|
||||
|
||||
// Create listener.
|
||||
// Create a listener.
|
||||
if ($format instanceof ProgressableInterface) {
|
||||
$listener = $format->createProgressListener($this, $this->ffprobe, 1, 1, 0);
|
||||
$this->listeners = array_merge($this->listeners, $listener);
|
||||
|
|
@ -220,7 +225,7 @@ class ComplexMedia extends AbstractMediaType
|
|||
/**
|
||||
* Apply added filters and execute ffmpeg command.
|
||||
*
|
||||
* @return ComplexMedia
|
||||
* @return void
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function save()
|
||||
|
|
@ -233,8 +238,6 @@ class ComplexMedia extends AbstractMediaType
|
|||
} catch (ExecutionFailureException $e) {
|
||||
throw new RuntimeException('Encoding failed', $e->getCode(), $e);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -256,7 +259,7 @@ class ComplexMedia extends AbstractMediaType
|
|||
$commands[] = '-vcodec';
|
||||
$commands[] = $format->getVideoCodec();
|
||||
}
|
||||
// If the user passed some additional parameters.
|
||||
// If the user passed some additional format parameters.
|
||||
if ($format->getAdditionalParameters() !== null) {
|
||||
$commands = array_merge($commands, $format->getAdditionalParameters());
|
||||
}
|
||||
|
|
@ -348,13 +351,9 @@ class ComplexMedia extends AbstractMediaType
|
|||
*/
|
||||
protected function buildCommand()
|
||||
{
|
||||
$commands = array('-y');
|
||||
if ($this->driver->getConfiguration()->has('ffmpeg.threads')) {
|
||||
$commands[] = '-threads';
|
||||
$commands[] = $this->driver->getConfiguration()->get('ffmpeg.threads');
|
||||
}
|
||||
|
||||
return array_merge($commands,
|
||||
$globalOptions = array('threads', 'filter_threads', 'filter_complex_threads');
|
||||
return array_merge(array('-y'),
|
||||
$this->buildConfiguredGlobalOptions($globalOptions),
|
||||
$this->getInitialParameters(),
|
||||
$this->buildInputsPart($this->inputs),
|
||||
$this->buildComplexFilterPart($this->filters),
|
||||
|
|
@ -363,6 +362,26 @@ class ComplexMedia extends AbstractMediaType
|
|||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string[] $optionNames
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function buildConfiguredGlobalOptions($optionNames)
|
||||
{
|
||||
$commands = array();
|
||||
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.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -13,14 +13,14 @@ class ComplexMediaTest extends FunctionalTestCase
|
|||
/**
|
||||
* Path prefix to avoid conflicts with another tests.
|
||||
*/
|
||||
const PATH_PREFIX = 'complex_media_';
|
||||
const OUTPUT_PATH_PREFIX = 'output/complex_media_';
|
||||
|
||||
public function testRunWithoutComplexFilterTestExtractAudio()
|
||||
{
|
||||
$ffmpeg = $this->getFFMpeg();
|
||||
$inputs = array(realpath(__DIR__ . '/../files/Test.ogv'));
|
||||
$format = new Mp3();
|
||||
$output = __DIR__ . '/output/' . self::PATH_PREFIX . 'extracted_with_map.mp3';
|
||||
$output = __DIR__ . '/' . self::OUTPUT_PATH_PREFIX . 'extracted_with_map.mp3';
|
||||
|
||||
// You can run it without -filter_complex, just using -map.
|
||||
$complexMedia = $ffmpeg->openComplex($inputs);
|
||||
|
|
@ -40,7 +40,7 @@ class ComplexMediaTest extends FunctionalTestCase
|
|||
$inputs = array(realpath(__DIR__ . '/../files/Audio.mp3'));
|
||||
$format = new Mp3();
|
||||
$format->setAudioKiloBitrate(30);
|
||||
$output = __DIR__ . '/output/' . self::PATH_PREFIX . 'audio_test.mp3';
|
||||
$output = __DIR__ . '/' . self::OUTPUT_PATH_PREFIX . 'audio_test.mp3';
|
||||
|
||||
$complexMedia = $ffmpeg->openComplex($inputs);
|
||||
$complexMedia
|
||||
|
|
@ -61,7 +61,7 @@ class ComplexMediaTest extends FunctionalTestCase
|
|||
realpath(__DIR__ . '/../files/portrait.MOV')
|
||||
);
|
||||
$format = new X264('aac', 'libx264');
|
||||
$output = __DIR__ . '/output/' . self::PATH_PREFIX . 'multiple_inputs_test.mp4';
|
||||
$output = __DIR__ . '/' . self::OUTPUT_PATH_PREFIX . 'multiple_inputs_test.mp4';
|
||||
|
||||
$complexMedia = $ffmpeg->openComplex($inputs);
|
||||
$complexMedia->filters()
|
||||
|
|
@ -88,9 +88,9 @@ class ComplexMediaTest extends FunctionalTestCase
|
|||
$formatX264 = new X264('aac', 'libx264');
|
||||
$formatMp3 = new Mp3();
|
||||
|
||||
$outputMp3 = __DIR__ . '/output/' . self::PATH_PREFIX . 'test_multiple_outputs.mp3';
|
||||
$outputVideo1 = __DIR__ . '/output/' . self::PATH_PREFIX . 'test_multiple_outputs_v1.mp4';
|
||||
$outputVideo2 = __DIR__ . '/output/' . self::PATH_PREFIX . 'test_multiple_outputs_v2.mp4';
|
||||
$outputMp3 = __DIR__ . '/' . self::OUTPUT_PATH_PREFIX . 'test_multiple_outputs.mp3';
|
||||
$outputVideo1 = __DIR__ . '/' . self::OUTPUT_PATH_PREFIX . 'test_multiple_outputs_v1.mp4';
|
||||
$outputVideo2 = __DIR__ . '/' . self::OUTPUT_PATH_PREFIX . 'test_multiple_outputs_v2.mp4';
|
||||
|
||||
$complexMedia = $ffmpeg->openComplex($inputs);
|
||||
$complexMedia->filters()
|
||||
|
|
@ -131,7 +131,7 @@ class ComplexMediaTest extends FunctionalTestCase
|
|||
$ffmpeg = $this->getFFMpeg();
|
||||
$inputs = array(realpath(__DIR__ . '/../files/Test.ogv'));
|
||||
$format = new X264('aac', 'libx264');
|
||||
$output = __DIR__ . '/output/' . self::PATH_PREFIX . 'testsrc.mp4';
|
||||
$output = __DIR__ . '/' . self::OUTPUT_PATH_PREFIX . 'testsrc.mp4';
|
||||
|
||||
$complexMedia = $ffmpeg->openComplex($inputs);
|
||||
$complexMedia->filters()
|
||||
|
|
@ -167,7 +167,7 @@ class ComplexMediaTest extends FunctionalTestCase
|
|||
|
||||
$inputs = array(realpath(__DIR__ . '/../files/Test.ogv'));
|
||||
$format = new X264('aac', 'libx264');
|
||||
$output = __DIR__ . '/output/' . self::PATH_PREFIX . 'xstack_test.mp4';
|
||||
$output = __DIR__ . '/' . self::OUTPUT_PATH_PREFIX . 'xstack_test.mp4';
|
||||
|
||||
$complexMedia = $ffmpeg->openComplex($inputs);
|
||||
$complexMedia->filters()
|
||||
|
|
@ -194,7 +194,7 @@ class ComplexMediaTest extends FunctionalTestCase
|
|||
$inputs = array(realpath(__DIR__ . '/../files/Test.ogv'));
|
||||
$watermark = realpath(__DIR__ . '/../files/watermark.png');
|
||||
$format = new X264('aac', 'libx264');
|
||||
$output = __DIR__ . '/output/' . self::PATH_PREFIX . 'test_of_compatibility_with_existed_filters.mp4';
|
||||
$output = __DIR__ . '/' . self::OUTPUT_PATH_PREFIX . 'test_of_compatibility_with_existed_filters.mp4';
|
||||
|
||||
$complexMedia = $ffmpeg->openComplex($inputs);
|
||||
$complexMedia->filters()
|
||||
|
|
@ -247,4 +247,22 @@ class ComplexMediaTest extends FunctionalTestCase
|
|||
'outputFile.mp4', false, true);
|
||||
$this->assertStringNotContainsString('vcodec', $complexMedia2->getFinalCommand());
|
||||
}
|
||||
|
||||
public function testGlobalOptions()
|
||||
{
|
||||
$configuration = array(
|
||||
'ffmpeg.threads' => 3,
|
||||
'ffmpeg.filter_threads' => 13,
|
||||
'ffmpeg.filter_complex_threads' => 24,
|
||||
);
|
||||
|
||||
$ffmpeg = $this->getFFMpeg($configuration);
|
||||
$complexMedia = $ffmpeg->openComplex(array(__FILE__));
|
||||
$command = $complexMedia->getFinalCommand();
|
||||
|
||||
foreach ($configuration as $optionName => $optionValue) {
|
||||
$optionName = str_replace('ffmpeg.', '', $optionName);
|
||||
$this->assertStringContainsString('-' . $optionName . ' ' . $optionValue, $command);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,10 +8,12 @@ use Tests\FFMpeg\BaseTestCase;
|
|||
abstract class FunctionalTestCase extends BaseTestCase
|
||||
{
|
||||
/**
|
||||
* @param array $configuration
|
||||
*
|
||||
* @return FFMpeg
|
||||
*/
|
||||
public function getFFMpeg()
|
||||
public function getFFMpeg($configuration = array())
|
||||
{
|
||||
return FFMpeg::create(array('timeout' => 300));
|
||||
return FFMpeg::create(array_merge(array('timeout' => 300), $configuration));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue