Merge branch 'letsface-feature/custom-filter'
* letsface-feature/custom-filter: Minor fixes Fix CS Allow to set bframe support in a format Added custom filter support Added watermark functionality and unit tests Fix Doc comment (width => integer) Add 'use FFMpeg\Coordinate\TimeCode;'
This commit is contained in:
		
				commit
				
					
						2da17ba59b
					
				
			
		
					 13 changed files with 248 additions and 12 deletions
				
			
		|  | @ -40,7 +40,7 @@ class Dimension | |||
|     /** | ||||
|      * Returns width. | ||||
|      * | ||||
|      * @return width | ||||
|      * @return integer | ||||
|      */ | ||||
|     public function getWidth() | ||||
|     { | ||||
|  |  | |||
|  | @ -12,8 +12,6 @@ | |||
| namespace FFMpeg; | ||||
| 
 | ||||
| use Doctrine\Common\Cache\ArrayCache; | ||||
| use FFMpeg\FFMpeg; | ||||
| use FFMpeg\FFProbe; | ||||
| use Silex\Application; | ||||
| use Silex\ServiceProviderInterface; | ||||
| 
 | ||||
|  |  | |||
|  | @ -3,7 +3,6 @@ | |||
| namespace FFMpeg\Filters\Audio; | ||||
| 
 | ||||
| use FFMpeg\Media\Audio; | ||||
| use FFMpeg\Filters\Audio\AudioResamplableFilter; | ||||
| 
 | ||||
| class AudioFilters | ||||
| { | ||||
|  |  | |||
							
								
								
									
										52
									
								
								src/FFMpeg/Filters/Video/CustomFilter.php
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								src/FFMpeg/Filters/Video/CustomFilter.php
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,52 @@ | |||
| <?php | ||||
| 
 | ||||
| /* | ||||
|  * This file is part of PHP-FFmpeg. | ||||
|  * | ||||
|  * (c) Alchemy <dev.team@alchemy.fr> | ||||
|  * | ||||
|  * 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; | ||||
|     } | ||||
| } | ||||
|  | @ -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; | ||||
|     } | ||||
| } | ||||
|  |  | |||
							
								
								
									
										75
									
								
								src/FFMpeg/Filters/Video/WatermarkFilter.php
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										75
									
								
								src/FFMpeg/Filters/Video/WatermarkFilter.php
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,75 @@ | |||
| <?php | ||||
| 
 | ||||
| /* | ||||
|  * This file is part of PHP-FFmpeg. | ||||
|  * | ||||
|  * (c) Alchemy <dev.team@alchemy.fr> | ||||
|  * | ||||
|  * 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)); | ||||
|     } | ||||
| } | ||||
|  | @ -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; | ||||
|  |  | |||
|  | @ -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 | ||||
| { | ||||
|  |  | |||
|  | @ -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 | ||||
| { | ||||
|  |  | |||
|  | @ -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'; | ||||
|  |  | |||
							
								
								
									
										20
									
								
								tests/FFMpeg/Tests/Filters/Video/CustomFilterTest.php
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								tests/FFMpeg/Tests/Filters/Video/CustomFilterTest.php
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,20 @@ | |||
| <?php | ||||
| 
 | ||||
| namespace FFMpeg\Tests\Filters\Video; | ||||
| 
 | ||||
| use FFMpeg\Filters\Video\CustomFilter; | ||||
| use FFMpeg\Filters\Video\FrameRateFilter; | ||||
| use FFMpeg\Tests\TestCase; | ||||
| use FFMpeg\Coordinate\FrameRate; | ||||
| 
 | ||||
| class CustomFilterTest extends TestCase | ||||
| { | ||||
|     public function testApplyCustomFilter() | ||||
|     { | ||||
|         $video = $this->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)); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										63
									
								
								tests/FFMpeg/Tests/Filters/Video/WatermarkFilterTest.php
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								tests/FFMpeg/Tests/Filters/Video/WatermarkFilterTest.php
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,63 @@ | |||
| <?php | ||||
| 
 | ||||
| namespace FFMpeg\Tests\Filters\Video; | ||||
| 
 | ||||
| use FFMpeg\FFProbe\DataMapping\Stream; | ||||
| use FFMpeg\FFProbe\DataMapping\StreamCollection; | ||||
| use FFMpeg\Filters\Video\RotateFilter; | ||||
| use FFMpeg\Filters\Video\WatermarkFilter; | ||||
| use FFMpeg\Tests\TestCase; | ||||
| 
 | ||||
| class WatermarkFilterTest extends TestCase | ||||
| { | ||||
|     public function testApplyWatermark() | ||||
|     { | ||||
|         $stream = new Stream(array('width' => 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)); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										
											BIN
										
									
								
								tests/files/waternark.png
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								tests/files/waternark.png
									
										
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 3.2 KiB | 
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue