From fc7529822f9714ddaf2bdd5ed405cd5df0876f56 Mon Sep 17 00:00:00 2001 From: grosroro Date: Mon, 28 May 2012 19:46:49 +0200 Subject: [PATCH] Add resize mode, move getMultiple method to FFMpeg --- src/FFMpeg/FFMpeg.php | 102 ++++++++++++++++++- src/FFMpeg/FFProbe.php | 18 +++- src/FFMpeg/Format/DefaultVideo.php | 72 +++++++------ src/FFMpeg/Format/Video.php | 9 ++ tests/src/FFMpeg/FFMpegTest.php | 24 +++++ tests/src/FFMpeg/Format/DefaultVideoTest.php | 22 +--- 6 files changed, 185 insertions(+), 62 deletions(-) diff --git a/src/FFMpeg/FFMpeg.php b/src/FFMpeg/FFMpeg.php index c170b73..e6b78bf 100644 --- a/src/FFMpeg/FFMpeg.php +++ b/src/FFMpeg/FFMpeg.php @@ -27,6 +27,18 @@ class FFMpeg extends Binary { protected $pathfile; + /** + * + * @var FFProbe + */ + protected $prober; + + public function __destruct() + { + $this->prober = null; + parent::__destruct(); + } + /** * Opens a file in order to be processed * @@ -49,6 +61,18 @@ class FFMpeg extends Binary return $this; } + /** + * Set a prober + * + * @return \FFMpeg\FFMpeg + */ + public function setProber(FFProbe $prober) + { + $this->prober = $prober; + + return $this; + } + /** * Close a file * @@ -89,7 +113,7 @@ class FFMpeg extends Binary try { $process->run(); } catch (\RuntimeException $e) { - + } if ( ! $process->isSuccessful()) { @@ -164,7 +188,7 @@ class FFMpeg extends Binary try { $process->run(); } catch (\RuntimeException $e) { - + } if ( ! $process->isSuccessful()) { @@ -196,7 +220,43 @@ class FFMpeg extends Binary $cmd_part2 = ''; if ($format->getWidth() && $format->getHeight()) { - $cmd_part2 .= ' -s ' . $format->getWidth() . 'x' . $format->getHeight(); + + switch ($format->getResizeMode()) { + case Video::RESIZEMODE_FIT: + default: + $width = $this->getMultiple($format->getWidth(), 16); + $height = $this->getMultiple($format->getHeight(), 16); + break; + case Video::RESIZEMODE_INSET: + + if ( ! $this->prober) { + throw new LogicException('You must set a valid prober if you use RESIZEMODE_INSET'); + } + + $result = $this->prober->probeStreams($this->pathfile); + + $originalWidth = $format->getWidth(); + $originalHeight = $format->getHeight(); + + foreach ($result as $stream) { + foreach ($stream as $info) { + if (strpos($info, 'width=') === 0) { + $originalWidth = substr($info, 6); + continue; + } + if (strpos($info, 'height=') === 0) { + $originalHeight = substr($info, 7); + continue; + } + } + } + + $width = $this->getMultiple($originalWidth, 16); + $height = $this->getMultiple($originalHeight, 16); + break; + } + + $cmd_part2 .= ' -s ' . $width . 'x' . $height; } $cmd_part2 .= ' -r ' . $format->getFrameRate() @@ -260,6 +320,42 @@ class FFMpeg extends Binary } } + /** + * Returns the nearest multiple for a value + * + * @param integer $value + * @param integer $multiple + * @return integer + */ + protected function getMultiple($value, $multiple) + { + $modulo = $value % $multiple; + + $ret = (int) $multiple; + + $halfDistance = $multiple / 2; + if ($modulo <= $halfDistance) + $bound = 'bottom'; + else + $bound = 'top'; + + switch ($bound) { + default: + case 'top': + $ret = $value + $multiple - $modulo; + break; + case 'bottom': + $ret = $value - $modulo; + break; + } + + if ($ret < $multiple) { + $ret = (int) $multiple; + } + + return (int) $ret; + } + /** * {@inheritdoc} * diff --git a/src/FFMpeg/FFProbe.php b/src/FFMpeg/FFProbe.php index 4bb3af4..34ae536 100644 --- a/src/FFMpeg/FFProbe.php +++ b/src/FFMpeg/FFProbe.php @@ -58,7 +58,23 @@ class FFProbe extends Binary $cmd = $this->binary . ' ' . $pathfile . ' -show_streams'; - return $this->executeProbe($cmd); + $output = explode("\n", $this->executeProbe($cmd)); + + $ret = array(); + $n = 0; + + foreach ($output as $line) { + + if (in_array($line, array('[STREAM]', '[/STREAM]'))) { + $n ++; + $ret[$n] = array(); + continue; + } + + $ret[$n][] = $line; + } + + return $ret; } /** diff --git a/src/FFMpeg/Format/DefaultVideo.php b/src/FFMpeg/Format/DefaultVideo.php index fb85a6c..8f635c7 100644 --- a/src/FFMpeg/Format/DefaultVideo.php +++ b/src/FFMpeg/Format/DefaultVideo.php @@ -20,9 +20,11 @@ use FFMpeg\Exception\InvalidArgumentException; */ abstract class DefaultVideo extends DefaultAudio implements Video { + protected $width; protected $height; protected $frameRate = 25; + protected $resizeMode = self::RESIZEMODE_FIT; protected $videoCodec; protected $GOPsize = 25; protected $kiloBitrate = 1000; @@ -59,12 +61,42 @@ abstract class DefaultVideo extends DefaultAudio implements Video throw new InvalidArgumentException('Wrong height value'); } - $this->width = $this->getMultiple($width, 16); - $this->height = $this->getMultiple($height, 16); + $this->width = $width; + $this->height = $height; return $this; } + /** + * Set the resize mode + * + * @param string $mode The mode, one of the self::RESIZEMODE_* constants + * + * @throws InvalidArgumentException + */ + public function setResizeMode($mode) + { + if ( ! in_array($mode, array(self::RESIZEMODE_FIT, self::RESIZEMODE_INSET))) { + throw new InvalidArgumentException( + 'Resize mode `%s` is not valid , avalaible values are %s', + $mode, + implode(', ', array(self::RESIZEMODE_FIT, self::RESIZEMODE_INSET)) + ); + } + + $this->resizeMode = $mode; + + return $this; + } + + /** + * {@inheritdoc} + */ + public function getResizeMode() + { + return $this->resizeMode; + } + /** * {@inheritdoc} */ @@ -145,40 +177,4 @@ abstract class DefaultVideo extends DefaultAudio implements Video return $this; } - - /** - * Returns the nearest multiple for a value - * - * @param integer $value - * @param integer $multiple - * @return integer - */ - protected function getMultiple($value, $multiple) - { - $modulo = $value % $multiple; - - $ret = (int) $multiple; - - $halfDistance = $multiple / 2; - if ($modulo <= $halfDistance) - $bound = 'bottom'; - else - $bound = 'top'; - - switch ($bound) { - default: - case 'top': - $ret = $value + $multiple - $modulo; - break; - case 'bottom': - $ret = $value - $modulo; - break; - } - - if ($ret < $multiple) { - $ret = (int) $multiple; - } - - return (int) $ret; - } } diff --git a/src/FFMpeg/Format/Video.php b/src/FFMpeg/Format/Video.php index 4a4bf42..374e76f 100644 --- a/src/FFMpeg/Format/Video.php +++ b/src/FFMpeg/Format/Video.php @@ -18,6 +18,8 @@ namespace FFMpeg\Format; */ interface Video extends Audio { + const RESIZEMODE_FIT = 'fit'; + const RESIZEMODE_INSET = 'inset'; /** * Returns the width @@ -33,6 +35,13 @@ interface Video extends Audio */ public function getHeight(); + /** + * Get the current resize mode + * + * @return string + */ + public function getResizeMode(); + /** * Returns the frame rate * diff --git a/tests/src/FFMpeg/FFMpegTest.php b/tests/src/FFMpeg/FFMpegTest.php index 464ac02..96cbb69 100644 --- a/tests/src/FFMpeg/FFMpegTest.php +++ b/tests/src/FFMpeg/FFMpegTest.php @@ -25,6 +25,7 @@ class FFMpegTest extends \PHPUnit_Framework_TestCase $this->object = FFMpeg::load($this->logger); $this->probe = FFProbe::load($this->logger); + $this->object->setProber($this->probe); } /** @@ -119,6 +120,7 @@ class FFMpegTest extends \PHPUnit_Framework_TestCase $logger->pushHandler(new \Monolog\Handler\NullHandler()); $ffmpeg = new FFMpeg('wrongbinary', $logger); + $ffmpeg->setProber($this->probe); $ffmpeg->open(__DIR__ . '/../../files/Test.ogv'); $format = new Format\Video\WebM(); @@ -215,4 +217,26 @@ class FFMpegTest extends \PHPUnit_Framework_TestCase unlink($dest); } + + /** + * @covers FFMpeg\FFMpeg::getMultiple + */ + public function testGetMultiple() + { + $object = FFMpegTester::load($this->logger); + $this->assertEquals(320, $object->getMultipleTester(321, 16)); + $this->assertEquals(320, $object->getMultipleTester(319, 16)); + $this->assertEquals(320, $object->getMultipleTester(313, 16)); + $this->assertEquals(304, $object->getMultipleTester(312, 16)); + $this->assertEquals(336, $object->getMultipleTester(329, 16)); + $this->assertEquals(16, $object->getMultipleTester(8, 16)); + } +} + +class FFMpegTester extends FFMpeg +{ + public function getMultipleTester($value, $multiple) + { + return parent::getMultiple($value, $multiple); + } } diff --git a/tests/src/FFMpeg/Format/DefaultVideoTest.php b/tests/src/FFMpeg/Format/DefaultVideoTest.php index 9bb0ffd..6145057 100644 --- a/tests/src/FFMpeg/Format/DefaultVideoTest.php +++ b/tests/src/FFMpeg/Format/DefaultVideoTest.php @@ -27,8 +27,8 @@ class DefaultVideoTest extends \PHPUnit_Framework_TestCase $this->assertEquals(640, $this->object->getHeight()); $this->object->setDimensions(242, 638); - $this->assertEquals(240, $this->object->getWidth()); - $this->assertEquals(640, $this->object->getHeight()); + $this->assertEquals(242, $this->object->getWidth()); + $this->assertEquals(638, $this->object->getHeight()); } /** @@ -155,19 +155,6 @@ class DefaultVideoTest extends \PHPUnit_Framework_TestCase return array(array(-5), array(0)); } - /** - * @covers FFMpeg\Format\DefaultVideo::getMultiple - */ - public function testGetMultiple() - { - $this->assertEquals(320, $this->object->getMultiple(321, 16)); - $this->assertEquals(320, $this->object->getMultiple(319, 16)); - $this->assertEquals(320, $this->object->getMultiple(313, 16)); - $this->assertEquals(304, $this->object->getMultiple(312, 16)); - $this->assertEquals(336, $this->object->getMultiple(329, 16)); - $this->assertEquals(16, $this->object->getMultiple(8, 16)); - } - /** * @covers FFMpeg\Format\DefaultVideo::getKiloBitrate */ @@ -199,9 +186,4 @@ class DefaultVideoTester extends DefaultVideo return '-f format'; } - public function getMultiple($value, $multiple) - { - return parent::getMultiple($value, $multiple); - } - }