From 15711a0e50b3486dd73107edb68ee5606922702f Mon Sep 17 00:00:00 2001 From: Romain Neutron Date: Wed, 4 Sep 2013 19:00:43 +0200 Subject: [PATCH 1/7] Add convenient Stream::getDimensions method to extract video dimension. --- CHANGELOG.md | 4 ++ src/FFMpeg/Exception/LogicException.php | 16 +++++ src/FFMpeg/FFProbe/DataMapping/Stream.php | 63 +++++++++++++++++++ src/FFMpeg/Filters/Video/ResizeFilter.php | 19 +++--- .../Tests/FFProbe/DataMapping/StreamTest.php | 42 +++++++++++++ 5 files changed, 134 insertions(+), 10 deletions(-) create mode 100644 src/FFMpeg/Exception/LogicException.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 88525aa..e519f4d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,10 @@ CHANGELOG --------- +* 0.3.3 (xx-xx-2013) + + * Add convenient Stream::getDimensions method to extract video dimension. + * 0.3.2 (08-08-2013) * Fix A/V synchronization over flash and HTML5 players. diff --git a/src/FFMpeg/Exception/LogicException.php b/src/FFMpeg/Exception/LogicException.php new file mode 100644 index 0000000..b73b567 --- /dev/null +++ b/src/FFMpeg/Exception/LogicException.php @@ -0,0 +1,16 @@ + + * + * 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 +{ +} diff --git a/src/FFMpeg/FFProbe/DataMapping/Stream.php b/src/FFMpeg/FFProbe/DataMapping/Stream.php index 9b0d170..e74503e 100644 --- a/src/FFMpeg/FFProbe/DataMapping/Stream.php +++ b/src/FFMpeg/FFProbe/DataMapping/Stream.php @@ -11,6 +11,10 @@ namespace FFMpeg\FFProbe\DataMapping; +use FFMpeg\Exception\LogicException; +use FFMpeg\Exception\RuntimeException; +use FFMpeg\Coordinate\Dimension; + class Stream extends AbstractData { /** @@ -32,4 +36,63 @@ class Stream extends AbstractData { 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; + } } diff --git a/src/FFMpeg/Filters/Video/ResizeFilter.php b/src/FFMpeg/Filters/Video/ResizeFilter.php index a3e407d..d1ef2b8 100644 --- a/src/FFMpeg/Filters/Video/ResizeFilter.php +++ b/src/FFMpeg/Filters/Video/ResizeFilter.php @@ -12,6 +12,7 @@ namespace FFMpeg\Filters\Video; use FFMpeg\Coordinate\Dimension; +use FFMpeg\Exception\RuntimeException; use FFMpeg\Media\Video; use FFMpeg\Format\VideoInterface; @@ -80,23 +81,21 @@ class ResizeFilter implements VideoFilterInterface */ public function apply(Video $video, VideoInterface $format) { - $originalWidth = $originalHeight = null; + $dimensions = null; + $commands = array(); foreach ($video->getStreams() as $stream) { if ($stream->isVideo()) { - if ($stream->has('width')) { - $originalWidth = $stream->get('width'); - } - if ($stream->has('height')) { - $originalHeight = $stream->get('height'); + try { + $dimensions = $stream->getDimensions(); + } catch (RuntimeException $e) { + } } } - $commands = array(); - - if ($originalHeight !== null && $originalWidth !== null) { - $dimensions = $this->getComputedDimensions(new Dimension($originalWidth, $originalHeight), $format->getModulus()); + if (null !== $dimensions) { + $dimensions = $this->getComputedDimensions($dimensions, $format->getModulus()); $commands[] = '-s'; $commands[] = $dimensions->getWidth() . 'x' . $dimensions->getHeight(); diff --git a/tests/FFMpeg/Tests/FFProbe/DataMapping/StreamTest.php b/tests/FFMpeg/Tests/FFProbe/DataMapping/StreamTest.php index e1ea7b6..c9f9c19 100644 --- a/tests/FFMpeg/Tests/FFProbe/DataMapping/StreamTest.php +++ b/tests/FFMpeg/Tests/FFProbe/DataMapping/StreamTest.php @@ -2,6 +2,7 @@ namespace FFMpeg\Tests\FFProbe\DataMapping; +use FFMpeg\Coordinate\Dimension; use FFMpeg\Tests\TestCase; use FFMpeg\FFProbe\DataMapping\Stream; @@ -40,4 +41,45 @@ class StreamTest extends TestCase 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()); + } } From f530d60118051af389d9a25342138fe5f5acd55b Mon Sep 17 00:00:00 2001 From: Romain Neutron Date: Wed, 4 Sep 2013 19:44:45 +0200 Subject: [PATCH 2/7] Break if dimension is found --- src/FFMpeg/Filters/Video/ResizeFilter.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/FFMpeg/Filters/Video/ResizeFilter.php b/src/FFMpeg/Filters/Video/ResizeFilter.php index d1ef2b8..c5f96cb 100644 --- a/src/FFMpeg/Filters/Video/ResizeFilter.php +++ b/src/FFMpeg/Filters/Video/ResizeFilter.php @@ -88,6 +88,7 @@ class ResizeFilter implements VideoFilterInterface if ($stream->isVideo()) { try { $dimensions = $stream->getDimensions(); + break; } catch (RuntimeException $e) { } From 5814eb3085269b8b039170f52eb320b9c2d47618 Mon Sep 17 00:00:00 2001 From: Romain Neutron Date: Wed, 4 Sep 2013 19:50:38 +0200 Subject: [PATCH 3/7] Inject Video at Frame construction --- src/FFMpeg/Media/Frame.php | 18 ++++++++++++++++-- src/FFMpeg/Media/Video.php | 2 +- tests/FFMpeg/Tests/Media/FrameTest.php | 8 ++++---- tests/FFMpeg/Tests/TestCase.php | 10 ++++++++-- 4 files changed, 29 insertions(+), 9 deletions(-) diff --git a/src/FFMpeg/Media/Frame.php b/src/FFMpeg/Media/Frame.php index bfbed8f..55d4311 100644 --- a/src/FFMpeg/Media/Frame.php +++ b/src/FFMpeg/Media/Frame.php @@ -18,16 +18,30 @@ use FFMpeg\Driver\FFMpegDriver; use FFMpeg\FFProbe; use FFMpeg\Exception\RuntimeException; use FFMpeg\Coordinate\TimeCode; +use FFMpeg\Media\Video; class Frame extends AbstractMediaType { /** @var TimeCode */ private $timecode; + /** @var Video */ + private $video; - public function __construct($pathfile, FFMpegDriver $driver, FFProbe $ffprobe, TimeCode $timecode) + public function __construct(Video $video, FFMpegDriver $driver, FFProbe $ffprobe, TimeCode $timecode) { - parent::__construct($pathfile, $driver, $ffprobe); + parent::__construct($video->getPathfile(), $driver, $ffprobe); $this->timecode = $timecode; + $this->video = $video; + } + + /** + * Returns the video related to the frame. + * + * @return Video + */ + public function getVideo() + { + return $this->video; } /** diff --git a/src/FFMpeg/Media/Video.php b/src/FFMpeg/Media/Video.php index 77da940..006e346 100644 --- a/src/FFMpeg/Media/Video.php +++ b/src/FFMpeg/Media/Video.php @@ -159,6 +159,6 @@ class Video extends Audio */ public function frame(TimeCode $at) { - return new Frame($this->pathfile, $this->driver, $this->ffprobe, $at); + return new Frame($this, $this->driver, $this->ffprobe, $at); } } diff --git a/tests/FFMpeg/Tests/Media/FrameTest.php b/tests/FFMpeg/Tests/Media/FrameTest.php index a95df2b..c98cb87 100644 --- a/tests/FFMpeg/Tests/Media/FrameTest.php +++ b/tests/FFMpeg/Tests/Media/FrameTest.php @@ -20,7 +20,7 @@ class FrameTest extends AbstractMediaTestCase $ffprobe = $this->getFFProbeMock(); $timecode = $this->getTimeCodeMock(); - $frame = new Frame(__FILE__, $driver, $ffprobe, $timecode); + $frame = new Frame($this->getVideoMock(__FILE__), $driver, $ffprobe, $timecode); $this->assertSame($timecode, $frame->getTimeCode()); } @@ -30,7 +30,7 @@ class FrameTest extends AbstractMediaTestCase $ffprobe = $this->getFFProbeMock(); $timecode = $this->getTimeCodeMock(); - $frame = new Frame(__FILE__, $driver, $ffprobe, $timecode); + $frame = new Frame($this->getVideoMock(__FILE__), $driver, $ffprobe, $timecode); $this->assertInstanceOf('FFMpeg\Filters\Frame\FrameFilters', $frame->filters()); } @@ -50,7 +50,7 @@ class FrameTest extends AbstractMediaTestCase ->method('add') ->with($filter); - $frame = new Frame(__FILE__, $driver, $ffprobe, $timecode); + $frame = new Frame($this->getVideoMock(__FILE__), $driver, $ffprobe, $timecode); $frame->setFiltersCollection($filters); $frame->addFilter($filter); } @@ -75,7 +75,7 @@ class FrameTest extends AbstractMediaTestCase ->method('command') ->with($commands); - $frame = new Frame(__FILE__, $driver, $ffprobe, $timecode); + $frame = new Frame($this->getVideoMock(__FILE__), $driver, $ffprobe, $timecode); $this->assertSame($frame, $frame->save($pathfile, $accurate)); } diff --git a/tests/FFMpeg/Tests/TestCase.php b/tests/FFMpeg/Tests/TestCase.php index d347acd..0d6f906 100644 --- a/tests/FFMpeg/Tests/TestCase.php +++ b/tests/FFMpeg/Tests/TestCase.php @@ -122,10 +122,16 @@ class TestCase extends \PHPUnit_Framework_TestCase ->getMock(); } - protected function getVideoMock() + protected function getVideoMock($filename = null) { - return $this->getMockBuilder('FFMpeg\Media\Video') + $video = $this->getMockBuilder('FFMpeg\Media\Video') ->disableOriginalConstructor() ->getMock(); + + $video->expects($this->any()) + ->method('getFilename') + ->will($this->returnValue($filename)); + + return $video; } } From bcf3e5f65a07a3d1127eeb7b062fe405521bf435 Mon Sep 17 00:00:00 2001 From: Romain Neutron Date: Wed, 4 Sep 2013 19:52:24 +0200 Subject: [PATCH 4/7] Apply frame filters on Frame::save --- src/FFMpeg/Filters/Frame/FrameFilterInterface.php | 3 +-- src/FFMpeg/Media/Frame.php | 10 ++++++++-- tests/FFMpeg/Tests/Media/FrameTest.php | 2 +- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/FFMpeg/Filters/Frame/FrameFilterInterface.php b/src/FFMpeg/Filters/Frame/FrameFilterInterface.php index db4fdac..d9df0e4 100644 --- a/src/FFMpeg/Filters/Frame/FrameFilterInterface.php +++ b/src/FFMpeg/Filters/Frame/FrameFilterInterface.php @@ -13,9 +13,8 @@ namespace FFMpeg\Filters\Frame; use FFMpeg\Filters\FilterInterface; use FFMpeg\Media\Frame; -use FFMpeg\Format\FrameInterface; interface FrameFilterInterface extends FilterInterface { - public function apply(Frame $frame, FrameInterface $format); + public function apply(Frame $frame); } diff --git a/src/FFMpeg/Media/Frame.php b/src/FFMpeg/Media/Frame.php index 55d4311..a48c50e 100644 --- a/src/FFMpeg/Media/Frame.php +++ b/src/FFMpeg/Media/Frame.php @@ -97,16 +97,22 @@ class Frame extends AbstractMediaType '-y', '-ss', (string) $this->timecode, '-i', $this->pathfile, '-vframes', '1', - '-f', 'image2', $pathfile + '-f', 'image2' ); } else { $commands = array( '-y', '-i', $this->pathfile, '-vframes', '1', '-ss', (string) $this->timecode, - '-f', 'image2', $pathfile + '-f', 'image2' ); } + foreach ($this->filters as $filter) { + $commands = array_merge($commands, $filter->apply($this)); + } + + $commands = array_merge($commands, array($pathfile)); + try { $this->driver->command($commands); } catch (ExecutionFailureException $e) { diff --git a/tests/FFMpeg/Tests/Media/FrameTest.php b/tests/FFMpeg/Tests/Media/FrameTest.php index c98cb87..b64d6e9 100644 --- a/tests/FFMpeg/Tests/Media/FrameTest.php +++ b/tests/FFMpeg/Tests/Media/FrameTest.php @@ -11,7 +11,7 @@ class FrameTest extends AbstractMediaTestCase */ public function testWithInvalidFile() { - new Frame('/No/file', $this->getFFMpegDriverMock(), $this->getFFProbeMock(), $this->getTimeCodeMock()); + new Frame($this->getVideoMock('/No/file'), $this->getFFMpegDriverMock(), $this->getFFProbeMock(), $this->getTimeCodeMock()); } public function testGetTimeCode() From 1de948faba5aba5267f8dec3bbdd7f36e0237698 Mon Sep 17 00:00:00 2001 From: Romain Neutron Date: Thu, 5 Sep 2013 11:05:14 +0200 Subject: [PATCH 5/7] Add DisplayRatioFixer Frame filter --- CHANGELOG.md | 1 + .../Filters/Frame/DisplayRatioFixerFilter.php | 58 +++++++++++++++++++ .../Frame/DisplayRatioFixerFilterTest.php | 28 +++++++++ 3 files changed, 87 insertions(+) create mode 100644 src/FFMpeg/Filters/Frame/DisplayRatioFixerFilter.php create mode 100644 tests/FFMpeg/Tests/Filters/Frame/DisplayRatioFixerFilterTest.php diff --git a/CHANGELOG.md b/CHANGELOG.md index e519f4d..95840c8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ CHANGELOG * 0.3.3 (xx-xx-2013) * Add convenient Stream::getDimensions method to extract video dimension. + * Add DisplayRatioFixer Frame filter. * 0.3.2 (08-08-2013) diff --git a/src/FFMpeg/Filters/Frame/DisplayRatioFixerFilter.php b/src/FFMpeg/Filters/Frame/DisplayRatioFixerFilter.php new file mode 100644 index 0000000..0cc3cea --- /dev/null +++ b/src/FFMpeg/Filters/Frame/DisplayRatioFixerFilter.php @@ -0,0 +1,58 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace FFMpeg\Filters\Frame; + +use FFMpeg\Exception\RuntimeException; +use FFMpeg\Media\Frame; + +class DisplayRatioFixerFilter implements FrameFilterInterface +{ + /** @var integer */ + private $priority; + + public function __construct($priority = 0) + { + $this->priority = $priority; + } + + /** + * {@inheritdoc} + */ + public function getPriority() + { + return $this->priority; + } + + /** + * {@inheritdoc} + */ + public function apply(Frame $frame) + { + $dimensions = null; + $commands = array(); + + foreach ($frame->getVideo()->getStreams() as $stream) { + if ($stream->isVideo()) { + try { + $dimensions = $stream->getDimensions(); + $commands[] = '-s'; + $commands[] = $dimensions->getWidth() . 'x' . $dimensions->getHeight(); + break; + } catch (RuntimeException $e) { + + } + } + } + + return $commands; + } +} diff --git a/tests/FFMpeg/Tests/Filters/Frame/DisplayRatioFixerFilterTest.php b/tests/FFMpeg/Tests/Filters/Frame/DisplayRatioFixerFilterTest.php new file mode 100644 index 0000000..bb642b4 --- /dev/null +++ b/tests/FFMpeg/Tests/Filters/Frame/DisplayRatioFixerFilterTest.php @@ -0,0 +1,28 @@ + 'video', 'width' => 960, 'height' => 720)); + $streams = new StreamCollection(array($stream)); + + $video = $this->getVideoMock(__FILE__); + $video->expects($this->once()) + ->method('getStreams') + ->will($this->returnValue($streams)); + + $frame = new Frame($video, $this->getFFMpegDriverMock(), $this->getFFProbeMock(), new TimeCode(0, 0, 0, 0)); + $filter = new DisplayRatioFixerFilter(); + $this->assertEquals(array('-s', '960x720'), $filter->apply($frame)); + } +} From e43da86152e36d78bba3e4e7ddea5a6aad73f8f5 Mon Sep 17 00:00:00 2001 From: Romain Neutron Date: Thu, 5 Sep 2013 11:12:10 +0200 Subject: [PATCH 6/7] Fix FiltersCollection::getIterator in case of empty collection --- src/FFMpeg/Filters/FiltersCollection.php | 8 ++++++-- tests/FFMpeg/Tests/Filters/FiltersCollectionTest.php | 6 ++++++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/FFMpeg/Filters/FiltersCollection.php b/src/FFMpeg/Filters/FiltersCollection.php index d44a880..c91241a 100644 --- a/src/FFMpeg/Filters/FiltersCollection.php +++ b/src/FFMpeg/Filters/FiltersCollection.php @@ -47,8 +47,12 @@ class FiltersCollection implements \Countable, \IteratorAggregate public function getIterator() { if (null === $this->sorted) { - krsort($this->filters); - $this->sorted = call_user_func_array('array_merge', $this->filters); + if (0 === count($this->filters)) { + $this->sorted = $this->filters; + } else { + krsort($this->filters); + $this->sorted = call_user_func_array('array_merge', $this->filters); + } } return new \ArrayIterator($this->sorted); diff --git a/tests/FFMpeg/Tests/Filters/FiltersCollectionTest.php b/tests/FFMpeg/Tests/Filters/FiltersCollectionTest.php index 52a1395..5a29008 100644 --- a/tests/FFMpeg/Tests/Filters/FiltersCollectionTest.php +++ b/tests/FFMpeg/Tests/Filters/FiltersCollectionTest.php @@ -30,6 +30,12 @@ class FiltersCollectionTest extends TestCase $this->assertCount(2, $coll->getIterator()); } + public function testEmptyIterator() + { + $coll = new FiltersCollection(); + $this->assertInstanceOf('\ArrayIterator', $coll->getIterator()); + } + public function testIteratorSort() { $coll = new FiltersCollection(); From bb3191528552750f5329b89bd23a358526d167a5 Mon Sep 17 00:00:00 2001 From: Romain Neutron Date: Thu, 5 Sep 2013 11:16:26 +0200 Subject: [PATCH 7/7] Add FrameFilters::fixDisplayRatio method --- src/FFMpeg/Filters/Frame/FrameFilters.php | 15 +++++++++++++ .../Tests/Filters/Frame/FrameFiltersTest.php | 21 +++++++++++++++++++ tests/FFMpeg/Tests/TestCase.php | 9 +++++++- 3 files changed, 44 insertions(+), 1 deletion(-) create mode 100644 tests/FFMpeg/Tests/Filters/Frame/FrameFiltersTest.php diff --git a/src/FFMpeg/Filters/Frame/FrameFilters.php b/src/FFMpeg/Filters/Frame/FrameFilters.php index 85bfde9..255da0c 100644 --- a/src/FFMpeg/Filters/Frame/FrameFilters.php +++ b/src/FFMpeg/Filters/Frame/FrameFilters.php @@ -21,4 +21,19 @@ class FrameFilters { $this->frame = $frame; } + + /** + * Fixes the display ratio of the output frame. + * + * In case the sample ratio and display ratio are different, image may be + * anamorphozed. This filter fixes this by specifying the output size. + * + * @return FrameFilters + */ + public function fixDisplayRatio() + { + $this->frame->addFilter(new DisplayRatioFixerFilter()); + + return $this; + } } diff --git a/tests/FFMpeg/Tests/Filters/Frame/FrameFiltersTest.php b/tests/FFMpeg/Tests/Filters/Frame/FrameFiltersTest.php new file mode 100644 index 0000000..a0e6434 --- /dev/null +++ b/tests/FFMpeg/Tests/Filters/Frame/FrameFiltersTest.php @@ -0,0 +1,21 @@ +getFrameMock(); + $filters = new FrameFilters($frame); + + $frame->expects($this->once()) + ->method('addFilter') + ->with($this->isInstanceOf('FFMpeg\Filters\Frame\DisplayRatioFixerFilter')); + + $filters->fixDisplayRatio(); + } +} diff --git a/tests/FFMpeg/Tests/TestCase.php b/tests/FFMpeg/Tests/TestCase.php index 0d6f906..4757f95 100644 --- a/tests/FFMpeg/Tests/TestCase.php +++ b/tests/FFMpeg/Tests/TestCase.php @@ -40,6 +40,13 @@ class TestCase extends \PHPUnit_Framework_TestCase ->getMock(); } + public function getFrameMock() + { + return $this->getMockBuilder('FFMpeg\Media\Frame') + ->disableOriginalConstructor() + ->getMock(); + } + public function getFFMpegDriverMock() { return $this->getMockBuilder('FFMpeg\Driver\FFMpegDriver') @@ -129,7 +136,7 @@ class TestCase extends \PHPUnit_Framework_TestCase ->getMock(); $video->expects($this->any()) - ->method('getFilename') + ->method('getPathfile') ->will($this->returnValue($filename)); return $video;