Merge branch '0.4'

This commit is contained in:
Romain Neutron 2013-12-02 14:48:38 +01:00
commit f3893b9459
11 changed files with 165 additions and 8 deletions

View file

@ -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

View file

@ -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).

View file

@ -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;
}

View file

@ -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.
*

View file

@ -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');
}

View file

@ -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;
}

View file

@ -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;
}
/**

View file

@ -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));

View file

@ -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);
}
}

View file

@ -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

Binary file not shown.