Merge branch '0.4'
This commit is contained in:
		
				commit
				
					
						f3893b9459
					
				
			
		
					 11 changed files with 165 additions and 8 deletions
				
			
		|  | @ -1,7 +1,11 @@ | ||||||
| CHANGELOG | CHANGELOG | ||||||
| --------- | --------- | ||||||
| 
 | 
 | ||||||
| * 0.4.2 (xx-xx-xx) | * 0.4.3 (12-02-2013) | ||||||
|  | 
 | ||||||
|  |   * Fix using rotate and resize filters at the same time (#78) | ||||||
|  | 
 | ||||||
|  | * 0.4.2 (11-29-2013) | ||||||
| 
 | 
 | ||||||
|   * Add Rotate filter. |   * Add Rotate filter. | ||||||
|   * Remove time_start metadata when using synchronize filter |   * Remove time_start metadata when using synchronize filter | ||||||
|  |  | ||||||
|  | @ -10,12 +10,20 @@ Check another amazing repo : [PHP FFMpeg extras](https://github.com/alchemy-fr/P | ||||||
| 
 | 
 | ||||||
| ## Your attention please | ## Your attention please | ||||||
| 
 | 
 | ||||||
|  | ### How this library works : | ||||||
|  | 
 | ||||||
| This library requires a working FFMpeg install. You will need both FFMpeg and FFProbe binaries to use it. | This library requires a working FFMpeg install. You will need both FFMpeg and FFProbe binaries to use it. | ||||||
| Be sure that these binaries can be located with system PATH to get the benefit of the binary detection, | Be sure that these binaries can be located with system PATH to get the benefit of the binary detection, | ||||||
| otherwise you should have to explicitely give the binaries path on load. | otherwise you should have to explicitely give the binaries path on load. | ||||||
| 
 | 
 | ||||||
| For Windows users : Please find the binaries at http://ffmpeg.zeranoe.com/builds/. | For Windows users : Please find the binaries at http://ffmpeg.zeranoe.com/builds/. | ||||||
| 
 | 
 | ||||||
|  | ### Known issues : | ||||||
|  | 
 | ||||||
|  | - Using rotate and resize will produce a corrupted output when using  | ||||||
|  | [libav](http://libav.org/) 0.8. The bug is fixed in version 9. This bug does not  | ||||||
|  | appear in latest ffmpeg version. | ||||||
|  | 
 | ||||||
| ## Installation | ## Installation | ||||||
| 
 | 
 | ||||||
| The recommended way to install PHP-FFMpeg is through [Composer](https://getcomposer.org). | The recommended way to install PHP-FFMpeg is through [Composer](https://getcomposer.org). | ||||||
|  |  | ||||||
|  | @ -226,8 +226,13 @@ class FFProbe | ||||||
|         $parseIsToDo = false; |         $parseIsToDo = false; | ||||||
| 
 | 
 | ||||||
|         if ($allowJson && $this->optionsTester->has('-print_format')) { |         if ($allowJson && $this->optionsTester->has('-print_format')) { | ||||||
|  |             // allowed in latest PHP-FFmpeg version
 | ||||||
|             $commands[] = '-print_format'; |             $commands[] = '-print_format'; | ||||||
|             $commands[] = 'json'; |             $commands[] = 'json'; | ||||||
|  |         } elseif ($allowJson && $this->optionsTester->has('-of')) { | ||||||
|  |             // option has changed in avconv 9
 | ||||||
|  |             $commands[] = '-of'; | ||||||
|  |             $commands[] = 'json'; | ||||||
|         } else { |         } else { | ||||||
|             $parseIsToDo = true; |             $parseIsToDo = true; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  | @ -50,6 +50,21 @@ abstract class AbstractData implements \Countable | ||||||
|         return $this->properties[$property]; |         return $this->properties[$property]; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     /** | ||||||
|  |      * Sets the property value given its name. | ||||||
|  |      * | ||||||
|  |      * @param  string $property | ||||||
|  |      * @param  mixed  $value | ||||||
|  |      * | ||||||
|  |      * @return AbstractData | ||||||
|  |      */ | ||||||
|  |     public function set($property, $value) | ||||||
|  |     { | ||||||
|  |         $this->properties[$property] = $value; | ||||||
|  | 
 | ||||||
|  |         return $this; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     /** |     /** | ||||||
|      * Returns all property names. |      * Returns all property names. | ||||||
|      * |      * | ||||||
|  |  | ||||||
|  | @ -55,6 +55,16 @@ class RotateFilter implements VideoFilterInterface | ||||||
|      */ |      */ | ||||||
|     public function apply(Video $video, VideoInterface $format) |     public function apply(Video $video, VideoInterface $format) | ||||||
|     { |     { | ||||||
|  |         if (in_array($this->angle, array(self::ROTATE_90, self::ROTATE_270), true)) { | ||||||
|  |             foreach ($video->getStreams()->videos() as $stream) { | ||||||
|  |                 if ($stream->has('width') && $stream->has('height')) { | ||||||
|  |                     $width = $stream->get('width'); | ||||||
|  |                     $stream->set('width', $stream->get('height')); | ||||||
|  |                     $stream->set('height', $width); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|         return array('-vf', $this->angle, '-metadata:s:v:0', 'rotate=0'); |         return array('-vf', $this->angle, '-metadata:s:v:0', 'rotate=0'); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -96,9 +96,9 @@ class VideoFilters extends AudioFilters | ||||||
|         return $this; |         return $this; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public function rotate($angle, $priority = 0) |     public function rotate($angle) | ||||||
|     { |     { | ||||||
|         $this->media->addFilter(new RotateFilter($angle, $priority)); |         $this->media->addFilter(new RotateFilter($angle, 30)); | ||||||
| 
 | 
 | ||||||
|         return $this; |         return $this; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  | @ -16,12 +16,18 @@ use FFMpeg\FFProbe\DataMapping\StreamCollection; | ||||||
| 
 | 
 | ||||||
| abstract class AbstractStreamableMedia extends AbstractMediaType | abstract class AbstractStreamableMedia extends AbstractMediaType | ||||||
| { | { | ||||||
|  |     private $streams; | ||||||
|  | 
 | ||||||
|     /** |     /** | ||||||
|      * @return StreamCollection |      * @return StreamCollection | ||||||
|      */ |      */ | ||||||
|     public function getStreams() |     public function getStreams() | ||||||
|     { |     { | ||||||
|         return $this->ffprobe->streams($this->pathfile); |         if (null === $this->streams) { | ||||||
|  |             $this->streams = $this->ffprobe->streams($this->pathfile); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         return $this->streams; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|  |  | ||||||
|  | @ -6,6 +6,9 @@ use FFMpeg\FFMpeg; | ||||||
| 
 | 
 | ||||||
| abstract class FunctionalTestCase extends \PHPUnit_Framework_TestCase | abstract class FunctionalTestCase extends \PHPUnit_Framework_TestCase | ||||||
| { | { | ||||||
|  |     /** | ||||||
|  |      * @return FFMpeg | ||||||
|  |      */ | ||||||
|     public function getFFMpeg() |     public function getFFMpeg() | ||||||
|     { |     { | ||||||
|         return FFMpeg::create(array('timeout' => 300)); |         return FFMpeg::create(array('timeout' => 300)); | ||||||
|  |  | ||||||
|  | @ -2,6 +2,9 @@ | ||||||
| 
 | 
 | ||||||
| namespace FFMpeg\Functional; | namespace FFMpeg\Functional; | ||||||
| 
 | 
 | ||||||
|  | use FFMpeg\Coordinate\Dimension; | ||||||
|  | use FFMpeg\Filters\Video\ResizeFilter; | ||||||
|  | use FFMpeg\Filters\Video\RotateFilter; | ||||||
| use FFMpeg\Format\Video\X264; | use FFMpeg\Format\Video\X264; | ||||||
| use FFMpeg\Media\Video; | use FFMpeg\Media\Video; | ||||||
| 
 | 
 | ||||||
|  | @ -54,4 +57,62 @@ class VideoTranscodeTest extends FunctionalTestCase | ||||||
|         $this->setExpectedException('FFMpeg\Exception\RuntimeException'); |         $this->setExpectedException('FFMpeg\Exception\RuntimeException'); | ||||||
|         $video->save(new X264('libvo_aacenc'), __DIR__ . '/output/output-x264.mp4'); |         $video->save(new X264('libvo_aacenc'), __DIR__ . '/output/output-x264.mp4'); | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  |     public function testTranscodePortraitVideo() | ||||||
|  |     { | ||||||
|  |         $info = $this->getNameAndVersion(); | ||||||
|  | 
 | ||||||
|  |         if ($info['name'] === 'avconv' && version_compare($info['version'], '0.9', '<')) { | ||||||
|  |             $this->markTestSkipped('This version of avconv is buggy and does not support this test.'); | ||||||
|  |         } | ||||||
|  |          | ||||||
|  |         $filename = __DIR__ . '/output/output-x264.mp4'; | ||||||
|  |         if (is_file($filename)) { | ||||||
|  |             unlink(__DIR__ . '/output/output-x264.mp4'); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         $ffmpeg = $this->getFFMpeg(); | ||||||
|  |         $video = $ffmpeg->open(__DIR__ . '/../../files/portrait.MOV'); | ||||||
|  | 
 | ||||||
|  |         $video->filters() | ||||||
|  |             ->resize(new Dimension(320, 240), ResizeFilter::RESIZEMODE_INSET) | ||||||
|  |             ->rotate(RotateFilter::ROTATE_90); | ||||||
|  |         $video->save(new X264('libvo_aacenc'), $filename); | ||||||
|  | 
 | ||||||
|  |         $dimension = $ffmpeg->getFFProbe() | ||||||
|  |             ->streams($filename) | ||||||
|  |             ->videos() | ||||||
|  |             ->first() | ||||||
|  |             ->getDimensions(); | ||||||
|  | 
 | ||||||
|  |         $this->assertLessThan(1, $dimension->getRatio(false)->getValue()); | ||||||
|  |         $this->assertEquals(240, $dimension->getHeight()); | ||||||
|  | 
 | ||||||
|  |         $this->assertFileExists($filename); | ||||||
|  |         unlink($filename); | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     private function getNameAndVersion() | ||||||
|  |     { | ||||||
|  |         $binary = $this | ||||||
|  |             ->getFFMpeg() | ||||||
|  |             ->getFFMpegDriver() | ||||||
|  |             ->getProcessBuilderFactory() | ||||||
|  |             ->getBinary(); | ||||||
|  |          | ||||||
|  |         $output = $matches = null; | ||||||
|  |         exec($binary . ' -version 2>&1', $output); | ||||||
|  | 
 | ||||||
|  |         if (!isset($output[0])) { | ||||||
|  |             return array('name' => null, 'version' => null); | ||||||
|  |         } | ||||||
|  |          | ||||||
|  |         preg_match('/^([a-z]+)\s+version\s+([0-9\.]+)/i', $output[0], $matches); | ||||||
|  | 
 | ||||||
|  |         if (count($matches) > 0) { | ||||||
|  |             return array('name' => $matches[1], 'version' => $matches[2]); | ||||||
|  |         } | ||||||
|  |          | ||||||
|  |         return array('name' => null, 'version' => null); | ||||||
|  |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -2,18 +2,63 @@ | ||||||
| 
 | 
 | ||||||
| namespace FFMpeg\Tests\Filters\Video; | namespace FFMpeg\Tests\Filters\Video; | ||||||
| 
 | 
 | ||||||
|  | use FFMpeg\FFProbe\DataMapping\Stream; | ||||||
|  | use FFMpeg\FFProbe\DataMapping\StreamCollection; | ||||||
| use FFMpeg\Filters\Video\RotateFilter; | use FFMpeg\Filters\Video\RotateFilter; | ||||||
| use FFMpeg\Tests\TestCase; | use FFMpeg\Tests\TestCase; | ||||||
| 
 | 
 | ||||||
| class RotateFilterTest extends TestCase | class RotateFilterTest extends TestCase | ||||||
| { | { | ||||||
|     public function testApply() |     /** | ||||||
|  |      * @dataProvider provide90degresTranspositions | ||||||
|  |      */ | ||||||
|  |     public function testApplyWithSizeTransformation($value) | ||||||
|     { |     { | ||||||
|  |         $stream = new Stream(array('width' => 320, 'height' => 240, 'codec_type' => 'video')); | ||||||
|  |         $streams = new StreamCollection(array($stream)); | ||||||
|  | 
 | ||||||
|         $video = $this->getVideoMock(); |         $video = $this->getVideoMock(); | ||||||
|  |         $video->expects($this->once()) | ||||||
|  |             ->method('getStreams') | ||||||
|  |             ->will($this->returnValue($streams)); | ||||||
|  | 
 | ||||||
|         $format = $this->getMock('FFMpeg\Format\VideoInterface'); |         $format = $this->getMock('FFMpeg\Format\VideoInterface'); | ||||||
| 
 | 
 | ||||||
|         $filter = new RotateFilter(RotateFilter::ROTATE_90); |         $filter = new RotateFilter($value); | ||||||
|         $this->assertEquals(array('-vf', RotateFilter::ROTATE_90, '-metadata:s:v:0', 'rotate=0'), $filter->apply($video, $format)); |         $this->assertEquals(array('-vf', $value, '-metadata:s:v:0', 'rotate=0'), $filter->apply($video, $format)); | ||||||
|  | 
 | ||||||
|  |         $this->assertEquals(240, $stream->get('width')); | ||||||
|  |         $this->assertEquals(320, $stream->get('height')); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public function provide90degresTranspositions() | ||||||
|  |     { | ||||||
|  |         return array( | ||||||
|  |             array(RotateFilter::ROTATE_90), | ||||||
|  |             array(RotateFilter::ROTATE_270), | ||||||
|  |         ); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * @dataProvider provideDegresWithoutTranspositions | ||||||
|  |      */ | ||||||
|  |     public function testApplyWithoutSizeTransformation($value) | ||||||
|  |     { | ||||||
|  |         $video = $this->getVideoMock(); | ||||||
|  |         $video->expects($this->never()) | ||||||
|  |             ->method('getStreams'); | ||||||
|  | 
 | ||||||
|  |         $format = $this->getMock('FFMpeg\Format\VideoInterface'); | ||||||
|  | 
 | ||||||
|  |         $filter = new RotateFilter($value); | ||||||
|  |         $this->assertEquals(array('-vf', $value, '-metadata:s:v:0', 'rotate=0'), $filter->apply($video, $format)); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public function provideDegresWithoutTranspositions() | ||||||
|  |     { | ||||||
|  |         return array( | ||||||
|  |             array(RotateFilter::ROTATE_180), | ||||||
|  |         ); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|  |  | ||||||
							
								
								
									
										
											BIN
										
									
								
								tests/files/portrait.MOV
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								tests/files/portrait.MOV
									
										
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue