Added the ComplexMedia type and the possibility to use -filter_complex and -map features. Added some built-in complex filters. Added the unit and functional tests of the new features. README.md has been updated.
This commit is contained in:
parent
89b0c2b4d0
commit
f20ad8a82e
17 changed files with 1583 additions and 7 deletions
61
src/FFMpeg/Filters/ComplexMedia/ANullSrcFilter.php
Normal file
61
src/FFMpeg/Filters/ComplexMedia/ANullSrcFilter.php
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
<?php
|
||||
|
||||
namespace FFMpeg\Filters\ComplexMedia;
|
||||
|
||||
use FFMpeg\Media\ComplexMedia;
|
||||
|
||||
/**
|
||||
* @see https://ffmpeg.org/ffmpeg-filters.html#anullsrc
|
||||
*/
|
||||
class ANullSrcFilter extends AbstractComplexFilter
|
||||
{
|
||||
/**
|
||||
* @var string|null
|
||||
*/
|
||||
private $channelLayout;
|
||||
|
||||
/**
|
||||
* @var int|null
|
||||
*/
|
||||
private $sampleRate;
|
||||
|
||||
/**
|
||||
* @var int|null
|
||||
*/
|
||||
private $nbSamples;
|
||||
|
||||
/**
|
||||
* ANullSrcComplexFilter constructor.
|
||||
*
|
||||
* @param string|null $channelLayout
|
||||
* @param int|null $sampleRate
|
||||
* @param int|null $nbSamples
|
||||
* @param int $priority
|
||||
*/
|
||||
public function __construct(
|
||||
$channelLayout = null,
|
||||
$sampleRate = null,
|
||||
$nbSamples = null,
|
||||
$priority = 0
|
||||
) {
|
||||
parent::__construct($priority);
|
||||
$this->channelLayout = $channelLayout;
|
||||
$this->sampleRate = $sampleRate;
|
||||
$this->nbSamples = $nbSamples;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function applyComplex(ComplexMedia $media)
|
||||
{
|
||||
return array(
|
||||
'-filter_complex',
|
||||
'anullsrc' . $this->buildFilterOptions(array(
|
||||
'channel_layout' => $this->channelLayout,
|
||||
'sample_rate' => $this->sampleRate,
|
||||
'nb_samples' => $this->nbSamples,
|
||||
))
|
||||
);
|
||||
}
|
||||
}
|
||||
52
src/FFMpeg/Filters/ComplexMedia/AbstractComplexFilter.php
Normal file
52
src/FFMpeg/Filters/ComplexMedia/AbstractComplexFilter.php
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
<?php
|
||||
|
||||
namespace FFMpeg\Filters\ComplexMedia;
|
||||
|
||||
abstract class AbstractComplexFilter implements ComplexCompatibleFilter
|
||||
{
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
protected $priority;
|
||||
|
||||
/**
|
||||
* AbstractComplexFilter constructor.
|
||||
*
|
||||
* @param int $priority
|
||||
*/
|
||||
public function __construct($priority = 0)
|
||||
{
|
||||
$this->priority = $priority;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getPriority()
|
||||
{
|
||||
return $this->priority;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the config of the filter.
|
||||
*
|
||||
* @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.
|
||||
*/
|
||||
protected function buildFilterOptions(array $params)
|
||||
{
|
||||
$config = array();
|
||||
foreach ($params as $paramName => $paramValue) {
|
||||
if ($paramValue !== null) {
|
||||
$config[] = $paramName . '=' . $paramValue;
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($config)) {
|
||||
return '=' . implode(':', $config);
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
}
|
||||
18
src/FFMpeg/Filters/ComplexMedia/ComplexCompatibleFilter.php
Normal file
18
src/FFMpeg/Filters/ComplexMedia/ComplexCompatibleFilter.php
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
<?php
|
||||
|
||||
namespace FFMpeg\Filters\ComplexMedia;
|
||||
|
||||
use FFMpeg\Filters\FilterInterface;
|
||||
use FFMpeg\Media\ComplexMedia;
|
||||
|
||||
interface ComplexCompatibleFilter extends FilterInterface
|
||||
{
|
||||
/**
|
||||
* Apply the complex filter to the given media.
|
||||
*
|
||||
* @param ComplexMedia $media
|
||||
*
|
||||
* @return string[] An array of arguments.
|
||||
*/
|
||||
public function applyComplex(ComplexMedia $media);
|
||||
}
|
||||
80
src/FFMpeg/Filters/ComplexMedia/ComplexFilterContainer.php
Normal file
80
src/FFMpeg/Filters/ComplexMedia/ComplexFilterContainer.php
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
<?php
|
||||
|
||||
namespace FFMpeg\Filters\ComplexMedia;
|
||||
|
||||
use FFMpeg\Media\ComplexMedia;
|
||||
|
||||
/**
|
||||
* Container for the complex filter.
|
||||
*/
|
||||
class ComplexFilterContainer implements ComplexFilterInterface
|
||||
{
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private $priority;
|
||||
|
||||
/**
|
||||
* @var ComplexCompatibleFilter
|
||||
*/
|
||||
private $baseFilter;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $inLabels;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $outLabels;
|
||||
|
||||
/**
|
||||
* ComplexFilter constructor.
|
||||
*
|
||||
* @param string $inLabels
|
||||
* @param ComplexCompatibleFilter $baseFilter
|
||||
* @param string $outLabels
|
||||
*/
|
||||
public function __construct($inLabels, ComplexCompatibleFilter $baseFilter, $outLabels)
|
||||
{
|
||||
$this->priority = $baseFilter->getPriority();
|
||||
$this->inLabels = $inLabels;
|
||||
$this->baseFilter = $baseFilter;
|
||||
$this->outLabels = $outLabels;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the priority of the filter.
|
||||
*
|
||||
* @return integer
|
||||
*/
|
||||
public function getPriority()
|
||||
{
|
||||
return $this->priority;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getInLabels()
|
||||
{
|
||||
return $this->inLabels;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getOutLabels()
|
||||
{
|
||||
return $this->outLabels;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function applyComplex(ComplexMedia $media)
|
||||
{
|
||||
return $this->baseFilter->applyComplex($media);
|
||||
}
|
||||
}
|
||||
16
src/FFMpeg/Filters/ComplexMedia/ComplexFilterInterface.php
Normal file
16
src/FFMpeg/Filters/ComplexMedia/ComplexFilterInterface.php
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
<?php
|
||||
|
||||
namespace FFMpeg\Filters\ComplexMedia;
|
||||
|
||||
interface ComplexFilterInterface extends ComplexCompatibleFilter
|
||||
{
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getInLabels();
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getOutLabels();
|
||||
}
|
||||
169
src/FFMpeg/Filters/ComplexMedia/ComplexFilters.php
Normal file
169
src/FFMpeg/Filters/ComplexMedia/ComplexFilters.php
Normal file
|
|
@ -0,0 +1,169 @@
|
|||
<?php
|
||||
|
||||
namespace FFMpeg\Filters\ComplexMedia;
|
||||
|
||||
use FFMpeg\Coordinate\Dimension;
|
||||
use FFMpeg\Filters\Video\PadFilter;
|
||||
use FFMpeg\Filters\Video\WatermarkFilter;
|
||||
use FFMpeg\Media\ComplexMedia;
|
||||
|
||||
class ComplexFilters
|
||||
{
|
||||
/**
|
||||
* @var ComplexMedia
|
||||
*/
|
||||
protected $media;
|
||||
|
||||
/**
|
||||
* ComplexFilters constructor.
|
||||
*
|
||||
* @param ComplexMedia $media
|
||||
*/
|
||||
public function __construct(ComplexMedia $media)
|
||||
{
|
||||
$this->media = $media;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $in
|
||||
* @param string $parameters
|
||||
* @param string $out
|
||||
*
|
||||
* @return 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
|
||||
*
|
||||
* @return ComplexFilters
|
||||
*/
|
||||
public function pad($in, Dimension $dimension, $out)
|
||||
{
|
||||
$this->media->addFilter($in, new PadFilter($dimension), $out);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a watermark image to a video.
|
||||
*
|
||||
* @param string $in
|
||||
* @param string $imagePath
|
||||
* @param string $out
|
||||
* @param array $coordinates
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function watermark($in, $imagePath, $out, array $coordinates = array())
|
||||
{
|
||||
$this->media->addFilter($in, new WatermarkFilter($imagePath, $coordinates), $out);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply "xstack" filter.
|
||||
* Warning: this filter is supported starting from 4.1 ffmpeg version.
|
||||
*
|
||||
* @param string $in
|
||||
* @param string $layout
|
||||
* @param int $inputsCount
|
||||
* @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;
|
||||
}
|
||||
|
||||
/**
|
||||
* This filter build various types of computed inputs.
|
||||
*
|
||||
* @param string $out
|
||||
* @param string|null $type
|
||||
* @param string|null $size
|
||||
* @param string|null $duration
|
||||
* @param string|null $sar
|
||||
* @param string|null $rate
|
||||
* @param string|null $level
|
||||
* @param string|null $color
|
||||
* @param int|null $alpha
|
||||
* @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(
|
||||
$out,
|
||||
$type = TestSrcFilter::TESTSRC,
|
||||
$size = '320x240',
|
||||
$duration = null,
|
||||
$sar = null,
|
||||
$rate = null,
|
||||
$level = null,
|
||||
$color = null,
|
||||
$alpha = null,
|
||||
$decimals = null
|
||||
) {
|
||||
$this->media->addFilter('',
|
||||
new TestSrcFilter($type, $size, $duration, $sar, $rate, $level, $color, $alpha, $decimals), $out);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply "anullsrc" filter.
|
||||
*
|
||||
* @param string $out
|
||||
* @param string|null $channelLayout
|
||||
* @param int|null $sampleRate
|
||||
* @param int|null $nbSamples
|
||||
*
|
||||
* @return ComplexFilters
|
||||
* @see https://ffmpeg.org/ffmpeg-filters.html#anullsrc
|
||||
*/
|
||||
public function aNullSrc(
|
||||
$out,
|
||||
$channelLayout = null,
|
||||
$sampleRate = null,
|
||||
$nbSamples = null
|
||||
) {
|
||||
$this->media->addFilter('', new ANullSrcFilter($channelLayout, $sampleRate, $nbSamples), $out);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply "sine" filter.
|
||||
*
|
||||
* @param $out
|
||||
* @param string $duration
|
||||
* @param int|null $frequency
|
||||
* @param string|null $beep_factor
|
||||
* @param int|null $sample_rate
|
||||
* @param string|null $samples_per_frame
|
||||
*
|
||||
* @return $this
|
||||
* @see https://ffmpeg.org/ffmpeg-filters.html#sine
|
||||
*/
|
||||
public function sine(
|
||||
$out,
|
||||
$duration,
|
||||
$frequency = null,
|
||||
$beep_factor = null,
|
||||
$sample_rate = null,
|
||||
$samples_per_frame = null
|
||||
) {
|
||||
$this->media->addFilter('',
|
||||
new SineFilter($duration, $frequency, $beep_factor, $sample_rate, $samples_per_frame), $out);
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
33
src/FFMpeg/Filters/ComplexMedia/CustomComplexFilter.php
Normal file
33
src/FFMpeg/Filters/ComplexMedia/CustomComplexFilter.php
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
<?php
|
||||
|
||||
namespace FFMpeg\Filters\ComplexMedia;
|
||||
|
||||
use FFMpeg\Media\ComplexMedia;
|
||||
|
||||
class CustomComplexFilter extends AbstractComplexFilter
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $filter;
|
||||
|
||||
/**
|
||||
* CustomComplexFilter constructor.
|
||||
*
|
||||
* @param string $filter
|
||||
* @param int $priority
|
||||
*/
|
||||
public function __construct($filter, $priority = 0)
|
||||
{
|
||||
parent::__construct($priority);
|
||||
$this->filter = $filter;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function applyComplex(ComplexMedia $media)
|
||||
{
|
||||
return array('-filter_complex', $this->filter);
|
||||
}
|
||||
}
|
||||
77
src/FFMpeg/Filters/ComplexMedia/SineFilter.php
Normal file
77
src/FFMpeg/Filters/ComplexMedia/SineFilter.php
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
<?php
|
||||
|
||||
namespace FFMpeg\Filters\ComplexMedia;
|
||||
|
||||
use FFMpeg\Media\ComplexMedia;
|
||||
|
||||
/**
|
||||
* @see https://ffmpeg.org/ffmpeg-filters.html#sine
|
||||
*/
|
||||
class SineFilter extends AbstractComplexFilter
|
||||
{
|
||||
/**
|
||||
* @var int|null
|
||||
*/
|
||||
private $frequency;
|
||||
|
||||
/**
|
||||
* @var string|null
|
||||
*/
|
||||
private $beep_factor;
|
||||
|
||||
/**
|
||||
* @var int|null
|
||||
*/
|
||||
private $sample_rate;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $duration;
|
||||
|
||||
/**
|
||||
* @var string|null
|
||||
*/
|
||||
private $samples_per_frame;
|
||||
|
||||
/**
|
||||
* SineComplexFilter constructor.
|
||||
*
|
||||
* @param string $duration
|
||||
* @param int|null $frequency
|
||||
* @param string|null $beep_factor
|
||||
* @param int|null $sample_rate
|
||||
* @param string|null $samples_per_frame
|
||||
* @param int $priority
|
||||
*/
|
||||
public function __construct($duration, $frequency, $beep_factor, $sample_rate, $samples_per_frame, $priority = 0)
|
||||
{
|
||||
parent::__construct($priority);
|
||||
$this->duration = $duration;
|
||||
$this->frequency = $frequency;
|
||||
$this->beep_factor = $beep_factor;
|
||||
$this->sample_rate = $sample_rate;
|
||||
$this->samples_per_frame = $samples_per_frame;
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply the complex filter to the given media.
|
||||
*
|
||||
* @param ComplexMedia $media
|
||||
*
|
||||
* @return string[] An array of arguments.
|
||||
*/
|
||||
public function applyComplex(ComplexMedia $media)
|
||||
{
|
||||
return array(
|
||||
'-filter_complex',
|
||||
'sine' . $this->buildFilterOptions(array(
|
||||
'frequency' => $this->frequency,
|
||||
'beep_factor' => $this->beep_factor,
|
||||
'sample_rate' => $this->sample_rate,
|
||||
'duration' => $this->duration,
|
||||
'samples_per_frame' => $this->samples_per_frame,
|
||||
))
|
||||
);
|
||||
}
|
||||
}
|
||||
211
src/FFMpeg/Filters/ComplexMedia/TestSrcFilter.php
Normal file
211
src/FFMpeg/Filters/ComplexMedia/TestSrcFilter.php
Normal file
|
|
@ -0,0 +1,211 @@
|
|||
<?php
|
||||
|
||||
namespace FFMpeg\Filters\ComplexMedia;
|
||||
|
||||
use FFMpeg\Media\ComplexMedia;
|
||||
|
||||
/**
|
||||
* This filter builds various types of computed inputs.
|
||||
*
|
||||
* @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
|
||||
*/
|
||||
class TestSrcFilter extends AbstractComplexFilter
|
||||
{
|
||||
/**
|
||||
* Source returns frames of size 4096x4096 of all rgb colors.
|
||||
*/
|
||||
const ALLRGB = 'allrgb';
|
||||
|
||||
/**
|
||||
* Source returns frames of size 4096x4096 of all yuv colors.
|
||||
*/
|
||||
const ALLYUV = 'allyuv';
|
||||
|
||||
/**
|
||||
* Source provides an uniformly colored input.
|
||||
*/
|
||||
const COLOR = 'color';
|
||||
|
||||
/**
|
||||
* Source provides an identity Hald CLUT.
|
||||
*/
|
||||
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';
|
||||
|
||||
/**
|
||||
* Source generates a color bars pattern, based on EBU PAL recommendations with 75% color levels.
|
||||
*/
|
||||
const PAL75BARS = 'pal75bars';
|
||||
|
||||
/**
|
||||
* Source generates a color bars pattern, based on EBU PAL recommendations with 100% color levels.
|
||||
*/
|
||||
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';
|
||||
|
||||
/**
|
||||
* Source generates a color bars pattern, based on the SMPTE Engineering Guideline EG 1-1990.
|
||||
*/
|
||||
const SMPTEBARS = 'smptebars';
|
||||
|
||||
/**
|
||||
* Source generates a color bars pattern, based on the SMPTE RP 219-2002.
|
||||
*/
|
||||
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';
|
||||
|
||||
/**
|
||||
* 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';
|
||||
|
||||
/**
|
||||
* Source generates an YUV test pattern. You should see a y, cb and cr stripe from top to bottom.
|
||||
*/
|
||||
const YUVTESTSRC = 'yuvtestsrc';
|
||||
|
||||
/**
|
||||
* @var string|null
|
||||
*/
|
||||
private $type;
|
||||
|
||||
/**
|
||||
* Specify the level of the Hald CLUT, only available in the haldclutsrc source.
|
||||
* A level of N generates a picture of N*N*N by N*N*N pixels to be used as identity matrix for 3D lookup tables.
|
||||
* Each component is coded on a 1/(N*N) scale.
|
||||
*
|
||||
* @var string|null
|
||||
*/
|
||||
private $level;
|
||||
|
||||
/**
|
||||
* Specify the color of the source, only available in the color source.
|
||||
*
|
||||
* @var string|null
|
||||
*/
|
||||
private $color;
|
||||
|
||||
/**
|
||||
* Specify the size of the sourced video.
|
||||
* This option is not available with the allrgb, allyuv, and haldclutsrc filters.
|
||||
*
|
||||
* @var string|null
|
||||
*/
|
||||
private $size;
|
||||
|
||||
/**
|
||||
* Specify the frame rate of the sourced video, as the number of frames generated per second.
|
||||
* It has to be a string in the format frame_rate_num/frame_rate_den, an integer number,
|
||||
* a floating point number or a valid video frame rate abbreviation. The default value is "25".
|
||||
*
|
||||
* @var string|null
|
||||
*/
|
||||
private $rate;
|
||||
|
||||
/**
|
||||
* Set the duration of the sourced video.
|
||||
* If not specified, or the expressed duration is negative, the video is supposed to be generated forever.
|
||||
*
|
||||
* @var string|null
|
||||
*/
|
||||
private $duration;
|
||||
|
||||
/**
|
||||
* Set the sample aspect ratio of the sourced video.
|
||||
*
|
||||
* @var string|null
|
||||
*/
|
||||
private $sar;
|
||||
|
||||
/**
|
||||
* Specify the alpha (opacity) of the background, only available in the testsrc2 source.
|
||||
* The value must be between 0 (fully transparent) and 255 (fully opaque, the default).
|
||||
*
|
||||
* @var int|null
|
||||
*/
|
||||
private $alpha;
|
||||
|
||||
/**
|
||||
* Set the number of decimals to show in the timestamp, only available in the testsrc source.
|
||||
* The displayed timestamp value will correspond to the original timestamp value multiplied
|
||||
* by the power of 10 of the specified value. Default value is 0.
|
||||
*
|
||||
* @var float|null
|
||||
*/
|
||||
private $decimals;
|
||||
|
||||
/**
|
||||
* TestSrcComplexFilter constructor.
|
||||
*
|
||||
* @param string|null $type
|
||||
* @param string|null $size
|
||||
* @param string|null $duration
|
||||
* @param string|null $sar
|
||||
* @param string|null $rate
|
||||
* @param string|null $level
|
||||
* @param string|null $color
|
||||
* @param int|null $alpha
|
||||
* @param float|null $decimals
|
||||
* @param int|null $priority
|
||||
*/
|
||||
public function __construct(
|
||||
$type = self::TESTSRC,
|
||||
$size = '320x240',
|
||||
$duration = null,
|
||||
$sar = null,
|
||||
$rate = null,
|
||||
$level = null,
|
||||
$color = null,
|
||||
$alpha = null,
|
||||
$decimals = null,
|
||||
$priority = 0
|
||||
) {
|
||||
parent::__construct($priority);
|
||||
$this->type = $type;
|
||||
$this->level = $level;
|
||||
$this->color = $color;
|
||||
$this->size = $size;
|
||||
$this->rate = $rate;
|
||||
$this->duration = $duration;
|
||||
$this->sar = $sar;
|
||||
$this->alpha = $alpha;
|
||||
$this->decimals = $decimals;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function applyComplex(ComplexMedia $media)
|
||||
{
|
||||
return array(
|
||||
'-filter_complex',
|
||||
$this->type . $this->buildFilterOptions(array(
|
||||
'level' => $this->level,
|
||||
'color' => $this->color,
|
||||
'size' => $this->size,
|
||||
'rate' => $this->rate,
|
||||
'duration' => $this->duration,
|
||||
'sar' => $this->sar,
|
||||
'alpha' => $this->alpha,
|
||||
'decimals' => $this->decimals
|
||||
))
|
||||
);
|
||||
}
|
||||
}
|
||||
71
src/FFMpeg/Filters/ComplexMedia/XStackFilter.php
Normal file
71
src/FFMpeg/Filters/ComplexMedia/XStackFilter.php
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
<?php
|
||||
|
||||
namespace FFMpeg\Filters\ComplexMedia;
|
||||
|
||||
use FFMpeg\Media\ComplexMedia;
|
||||
|
||||
/**
|
||||
* "xstack" filter.
|
||||
* Warning: this filter is supported starting from 4.1 ffmpeg version.
|
||||
*
|
||||
* @see https://ffmpeg.org/ffmpeg-filters.html#xstack
|
||||
*/
|
||||
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';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $layout;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private $inputsCount;
|
||||
|
||||
/**
|
||||
* CustomComplexFilter constructor.
|
||||
*
|
||||
* @param string $layout
|
||||
* @param int $inputsCount
|
||||
* @param int $priority
|
||||
*/
|
||||
public function __construct($layout, $inputsCount, $priority = 0)
|
||||
{
|
||||
parent::__construct($priority);
|
||||
$this->layout = $layout;
|
||||
$this->inputsCount = $inputsCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $count
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function getInputByCount($count)
|
||||
{
|
||||
$result = '';
|
||||
for ($i = 0; $i < $count; $i++) {
|
||||
$result .= '[' . $i . ':v]';
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function applyComplex(ComplexMedia $media)
|
||||
{
|
||||
return array(
|
||||
'-filter_complex',
|
||||
'xstack' . $this->buildFilterOptions(array(
|
||||
'inputs' => $this->inputsCount,
|
||||
'layout' => $this->layout
|
||||
))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -12,10 +12,12 @@
|
|||
namespace FFMpeg\Filters\Video;
|
||||
|
||||
use FFMpeg\Coordinate\Dimension;
|
||||
use FFMpeg\Media\Video;
|
||||
use FFMpeg\Filters\ComplexMedia\ComplexCompatibleFilter;
|
||||
use FFMpeg\Format\VideoInterface;
|
||||
use FFMpeg\Media\ComplexMedia;
|
||||
use FFMpeg\Media\Video;
|
||||
|
||||
class PadFilter implements VideoFilterInterface
|
||||
class PadFilter implements VideoFilterInterface, ComplexCompatibleFilter
|
||||
{
|
||||
/** @var Dimension */
|
||||
private $dimension;
|
||||
|
|
@ -48,11 +50,30 @@ class PadFilter implements VideoFilterInterface
|
|||
* {@inheritdoc}
|
||||
*/
|
||||
public function apply(Video $video, VideoInterface $format)
|
||||
{
|
||||
return $this->getCommands();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function applyComplex(ComplexMedia $media)
|
||||
{
|
||||
return $this->getCommands();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
protected function getCommands()
|
||||
{
|
||||
$commands = array();
|
||||
|
||||
$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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,10 +12,12 @@
|
|||
namespace FFMpeg\Filters\Video;
|
||||
|
||||
use FFMpeg\Exception\InvalidArgumentException;
|
||||
use FFMpeg\Filters\ComplexMedia\ComplexCompatibleFilter;
|
||||
use FFMpeg\Format\VideoInterface;
|
||||
use FFMpeg\Media\ComplexMedia;
|
||||
use FFMpeg\Media\Video;
|
||||
|
||||
class WatermarkFilter implements VideoFilterInterface
|
||||
class WatermarkFilter implements VideoFilterInterface, ComplexCompatibleFilter
|
||||
{
|
||||
/** @var string */
|
||||
private $watermarkPath;
|
||||
|
|
@ -47,6 +49,22 @@ class WatermarkFilter implements VideoFilterInterface
|
|||
* {@inheritdoc}
|
||||
*/
|
||||
public function apply(Video $video, VideoInterface $format)
|
||||
{
|
||||
return $this->getCommands();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function applyComplex(ComplexMedia $media)
|
||||
{
|
||||
return $this->getCommands();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
protected function getCommands()
|
||||
{
|
||||
$position = isset($this->coordinates['position']) ? $this->coordinates['position'] : 'absolute';
|
||||
|
||||
|
|
@ -55,7 +73,7 @@ class WatermarkFilter implements VideoFilterInterface
|
|||
if (isset($this->coordinates['top'])) {
|
||||
$y = $this->coordinates['top'];
|
||||
} elseif (isset($this->coordinates['bottom'])) {
|
||||
$y = sprintf('main_h - %d - overlay_h', $this->coordinates['bottom']);
|
||||
$y = 'main_h - ' . $this->coordinates['bottom'] . ' - overlay_h';
|
||||
} else {
|
||||
$y = 0;
|
||||
}
|
||||
|
|
@ -63,7 +81,7 @@ class WatermarkFilter implements VideoFilterInterface
|
|||
if (isset($this->coordinates['left'])) {
|
||||
$x = $this->coordinates['left'];
|
||||
} elseif (isset($this->coordinates['right'])) {
|
||||
$x = sprintf('main_w - %d - overlay_w', $this->coordinates['right']);
|
||||
$x = 'main_w - ' . $this->coordinates['right'] . ' - overlay_w';
|
||||
} else {
|
||||
$x = 0;
|
||||
}
|
||||
|
|
@ -75,6 +93,9 @@ class WatermarkFilter implements VideoFilterInterface
|
|||
break;
|
||||
}
|
||||
|
||||
return array('-vf', sprintf('movie=%s [watermark]; [in][watermark] overlay=%s:%s [out]', $this->watermarkPath, $x, $y));
|
||||
return array(
|
||||
'-vf',
|
||||
'movie=' . $this->watermarkPath . ' [watermark]; [in][watermark] overlay=' . $x . ':' . $y . ' [out]',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue