diff --git a/src/FFMpeg/Coordinate/Dimension.php b/src/FFMpeg/Coordinate/Dimension.php index 018d4ed..33ebaea 100644 --- a/src/FFMpeg/Coordinate/Dimension.php +++ b/src/FFMpeg/Coordinate/Dimension.php @@ -40,7 +40,7 @@ class Dimension /** * Returns width. * - * @return width + * @return integer */ public function getWidth() { diff --git a/src/FFMpeg/FFMpegServiceProvider.php b/src/FFMpeg/FFMpegServiceProvider.php index 4bb489b..6aa9735 100644 --- a/src/FFMpeg/FFMpegServiceProvider.php +++ b/src/FFMpeg/FFMpegServiceProvider.php @@ -12,8 +12,6 @@ namespace FFMpeg; use Doctrine\Common\Cache\ArrayCache; -use FFMpeg\FFMpeg; -use FFMpeg\FFProbe; use Silex\Application; use Silex\ServiceProviderInterface; diff --git a/src/FFMpeg/Filters/Audio/AudioFilters.php b/src/FFMpeg/Filters/Audio/AudioFilters.php index ddce8f1..fe328c5 100644 --- a/src/FFMpeg/Filters/Audio/AudioFilters.php +++ b/src/FFMpeg/Filters/Audio/AudioFilters.php @@ -3,7 +3,6 @@ namespace FFMpeg\Filters\Audio; use FFMpeg\Media\Audio; -use FFMpeg\Filters\Audio\AudioResamplableFilter; class AudioFilters { diff --git a/src/FFMpeg/Filters/Video/CustomFilter.php b/src/FFMpeg/Filters/Video/CustomFilter.php new file mode 100644 index 0000000..eb75079 --- /dev/null +++ b/src/FFMpeg/Filters/Video/CustomFilter.php @@ -0,0 +1,52 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace FFMpeg\Filters\Video; + +use FFMpeg\Format\VideoInterface; +use FFMpeg\Media\Video; + +class CustomFilter implements VideoFilterInterface +{ + /** @var string */ + private $filter; + /** @var integer */ + private $priority; + + /** + * A custom filter, useful if you want to build complex filters + * + * @param string $filter + * @param int $priority + */ + public function __construct($filter, $priority = 0) + { + $this->filter = $filter; + $this->priority = $priority; + } + + /** + * {@inheritdoc} + */ + public function getPriority() + { + return $this->priority; + } + + /** + * {@inheritdoc} + */ + public function apply(Video $video, VideoInterface $format) + { + $commands = array('-vf', $this->filter); + + return $commands; + } +} diff --git a/src/FFMpeg/Filters/Video/VideoFilters.php b/src/FFMpeg/Filters/Video/VideoFilters.php index 30b4b2a..55281e4 100644 --- a/src/FFMpeg/Filters/Video/VideoFilters.php +++ b/src/FFMpeg/Filters/Video/VideoFilters.php @@ -12,6 +12,7 @@ namespace FFMpeg\Filters\Video; use FFMpeg\Media\Video; +use FFMpeg\Coordinate\TimeCode; use FFMpeg\Coordinate\Dimension; use FFMpeg\Coordinate\FrameRate; use FFMpeg\Filters\Audio\AudioResamplableFilter; @@ -102,4 +103,17 @@ class VideoFilters extends AudioFilters return $this; } + + /** + * @param string $imagePath + * @param array $coordinates + * + * @return $this + */ + public function watermark($imagePath, array $coordinates = array()) + { + $this->media->addFilter(new WatermarkFilter($imagePath, $coordinates)); + + return $this; + } } diff --git a/src/FFMpeg/Filters/Video/WatermarkFilter.php b/src/FFMpeg/Filters/Video/WatermarkFilter.php new file mode 100644 index 0000000..40bb8fc --- /dev/null +++ b/src/FFMpeg/Filters/Video/WatermarkFilter.php @@ -0,0 +1,75 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace FFMpeg\Filters\Video; + +use FFMpeg\Format\VideoInterface; +use FFMpeg\Media\Video; + +class WatermarkFilter implements VideoFilterInterface +{ + /** @var string */ + private $watermarkPath; + /** @var array */ + private $coordinates; + /** @var integer */ + private $priority; + + public function __construct($watermarkPath, array $coordinates = array(), $priority = 0) + { + $this->watermarkPath = $watermarkPath; + $this->coordinates = $coordinates; + $this->priority = $priority; + } + + /** + * {@inheritdoc} + */ + public function getPriority() + { + return $this->priority; + } + + /** + * {@inheritdoc} + */ + public function apply(Video $video, VideoInterface $format) + { + $position = isset($this->coordinates['position']) ? $this->coordinates['position'] : 'absolute'; + + switch ($position) { + case 'relative': + if (isset($this->coordinates['top'])) { + $y = $this->coordinates['top']; + } elseif (isset($this->coordinates['bottom'])) { + $y = sprintf('main_h - %d - overlay_h', $this->coordinates['bottom']); + } else { + $y = 0; + } + + if (isset($this->coordinates['left'])) { + $x = $this->coordinates['left']; + } elseif (isset($this->coordinates['right'])) { + $x = sprintf('main_w - %d - overlay_w', $this->coordinates['right']); + } else { + $x = 0; + } + + break; + default: + $x = isset($this->coordinates['x']) ? $this->coordinates['x'] : 0; + $y = isset($this->coordinates['y']) ? $this->coordinates['y'] : 0; + break; + } + + return array('-vf', sprintf('overlay %s:%s', $x, $y)); + } +} diff --git a/src/FFMpeg/Format/Video/X264.php b/src/FFMpeg/Format/Video/X264.php index 40010fd..80e4b67 100644 --- a/src/FFMpeg/Format/Video/X264.php +++ b/src/FFMpeg/Format/Video/X264.php @@ -16,6 +16,9 @@ namespace FFMpeg\Format\Video; */ class X264 extends DefaultVideo { + /** @var boolean */ + private $bframesSupport = true; + public function __construct($audioCodec = 'libfaac', $videoCodec = 'libx264') { $this @@ -28,7 +31,19 @@ class X264 extends DefaultVideo */ public function supportBFrames() { - return true; + return $this->bframesSupport; + } + + /** + * @param $support + * + * @return X264 + */ + public function setBFramesSupport($support) + { + $this->bframesSupport = $support; + + return $this; } /** @@ -55,6 +70,9 @@ class X264 extends DefaultVideo return 2; } + /** + * @return int + */ public function getModulus() { return 2; diff --git a/src/FFMpeg/Media/AbstractMediaType.php b/src/FFMpeg/Media/AbstractMediaType.php index 45bb0c6..5523c0b 100644 --- a/src/FFMpeg/Media/AbstractMediaType.php +++ b/src/FFMpeg/Media/AbstractMediaType.php @@ -14,7 +14,6 @@ namespace FFMpeg\Media; use FFMpeg\Driver\FFMpegDriver; use FFMpeg\FFProbe; use FFMpeg\Filters\FiltersCollection; -use FFMpeg\Media\MediaTypeInterface; abstract class AbstractMediaType implements MediaTypeInterface { diff --git a/src/FFMpeg/Media/Frame.php b/src/FFMpeg/Media/Frame.php index b50e549..7b08eb3 100644 --- a/src/FFMpeg/Media/Frame.php +++ b/src/FFMpeg/Media/Frame.php @@ -18,7 +18,6 @@ use FFMpeg\Driver\FFMpegDriver; use FFMpeg\FFProbe; use FFMpeg\Exception\RuntimeException; use FFMpeg\Coordinate\TimeCode; -use FFMpeg\Media\Video; class Frame extends AbstractMediaType { diff --git a/src/FFMpeg/Media/Video.php b/src/FFMpeg/Media/Video.php index ae2996f..f802f5b 100644 --- a/src/FFMpeg/Media/Video.php +++ b/src/FFMpeg/Media/Video.php @@ -22,7 +22,6 @@ use FFMpeg\Format\FormatInterface; use FFMpeg\Format\ProgressableInterface; use FFMpeg\Format\AudioInterface; use FFMpeg\Format\VideoInterface; -use FFMpeg\Media\Frame; use Neutron\TemporaryFilesystem\Manager as FsManager; class Video extends Audio @@ -69,12 +68,12 @@ class Video extends Audio if ($this->driver->getConfiguration()->has('ffmpeg.threads')) { $filters->add(new SimpleFilter(array('-threads', $this->driver->getConfiguration()->get('ffmpeg.threads')))); } - if ($format instanceOf VideoInterface) { + if ($format instanceof VideoInterface) { if (null !== $format->getVideoCodec()) { $filters->add(new SimpleFilter(array('-vcodec', $format->getVideoCodec()))); } } - if ($format instanceOf AudioInterface) { + if ($format instanceof AudioInterface) { if (null !== $format->getAudioCodec()) { $filters->add(new SimpleFilter(array('-acodec', $format->getAudioCodec()))); } @@ -84,7 +83,7 @@ class Video extends Audio $commands = array_merge($commands, $filter->apply($this, $format)); } - if ($format instanceOf VideoInterface) { + if ($format instanceof VideoInterface) { $commands[] = '-b:v'; $commands[] = $format->getKiloBitrate() . 'k'; $commands[] = '-refs'; @@ -109,7 +108,7 @@ class Video extends Audio $commands[] = '1'; } - if ($format instanceOf AudioInterface) { + if ($format instanceof AudioInterface) { if (null !== $format->getAudioKiloBitrate()) { $commands[] = '-b:a'; $commands[] = $format->getAudioKiloBitrate() . 'k'; diff --git a/tests/FFMpeg/Tests/Filters/Video/CustomFilterTest.php b/tests/FFMpeg/Tests/Filters/Video/CustomFilterTest.php new file mode 100644 index 0000000..ff8ad75 --- /dev/null +++ b/tests/FFMpeg/Tests/Filters/Video/CustomFilterTest.php @@ -0,0 +1,20 @@ +getVideoMock(); + $format = $this->getMock('FFMpeg\Format\VideoInterface'); + + $filter = new CustomFilter('whatever i put would end up as a filter'); + $this->assertEquals(array('-vf', 'whatever i put would end up as a filter'), $filter->apply($video, $format)); + } +} diff --git a/tests/FFMpeg/Tests/Filters/Video/WatermarkFilterTest.php b/tests/FFMpeg/Tests/Filters/Video/WatermarkFilterTest.php new file mode 100644 index 0000000..82fb3e1 --- /dev/null +++ b/tests/FFMpeg/Tests/Filters/Video/WatermarkFilterTest.php @@ -0,0 +1,63 @@ + 320, 'height' => 240, 'codec_type' => 'video')); + $streams = new StreamCollection(array($stream)); + + $video = $this->getVideoMock(); + + $format = $this->getMock('FFMpeg\Format\VideoInterface'); + + $filter = new WatermarkFilter(__DIR__ . '/../../files/watermark.png'); + $this->assertEquals(array('-vf', 'overlay 0:0'), $filter->apply($video, $format)); + + // check size of video is unchanged + $this->assertEquals(320, $stream->get('width')); + $this->assertEquals(240, $stream->get('height')); + } + + public function testDifferentCoordinaates() + { + $video = $this->getVideoMock(); + $format = $this->getMock('FFMpeg\Format\VideoInterface'); + + // test position absolute + $filter = new WatermarkFilter(__DIR__ . '/../../files/watermark.png', array( + 'position' => 'absolute', + 'x' => 10, 'y' => 5 + )); + $this->assertEquals(array('-vf', 'overlay 10:5'), $filter->apply($video, $format)); + + // test position relative + $filter = new WatermarkFilter(__DIR__ . '/../../files/watermark.png', array( + 'position' => 'relative', + 'bottom' => 10, 'left' => 5 + )); + $this->assertEquals(array('-vf', 'overlay 5:main_h - 10 - overlay_h'), $filter->apply($video, $format)); + + // test position relative + $filter = new WatermarkFilter(__DIR__ . '/../../files/watermark.png', array( + 'position' => 'relative', + 'bottom' => 5, 'right' => 4 + )); + $this->assertEquals(array('-vf', 'overlay main_w - 4 - overlay_w:main_h - 5 - overlay_h'), $filter->apply($video, $format)); + + // test position relative + $filter = new WatermarkFilter(__DIR__ . '/../../files/watermark.png', array( + 'position' => 'relative', + 'left' => 5, 'top' => 11 + )); + $this->assertEquals(array('-vf', 'overlay 5:11'), $filter->apply($video, $format)); + } +} diff --git a/tests/files/waternark.png b/tests/files/waternark.png new file mode 100644 index 0000000..0c96e54 Binary files /dev/null and b/tests/files/waternark.png differ