Add resize mode, move getMultiple method to FFMpeg

This commit is contained in:
grosroro 2012-05-28 19:46:49 +02:00
commit fc7529822f
6 changed files with 185 additions and 62 deletions

View file

@ -27,6 +27,18 @@ class FFMpeg extends Binary
{ {
protected $pathfile; protected $pathfile;
/**
*
* @var FFProbe
*/
protected $prober;
public function __destruct()
{
$this->prober = null;
parent::__destruct();
}
/** /**
* Opens a file in order to be processed * Opens a file in order to be processed
* *
@ -49,6 +61,18 @@ class FFMpeg extends Binary
return $this; return $this;
} }
/**
* Set a prober
*
* @return \FFMpeg\FFMpeg
*/
public function setProber(FFProbe $prober)
{
$this->prober = $prober;
return $this;
}
/** /**
* Close a file * Close a file
* *
@ -89,7 +113,7 @@ class FFMpeg extends Binary
try { try {
$process->run(); $process->run();
} catch (\RuntimeException $e) { } catch (\RuntimeException $e) {
} }
if ( ! $process->isSuccessful()) { if ( ! $process->isSuccessful()) {
@ -164,7 +188,7 @@ class FFMpeg extends Binary
try { try {
$process->run(); $process->run();
} catch (\RuntimeException $e) { } catch (\RuntimeException $e) {
} }
if ( ! $process->isSuccessful()) { if ( ! $process->isSuccessful()) {
@ -196,7 +220,43 @@ class FFMpeg extends Binary
$cmd_part2 = ''; $cmd_part2 = '';
if ($format->getWidth() && $format->getHeight()) { 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() $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} * {@inheritdoc}
* *

View file

@ -58,7 +58,23 @@ class FFProbe extends Binary
$cmd = $this->binary . ' ' . $pathfile . ' -show_streams'; $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;
} }
/** /**

View file

@ -20,9 +20,11 @@ use FFMpeg\Exception\InvalidArgumentException;
*/ */
abstract class DefaultVideo extends DefaultAudio implements Video abstract class DefaultVideo extends DefaultAudio implements Video
{ {
protected $width; protected $width;
protected $height; protected $height;
protected $frameRate = 25; protected $frameRate = 25;
protected $resizeMode = self::RESIZEMODE_FIT;
protected $videoCodec; protected $videoCodec;
protected $GOPsize = 25; protected $GOPsize = 25;
protected $kiloBitrate = 1000; protected $kiloBitrate = 1000;
@ -59,12 +61,42 @@ abstract class DefaultVideo extends DefaultAudio implements Video
throw new InvalidArgumentException('Wrong height value'); throw new InvalidArgumentException('Wrong height value');
} }
$this->width = $this->getMultiple($width, 16); $this->width = $width;
$this->height = $this->getMultiple($height, 16); $this->height = $height;
return $this; 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} * {@inheritdoc}
*/ */
@ -145,40 +177,4 @@ abstract class DefaultVideo extends DefaultAudio implements Video
return $this; 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;
}
} }

View file

@ -18,6 +18,8 @@ namespace FFMpeg\Format;
*/ */
interface Video extends Audio interface Video extends Audio
{ {
const RESIZEMODE_FIT = 'fit';
const RESIZEMODE_INSET = 'inset';
/** /**
* Returns the width * Returns the width
@ -33,6 +35,13 @@ interface Video extends Audio
*/ */
public function getHeight(); public function getHeight();
/**
* Get the current resize mode
*
* @return string
*/
public function getResizeMode();
/** /**
* Returns the frame rate * Returns the frame rate
* *

View file

@ -25,6 +25,7 @@ class FFMpegTest extends \PHPUnit_Framework_TestCase
$this->object = FFMpeg::load($this->logger); $this->object = FFMpeg::load($this->logger);
$this->probe = FFProbe::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()); $logger->pushHandler(new \Monolog\Handler\NullHandler());
$ffmpeg = new FFMpeg('wrongbinary', $logger); $ffmpeg = new FFMpeg('wrongbinary', $logger);
$ffmpeg->setProber($this->probe);
$ffmpeg->open(__DIR__ . '/../../files/Test.ogv'); $ffmpeg->open(__DIR__ . '/../../files/Test.ogv');
$format = new Format\Video\WebM(); $format = new Format\Video\WebM();
@ -215,4 +217,26 @@ class FFMpegTest extends \PHPUnit_Framework_TestCase
unlink($dest); 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);
}
} }

View file

@ -27,8 +27,8 @@ class DefaultVideoTest extends \PHPUnit_Framework_TestCase
$this->assertEquals(640, $this->object->getHeight()); $this->assertEquals(640, $this->object->getHeight());
$this->object->setDimensions(242, 638); $this->object->setDimensions(242, 638);
$this->assertEquals(240, $this->object->getWidth()); $this->assertEquals(242, $this->object->getWidth());
$this->assertEquals(640, $this->object->getHeight()); $this->assertEquals(638, $this->object->getHeight());
} }
/** /**
@ -155,19 +155,6 @@ class DefaultVideoTest extends \PHPUnit_Framework_TestCase
return array(array(-5), array(0)); 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 * @covers FFMpeg\Format\DefaultVideo::getKiloBitrate
*/ */
@ -199,9 +186,4 @@ class DefaultVideoTester extends DefaultVideo
return '-f format'; return '-f format';
} }
public function getMultiple($value, $multiple)
{
return parent::getMultiple($value, $multiple);
}
} }