Merge pull request #56 from alchemy-fr/streams-dimensions
Add convenient Stream::getDimensions method to extract video dimension.
This commit is contained in:
		
				commit
				
					
						71e3137387
					
				
			
		
					 5 changed files with 135 additions and 10 deletions
				
			
		|  | @ -1,6 +1,10 @@ | ||||||
| CHANGELOG | CHANGELOG | ||||||
| --------- | --------- | ||||||
| 
 | 
 | ||||||
|  | * 0.3.3 (xx-xx-2013) | ||||||
|  | 
 | ||||||
|  |   * Add convenient Stream::getDimensions method to extract video dimension. | ||||||
|  | 
 | ||||||
| * 0.3.2 (08-08-2013) | * 0.3.2 (08-08-2013) | ||||||
| 
 | 
 | ||||||
|   * Fix A/V synchronization over flash and HTML5 players. |   * Fix A/V synchronization over flash and HTML5 players. | ||||||
|  |  | ||||||
							
								
								
									
										16
									
								
								src/FFMpeg/Exception/LogicException.php
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								src/FFMpeg/Exception/LogicException.php
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,16 @@ | ||||||
|  | <?php | ||||||
|  | 
 | ||||||
|  | /* | ||||||
|  |  * This file is part of PHP-FFmpeg. | ||||||
|  |  * | ||||||
|  |  * (c) Alchemy <info@alchemy.fr> | ||||||
|  |  * | ||||||
|  |  * For the full copyright and license information, please view the LICENSE | ||||||
|  |  * file that was distributed with this source code. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | namespace FFMpeg\Exception; | ||||||
|  | 
 | ||||||
|  | class LogicException extends \LogicException implements ExceptionInterface | ||||||
|  | { | ||||||
|  | } | ||||||
|  | @ -11,6 +11,10 @@ | ||||||
| 
 | 
 | ||||||
| namespace FFMpeg\FFProbe\DataMapping; | namespace FFMpeg\FFProbe\DataMapping; | ||||||
| 
 | 
 | ||||||
|  | use FFMpeg\Exception\LogicException; | ||||||
|  | use FFMpeg\Exception\RuntimeException; | ||||||
|  | use FFMpeg\Coordinate\Dimension; | ||||||
|  | 
 | ||||||
| class Stream extends AbstractData | class Stream extends AbstractData | ||||||
| { | { | ||||||
|     /** |     /** | ||||||
|  | @ -32,4 +36,63 @@ class Stream extends AbstractData | ||||||
|     { |     { | ||||||
|         return $this->has('codec_type') ? 'video' === $this->get('codec_type') : false; |         return $this->has('codec_type') ? 'video' === $this->get('codec_type') : false; | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Returns the dimension of the video stream. | ||||||
|  |      * | ||||||
|  |      * @return Dimension | ||||||
|  |      * | ||||||
|  |      * @throws LogicException   In case the stream is not a video stream. | ||||||
|  |      * @throws RuntimeException In case the dimensions can not be extracted. | ||||||
|  |      */ | ||||||
|  |     public function getDimensions() | ||||||
|  |     { | ||||||
|  |         if (!$this->isVideo()) { | ||||||
|  |             throw new LogicException('Dimensions can only be retrieved from video streams.'); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         $width = $height = $sampleRatio = $displayRatio = null; | ||||||
|  | 
 | ||||||
|  |         if ($this->has('width')) { | ||||||
|  |             $width = $this->get('width'); | ||||||
|  |         } | ||||||
|  |         if ($this->has('height')) { | ||||||
|  |             $height = $this->get('height'); | ||||||
|  |         } | ||||||
|  |         if (null !== $ratio = $this->extractRatio($this, 'sample_aspect_ratio')) { | ||||||
|  |             $sampleRatio = $ratio; | ||||||
|  |         } | ||||||
|  |         if (null !== $ratio = $this->extractRatio($this, 'display_aspect_ratio')) { | ||||||
|  |             $displayRatio = $ratio; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         if (null === $height || null === $width) { | ||||||
|  |             throw new RuntimeException('Unable to extract dimensions.'); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         if (null !== $displayRatio && null !== $sampleRatio) { | ||||||
|  |             $width = round($width / $sampleRatio[0] * $sampleRatio[1] * $displayRatio[0] / $displayRatio[1]); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         return new Dimension($width, $height); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Extracts a ratio from a string in a \d+:\d+ format given a key name. | ||||||
|  |      * | ||||||
|  |      * @param  Stream     $stream The stream where to look for the ratio. | ||||||
|  |      * @param  string     $name   the name of the key. | ||||||
|  |      * @return null|array An array containing the width and the height, null if not found. | ||||||
|  |      */ | ||||||
|  |     private function extractRatio(Stream $stream, $name) | ||||||
|  |     { | ||||||
|  |         if ($stream->has($name)) { | ||||||
|  |             $ratio = $stream->get($name); | ||||||
|  |             if (preg_match('/\d+:\d+/', $ratio)) { | ||||||
|  |                 return array_map(function ($int) { return (int) $int; }, explode(':', $ratio)); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         return null; | ||||||
|  |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -12,6 +12,7 @@ | ||||||
| namespace FFMpeg\Filters\Video; | namespace FFMpeg\Filters\Video; | ||||||
| 
 | 
 | ||||||
| use FFMpeg\Coordinate\Dimension; | use FFMpeg\Coordinate\Dimension; | ||||||
|  | use FFMpeg\Exception\RuntimeException; | ||||||
| use FFMpeg\Media\Video; | use FFMpeg\Media\Video; | ||||||
| use FFMpeg\Format\VideoInterface; | use FFMpeg\Format\VideoInterface; | ||||||
| 
 | 
 | ||||||
|  | @ -80,23 +81,22 @@ class ResizeFilter implements VideoFilterInterface | ||||||
|      */ |      */ | ||||||
|     public function apply(Video $video, VideoInterface $format) |     public function apply(Video $video, VideoInterface $format) | ||||||
|     { |     { | ||||||
|         $originalWidth = $originalHeight = null; |         $dimensions = null; | ||||||
|  |         $commands = array(); | ||||||
| 
 | 
 | ||||||
|         foreach ($video->getStreams() as $stream) { |         foreach ($video->getStreams() as $stream) { | ||||||
|             if ($stream->isVideo()) { |             if ($stream->isVideo()) { | ||||||
|                 if ($stream->has('width')) { |                 try { | ||||||
|                     $originalWidth = $stream->get('width'); |                     $dimensions = $stream->getDimensions(); | ||||||
|                 } |                     break; | ||||||
|                 if ($stream->has('height')) { |                 } catch (RuntimeException $e) { | ||||||
|                     $originalHeight = $stream->get('height'); | 
 | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         $commands = array(); |         if (null !== $dimensions) { | ||||||
| 
 |             $dimensions = $this->getComputedDimensions($dimensions, $format->getModulus()); | ||||||
|         if ($originalHeight !== null && $originalWidth !== null) { |  | ||||||
|             $dimensions = $this->getComputedDimensions(new Dimension($originalWidth, $originalHeight), $format->getModulus()); |  | ||||||
| 
 | 
 | ||||||
|             $commands[] = '-s'; |             $commands[] = '-s'; | ||||||
|             $commands[] = $dimensions->getWidth() . 'x' . $dimensions->getHeight(); |             $commands[] = $dimensions->getWidth() . 'x' . $dimensions->getHeight(); | ||||||
|  |  | ||||||
|  | @ -2,6 +2,7 @@ | ||||||
| 
 | 
 | ||||||
| namespace FFMpeg\Tests\FFProbe\DataMapping; | namespace FFMpeg\Tests\FFProbe\DataMapping; | ||||||
| 
 | 
 | ||||||
|  | use FFMpeg\Coordinate\Dimension; | ||||||
| use FFMpeg\Tests\TestCase; | use FFMpeg\Tests\TestCase; | ||||||
| use FFMpeg\FFProbe\DataMapping\Stream; | use FFMpeg\FFProbe\DataMapping\Stream; | ||||||
| 
 | 
 | ||||||
|  | @ -40,4 +41,45 @@ class StreamTest extends TestCase | ||||||
|             array(false, array('codec_type' => 'audio')), |             array(false, array('codec_type' => 'audio')), | ||||||
|         ); |         ); | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * @expectedException FFMpeg\Exception\LogicException | ||||||
|  |      * @expectedExceptionMessage Dimensions can only be retrieved from video streams. | ||||||
|  |      */ | ||||||
|  |     public function testGetDimensionsFromAudio() | ||||||
|  |     { | ||||||
|  |         $stream = new Stream(array('codec_type' => 'audio')); | ||||||
|  |         $stream->getDimensions(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public function testGetDimensionsFromVideo() | ||||||
|  |     { | ||||||
|  |         $stream = new Stream(array('codec_type' => 'video', 'width' => 960, 'height' => 720)); | ||||||
|  |         $this->assertEquals(new Dimension(960, 720), $stream->getDimensions()); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * @dataProvider provideInvalidPropertiesForDimensionsExtraction | ||||||
|  |      * @expectedException FFMpeg\Exception\RuntimeException | ||||||
|  |      * @expectedExceptionMessage Unable to extract dimensions. | ||||||
|  |      */ | ||||||
|  |     public function testUnableToGetDimensionsFromVideo($properties) | ||||||
|  |     { | ||||||
|  |         $stream = new Stream(array('codec_type' => 'video', 'width' => 960)); | ||||||
|  |         $stream->getDimensions(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public function provideInvalidPropertiesForDimensionsExtraction() | ||||||
|  |     { | ||||||
|  |         return array( | ||||||
|  |             array('codec_type' => 'video', 'width' => 960), | ||||||
|  |             array('codec_type' => 'video', 'height' => 960), | ||||||
|  |         ); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public function testGetDimensionsFromVideoWithDisplayRatio() | ||||||
|  |     { | ||||||
|  |         $stream = new Stream(array('codec_type' => 'video', 'width' => 960, 'height' => 720, 'sample_aspect_ratio' => '4:3', 'display_aspect_ratio' => '16:9')); | ||||||
|  |         $this->assertEquals(new Dimension(1280, 720), $stream->getDimensions()); | ||||||
|  |     } | ||||||
| } | } | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue