From d3e97c974edc5ff46ddd5b0d8f157393e11b8f53 Mon Sep 17 00:00:00 2001 From: Romain Neutron Date: Thu, 10 Oct 2013 15:09:10 +0200 Subject: [PATCH] Add support for video to audio transcoding --- CHANGELOG.md | 3 ++ src/FFMpeg/Format/Audio/DefaultAudio.php | 8 +++ src/FFMpeg/Format/AudioInterface.php | 7 --- src/FFMpeg/Format/FormatInterface.php | 13 +++++ src/FFMpeg/Format/Video/DefaultVideo.php | 8 --- src/FFMpeg/Format/VideoInterface.php | 7 --- src/FFMpeg/Media/Video.php | 68 ++++++++++++++---------- tests/FFMpeg/Tests/Media/AudioProg.php | 10 ++++ tests/FFMpeg/Tests/Media/AudioTest.php | 4 -- tests/FFMpeg/Tests/Media/Prog.php | 10 ++++ tests/FFMpeg/Tests/Media/VideoTest.php | 48 +++++++++++++++-- 11 files changed, 127 insertions(+), 59 deletions(-) create mode 100644 tests/FFMpeg/Tests/Media/AudioProg.php create mode 100644 tests/FFMpeg/Tests/Media/Prog.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 3e6796d..5bb689f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,9 @@ CHANGELOG * 0.4.0 (xx-xx-xxxx) + * Add support for video to audio transcoding + * BC Break : Add FormatInterface::getPasses and FormatInterface::getExtraParams + * 0.3.5 (xx-xx-2013) * Add vorbis audio format (@jacobbudin). diff --git a/src/FFMpeg/Format/Audio/DefaultAudio.php b/src/FFMpeg/Format/Audio/DefaultAudio.php index a0002d1..7e099e3 100644 --- a/src/FFMpeg/Format/Audio/DefaultAudio.php +++ b/src/FFMpeg/Format/Audio/DefaultAudio.php @@ -103,4 +103,12 @@ abstract class DefaultAudio extends EventEmitter implements AudioInterface, Prog return array($listener); } + + /** + * {@inheritDoc} + */ + public function getPasses() + { + return 1; + } } diff --git a/src/FFMpeg/Format/AudioInterface.php b/src/FFMpeg/Format/AudioInterface.php index 3cf254b..10e6854 100644 --- a/src/FFMpeg/Format/AudioInterface.php +++ b/src/FFMpeg/Format/AudioInterface.php @@ -19,13 +19,6 @@ interface AudioInterface extends FormatInterface */ public function getAudioKiloBitrate(); - /** - * Returns an array of extra parameters to add to ffmpeg commandline. - * - * @return array() - */ - public function getExtraParams(); - /** * Returns the audio codec. * diff --git a/src/FFMpeg/Format/FormatInterface.php b/src/FFMpeg/Format/FormatInterface.php index 4495f7a..979a091 100644 --- a/src/FFMpeg/Format/FormatInterface.php +++ b/src/FFMpeg/Format/FormatInterface.php @@ -12,4 +12,17 @@ namespace FFMpeg\Format; interface FormatInterface { + /** + * Returns the number of passes. + * + * @return string + */ + public function getPasses(); + + /** + * Returns an array of extra parameters to add to ffmpeg commandline. + * + * @return array() + */ + public function getExtraParams(); } diff --git a/src/FFMpeg/Format/Video/DefaultVideo.php b/src/FFMpeg/Format/Video/DefaultVideo.php index f74b23e..b33965d 100644 --- a/src/FFMpeg/Format/Video/DefaultVideo.php +++ b/src/FFMpeg/Format/Video/DefaultVideo.php @@ -86,14 +86,6 @@ abstract class DefaultVideo extends DefaultAudio implements VideoInterface return $this; } - /** - * {@inheritDoc} - */ - public function getPasses() - { - return 1; - } - /** * @return integer */ diff --git a/src/FFMpeg/Format/VideoInterface.php b/src/FFMpeg/Format/VideoInterface.php index 6bf91a1..fa6fb0c 100644 --- a/src/FFMpeg/Format/VideoInterface.php +++ b/src/FFMpeg/Format/VideoInterface.php @@ -20,13 +20,6 @@ interface VideoInterface extends AudioInterface */ public function getKiloBitrate(); - /** - * Returns the number of passes. - * - * @return string - */ - public function getPasses(); - /** * Returns the modulus used by the Resizable video. * diff --git a/src/FFMpeg/Media/Video.php b/src/FFMpeg/Media/Video.php index b51549a..ae2996f 100644 --- a/src/FFMpeg/Media/Video.php +++ b/src/FFMpeg/Media/Video.php @@ -20,6 +20,8 @@ use FFMpeg\Filters\Video\VideoFilters; use FFMpeg\Filters\FilterInterface; use FFMpeg\Format\FormatInterface; use FFMpeg\Format\ProgressableInterface; +use FFMpeg\Format\AudioInterface; +use FFMpeg\Format\VideoInterface; use FFMpeg\Media\Frame; use Neutron\TemporaryFilesystem\Manager as FsManager; @@ -67,43 +69,51 @@ class Video extends Audio if ($this->driver->getConfiguration()->has('ffmpeg.threads')) { $filters->add(new SimpleFilter(array('-threads', $this->driver->getConfiguration()->get('ffmpeg.threads')))); } - if (null !== $format->getVideoCodec()) { - $filters->add(new SimpleFilter(array('-vcodec', $format->getVideoCodec()))); + if ($format instanceOf VideoInterface) { + if (null !== $format->getVideoCodec()) { + $filters->add(new SimpleFilter(array('-vcodec', $format->getVideoCodec()))); + } } - if (null !== $format->getAudioCodec()) { - $filters->add(new SimpleFilter(array('-acodec', $format->getAudioCodec()))); + if ($format instanceOf AudioInterface) { + if (null !== $format->getAudioCodec()) { + $filters->add(new SimpleFilter(array('-acodec', $format->getAudioCodec()))); + } } foreach ($filters as $filter) { $commands = array_merge($commands, $filter->apply($this, $format)); } - $commands[] = '-b:v'; - $commands[] = $format->getKiloBitrate() . 'k'; - $commands[] = '-refs'; - $commands[] = '6'; - $commands[] = '-coder'; - $commands[] = '1'; - $commands[] = '-sc_threshold'; - $commands[] = '40'; - $commands[] = '-flags'; - $commands[] = '+loop'; - $commands[] = '-me_range'; - $commands[] = '16'; - $commands[] = '-subq'; - $commands[] = '7'; - $commands[] = '-i_qfactor'; - $commands[] = '0.71'; - $commands[] = '-qcomp'; - $commands[] = '0.6'; - $commands[] = '-qdiff'; - $commands[] = '4'; - $commands[] = '-trellis'; - $commands[] = '1'; + if ($format instanceOf VideoInterface) { + $commands[] = '-b:v'; + $commands[] = $format->getKiloBitrate() . 'k'; + $commands[] = '-refs'; + $commands[] = '6'; + $commands[] = '-coder'; + $commands[] = '1'; + $commands[] = '-sc_threshold'; + $commands[] = '40'; + $commands[] = '-flags'; + $commands[] = '+loop'; + $commands[] = '-me_range'; + $commands[] = '16'; + $commands[] = '-subq'; + $commands[] = '7'; + $commands[] = '-i_qfactor'; + $commands[] = '0.71'; + $commands[] = '-qcomp'; + $commands[] = '0.6'; + $commands[] = '-qdiff'; + $commands[] = '4'; + $commands[] = '-trellis'; + $commands[] = '1'; + } - if (null !== $format->getAudioKiloBitrate()) { - $commands[] = '-b:a'; - $commands[] = $format->getAudioKiloBitrate() . 'k'; + if ($format instanceOf AudioInterface) { + if (null !== $format->getAudioKiloBitrate()) { + $commands[] = '-b:a'; + $commands[] = $format->getAudioKiloBitrate() . 'k'; + } } $fs = FsManager::create(); diff --git a/tests/FFMpeg/Tests/Media/AudioProg.php b/tests/FFMpeg/Tests/Media/AudioProg.php new file mode 100644 index 0000000..e4554d4 --- /dev/null +++ b/tests/FFMpeg/Tests/Media/AudioProg.php @@ -0,0 +1,10 @@ +method('getPasses') ->will($this->returnValue(2)); + $audioFormat = $this->getMock('FFMpeg\Format\AudioInterface'); + $audioFormat->expects($this->any()) + ->method('getExtraParams') + ->will($this->returnValue(array())); + $audioFormat->expects($this->any()) + ->method('getAudioCodec') + ->will($this->returnValue('patati-patata-audio')); + $audioFormat->expects($this->any()) + ->method('getAudioKiloBitrate') + ->will($this->returnValue(92)); + $audioFormat->expects($this->any()) + ->method('getPasses') + ->will($this->returnValue(1)); + $audioVideoFormat = $this->getMock('FFMpeg\Format\VideoInterface'); $audioVideoFormat->expects($this->any()) ->method('getExtraParams') @@ -333,6 +347,24 @@ class VideoTest extends AbstractStreamableTestCase ->method('getPasses') ->will($this->returnValue(2)); + $progressableAudioFormat = $this->getMockBuilder('FFMpeg\Tests\Media\AudioProg') + ->disableOriginalConstructor()->getMock(); + $progressableAudioFormat->expects($this->any()) + ->method('getExtraParams') + ->will($this->returnValue(array())); + $progressableAudioFormat->expects($this->any()) + ->method('getAudioCodec') + ->will($this->returnValue('patati-patata-audio')); + $progressableAudioFormat->expects($this->any()) + ->method('createProgressListener') + ->will($this->returnValue($listeners)); + $progressableAudioFormat->expects($this->any()) + ->method('getAudioKiloBitrate') + ->will($this->returnValue(92)); + $progressableAudioFormat->expects($this->any()) + ->method('getPasses') + ->will($this->returnValue(1)); + return array( array(false, array(array( '-y', '-i', __FILE__, '-b:v', '663k', @@ -451,6 +483,18 @@ class VideoTest extends AbstractStreamableTestCase '-qdiff', '4', '-trellis', '1', '-b:a', '92k', '-pass', '2', '-passlogfile', '/target/file', )), $listeners, $progressableFormat), + array(true, array(array( + '-y', '-i', __FILE__, + '-threads', 24, '-acodec', 'patati-patata-audio', + '-b:a', '92k', + '/target/file', + )), null, $audioFormat), + array(true, array(array( + '-y', '-i', __FILE__, + '-threads', 24, '-acodec', 'patati-patata-audio', + '-b:a', '92k', + '/target/file', + )), $listeners, $progressableAudioFormat), ); } @@ -555,7 +599,3 @@ class VideoTest extends AbstractStreamableTestCase return 'FFMpeg\Media\Video'; } } - -abstract class Prog implements ProgressableInterface, VideoInterface -{ -}