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 | ||||
| --------- | ||||
| 
 | ||||
| * 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. | ||||
|   * 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 | ||||
| 
 | ||||
| ### How this library works : | ||||
| 
 | ||||
| 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, | ||||
| 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/. | ||||
| 
 | ||||
| ### 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 | ||||
| 
 | ||||
| The recommended way to install PHP-FFMpeg is through [Composer](https://getcomposer.org). | ||||
|  |  | |||
|  | @ -226,8 +226,13 @@ class FFProbe | |||
|         $parseIsToDo = false; | ||||
| 
 | ||||
|         if ($allowJson && $this->optionsTester->has('-print_format')) { | ||||
|             // allowed in latest PHP-FFmpeg version
 | ||||
|             $commands[] = '-print_format'; | ||||
|             $commands[] = 'json'; | ||||
|         } elseif ($allowJson && $this->optionsTester->has('-of')) { | ||||
|             // option has changed in avconv 9
 | ||||
|             $commands[] = '-of'; | ||||
|             $commands[] = 'json'; | ||||
|         } else { | ||||
|             $parseIsToDo = true; | ||||
|         } | ||||
|  |  | |||
|  | @ -50,6 +50,21 @@ abstract class AbstractData implements \Countable | |||
|         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. | ||||
|      * | ||||
|  |  | |||
|  | @ -55,6 +55,16 @@ class RotateFilter implements VideoFilterInterface | |||
|      */ | ||||
|     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'); | ||||
|     } | ||||
| 
 | ||||
|  |  | |||
|  | @ -96,9 +96,9 @@ class VideoFilters extends AudioFilters | |||
|         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; | ||||
|     } | ||||
|  |  | |||
|  | @ -16,12 +16,18 @@ use FFMpeg\FFProbe\DataMapping\StreamCollection; | |||
| 
 | ||||
| abstract class AbstractStreamableMedia extends AbstractMediaType | ||||
| { | ||||
|     private $streams; | ||||
| 
 | ||||
|     /** | ||||
|      * @return StreamCollection | ||||
|      */ | ||||
|     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 | ||||
| { | ||||
|     /** | ||||
|      * @return FFMpeg | ||||
|      */ | ||||
|     public function getFFMpeg() | ||||
|     { | ||||
|         return FFMpeg::create(array('timeout' => 300)); | ||||
|  |  | |||
|  | @ -2,6 +2,9 @@ | |||
| 
 | ||||
| namespace FFMpeg\Functional; | ||||
| 
 | ||||
| use FFMpeg\Coordinate\Dimension; | ||||
| use FFMpeg\Filters\Video\ResizeFilter; | ||||
| use FFMpeg\Filters\Video\RotateFilter; | ||||
| use FFMpeg\Format\Video\X264; | ||||
| use FFMpeg\Media\Video; | ||||
| 
 | ||||
|  | @ -54,4 +57,62 @@ class VideoTranscodeTest extends FunctionalTestCase | |||
|         $this->setExpectedException('FFMpeg\Exception\RuntimeException'); | ||||
|         $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; | ||||
| 
 | ||||
| use FFMpeg\FFProbe\DataMapping\Stream; | ||||
| use FFMpeg\FFProbe\DataMapping\StreamCollection; | ||||
| use FFMpeg\Filters\Video\RotateFilter; | ||||
| use FFMpeg\Tests\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->expects($this->once()) | ||||
|             ->method('getStreams') | ||||
|             ->will($this->returnValue($streams)); | ||||
| 
 | ||||
|         $format = $this->getMock('FFMpeg\Format\VideoInterface'); | ||||
| 
 | ||||
|         $filter = new RotateFilter(RotateFilter::ROTATE_90); | ||||
|         $this->assertEquals(array('-vf', RotateFilter::ROTATE_90, '-metadata:s:v:0', 'rotate=0'), $filter->apply($video, $format)); | ||||
|         $filter = new RotateFilter($value); | ||||
|         $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