From 462663fbddd77269c617e621205c5a02b9e8be48 Mon Sep 17 00:00:00 2001 From: a3020 Date: Tue, 20 Dec 2016 11:42:05 +0100 Subject: [PATCH 01/14] Explicitly --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 3f7cc1f..62d47d5 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ Check another amazing repo : [PHP FFMpeg extras](https://github.com/alchemy-fr/P 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. +otherwise you should have to explicitly give the binaries path on load. For Windows users : Please find the binaries at http://ffmpeg.zeranoe.com/builds/. @@ -69,7 +69,7 @@ $ffmpeg = FFMpeg\FFMpeg::create(); ``` FFMpeg will autodetect ffmpeg and ffprobe binaries. If you want to give binary -paths explicitely, you can pass an array as configuration. A `Psr\Logger\LoggerInterface` +paths explicitly, you can pass an array as configuration. A `Psr\Logger\LoggerInterface` can also be passed to log binary executions. ```php From 345656b1dc55f0ec61d53835262dd50ec74ab827 Mon Sep 17 00:00:00 2001 From: Romain Biard Date: Tue, 20 Dec 2016 18:25:45 -0300 Subject: [PATCH 02/14] Creation of a pad filters which adds padding (black bars) to a video --- src/FFMpeg/Filters/Video/PadFilter.php | 60 +++++++++++++++++++++++ src/FFMpeg/Filters/Video/VideoFilters.php | 14 ++++++ 2 files changed, 74 insertions(+) create mode 100644 src/FFMpeg/Filters/Video/PadFilter.php diff --git a/src/FFMpeg/Filters/Video/PadFilter.php b/src/FFMpeg/Filters/Video/PadFilter.php new file mode 100644 index 0000000..551604c --- /dev/null +++ b/src/FFMpeg/Filters/Video/PadFilter.php @@ -0,0 +1,60 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace FFMpeg\Filters\Video; + +use FFMpeg\Coordinate\Dimension; +use FFMpeg\Exception\RuntimeException; +use FFMpeg\Media\Video; +use FFMpeg\Format\VideoInterface; + +class PadFilter implements VideoFilterInterface +{ + /** @var Dimension */ + private $dimension; + /** @var integer */ + private $priority; + + public function __construct(Dimension $dimension, $priority = 0) + { + $this->dimension = $dimension; + $this->priority = $priority; + } + + /** + * {@inheritdoc} + */ + public function getPriority() + { + return $this->priority; + } + + /** + * @return Dimension + */ + public function getDimension() + { + return $this->dimension; + } + + /** + * {@inheritdoc} + */ + public function apply(Video $video, VideoInterface $format) + { + $commands = array(); + + $commands[] = '-vf'; + $commands[] = 'pad=' . $this->dimension->getWidth() . ':' . $this->dimension->getHeight() . ':(' . $this->dimension->getWidth() . '-iw)/2:(' . $this->dimension->getHeight() .'-ih)/2'; + + return $commands; + } +} diff --git a/src/FFMpeg/Filters/Video/VideoFilters.php b/src/FFMpeg/Filters/Video/VideoFilters.php index 00a99d9..a5caa32 100644 --- a/src/FFMpeg/Filters/Video/VideoFilters.php +++ b/src/FFMpeg/Filters/Video/VideoFilters.php @@ -98,6 +98,20 @@ class VideoFilters extends AudioFilters return $this; } + /** + * Adds padding (black bars) to a video. + * + * @param Dimension $dimension + * + * @return VideoFilters + */ + public function pad(Dimension $dimension) + { + $this->media->addFilter(new PadFilter($dimension)); + + return $this; + } + public function rotate($angle) { $this->media->addFilter(new RotateFilter($angle, 30)); From 7c4eed68f9eea91537efa06bf50665c286b1bf09 Mon Sep 17 00:00:00 2001 From: Romain Biard Date: Tue, 20 Dec 2016 18:47:40 -0300 Subject: [PATCH 03/14] We change the way we execute this filter. --- src/FFMpeg/Filters/Video/PadFilter.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/FFMpeg/Filters/Video/PadFilter.php b/src/FFMpeg/Filters/Video/PadFilter.php index 551604c..df19a2d 100644 --- a/src/FFMpeg/Filters/Video/PadFilter.php +++ b/src/FFMpeg/Filters/Video/PadFilter.php @@ -53,7 +53,7 @@ class PadFilter implements VideoFilterInterface $commands = array(); $commands[] = '-vf'; - $commands[] = 'pad=' . $this->dimension->getWidth() . ':' . $this->dimension->getHeight() . ':(' . $this->dimension->getWidth() . '-iw)/2:(' . $this->dimension->getHeight() .'-ih)/2'; + $commands[] = 'scale=iw*min(' . $this->dimension->getWidth() . '/iw\,' . $this->dimension->getHeight() .'/ih):ih*min(' . $this->dimension->getWidth() . '/iw\,' . $this->dimension->getHeight() .'/ih),pad=' . $this->dimension->getWidth() . ':' . $this->dimension->getHeight() . ':(' . $this->dimension->getWidth() . '-iw)/2:(' . $this->dimension->getHeight() .'-ih)/2'; return $commands; } From bbe94784c2d7388e4c29a753ac6af1587c8b55ca Mon Sep 17 00:00:00 2001 From: Romain Biard Date: Wed, 21 Dec 2016 10:26:51 -0300 Subject: [PATCH 04/14] Addition of the tests --- composer.json | 5 +++ tests/Unit/Filters/Video/PadFilterTest.php | 44 ++++++++++++++++++++++ 2 files changed, 49 insertions(+) create mode 100644 tests/Unit/Filters/Video/PadFilterTest.php diff --git a/composer.json b/composer.json index 7e2babf..c7a79b4 100644 --- a/composer.json +++ b/composer.json @@ -19,6 +19,11 @@ "name": "Patrik Karisch", "email": "patrik@karisch.guru", "homepage": "http://www.karisch.guru" + }, + { + "name": "Romain Biard", + "email": "romain.biard@gmail.com", + "homepage": "https://www.strime.io/" } ], "require": { diff --git a/tests/Unit/Filters/Video/PadFilterTest.php b/tests/Unit/Filters/Video/PadFilterTest.php new file mode 100644 index 0000000..0fc48e6 --- /dev/null +++ b/tests/Unit/Filters/Video/PadFilterTest.php @@ -0,0 +1,44 @@ +getVideoMock(); + $pathfile = '/path/to/file'.mt_rand(); + + $format = $this->createMock('FFMpeg\Format\VideoInterface'); + + $streams = new StreamCollection(array( + new Stream(array( + 'codec_type' => 'video', + 'width' => $width, + 'height' => $height, + )) + )); + + $filter = new PadFilter($dimension); + $this->assertEquals($expected, $filter->apply($video, $format)); + } + + public function provideDimensions() + { + return array( + array(new Dimension(1000, 800), 640, 480, array('-vf', 'scale=iw*min(1000/iw\,800/ih):ih*min(1000/iw\,800/ih),pad=1000:800:(1000-iw)/2:(800-ih)/2')), + array(new Dimension(300, 600), 640, 480, array('-vf', 'scale=iw*min(300/iw\,600/ih):ih*min(300/iw\,600/ih),pad=300:600:(300-iw)/2:(600-ih)/2')), + array(new Dimension(100, 900), 640, 480, array('-vf', 'scale=iw*min(100/iw\,900/ih):ih*min(100/iw\,900/ih),pad=100:900:(100-iw)/2:(900-ih)/2')), + array(new Dimension(1200, 200), 640, 480, array('-vf', 'scale=iw*min(1200/iw\,200/ih):ih*min(1200/iw\,200/ih),pad=1200:200:(1200-iw)/2:(200-ih)/2')), + ); + } +} From 52d32ec70b9671558fd600c8264e7398683a024a Mon Sep 17 00:00:00 2001 From: Romain Biard Date: Wed, 21 Dec 2016 10:30:52 -0300 Subject: [PATCH 05/14] Update of the README --- README.md | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 3f7cc1f..94196dc 100644 --- a/README.md +++ b/README.md @@ -221,12 +221,28 @@ Resizes a video to a given size. $video->filters()->resize($dimension, $mode, $useStandards); ``` -The resize filter takes three parameters : +The resize filter takes three parameters: - `$dimension`, an instance of `FFMpeg\Coordinate\Dimension` - `$mode`, one of the constants `FFMpeg\Filters\Video\ResizeFilter::RESIZEMODE_*` constants - `$useStandards`, a boolean to force the use of the nearest aspect ratio standard. +If you want a video in a non-standard ratio, you can use the padding filter to resize your video in the desired size, and wrap it into black bars. + +```php +$video->filters()->pad($dimension); +``` + +The pad filter takes one parameter: + +- `$dimension`, an instance of `FFMpeg\Coordinate\Dimension` + +Don't forget to save it afterwards. + +```php +$video->save(new FFMpeg\Format\Video\X264(), $new_file); +``` + ###### Watermark Watermark a video with a given image. From ad2adb61d1473bfa40c3dd6df2b3153fca11918f Mon Sep 17 00:00:00 2001 From: Romain Biard Date: Wed, 21 Dec 2016 12:42:42 -0300 Subject: [PATCH 06/14] We exclude sami.phar of the git tracking --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index c85f162..2b7fb77 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ composer.phar composer.lock phpunit.xml +sami.phar From ac3e8f16ca47b8864dcb79033c2fc6929a029996 Mon Sep 17 00:00:00 2001 From: Romain Biard Date: Wed, 21 Dec 2016 12:43:57 -0300 Subject: [PATCH 07/14] We use getMote instead of createMock --- tests/Unit/Filters/Video/PadFilterTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Unit/Filters/Video/PadFilterTest.php b/tests/Unit/Filters/Video/PadFilterTest.php index 0fc48e6..1d7c85a 100644 --- a/tests/Unit/Filters/Video/PadFilterTest.php +++ b/tests/Unit/Filters/Video/PadFilterTest.php @@ -18,7 +18,7 @@ class PadFilterTest extends TestCase $video = $this->getVideoMock(); $pathfile = '/path/to/file'.mt_rand(); - $format = $this->createMock('FFMpeg\Format\VideoInterface'); + $format = $this->getMock('FFMpeg\Format\VideoInterface'); $streams = new StreamCollection(array( new Stream(array( From af38e5b0acb6e2c87ec013175c0cc968d2a0749f Mon Sep 17 00:00:00 2001 From: Romain Biard Date: Wed, 28 Dec 2016 16:42:03 -0300 Subject: [PATCH 08/14] Creation of a method to apply custom filters --- src/FFMpeg/Filters/Video/VideoFilters.php | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/FFMpeg/Filters/Video/VideoFilters.php b/src/FFMpeg/Filters/Video/VideoFilters.php index 00a99d9..4978e80 100644 --- a/src/FFMpeg/Filters/Video/VideoFilters.php +++ b/src/FFMpeg/Filters/Video/VideoFilters.php @@ -132,4 +132,18 @@ class VideoFilters extends AudioFilters return $this; } + + /** + * Resizes a video to a given dimension. + * + * @param string $parameters + * + * @return VideoFilters + */ + public function custom($parameters) + { + $this->media->addFilter(new CustomFilter($parameters)); + + return $this; + } } From 71bfcbcc1172eba3dbb610155f01b36fe78a8b48 Mon Sep 17 00:00:00 2001 From: Romain Biard Date: Wed, 28 Dec 2016 16:47:22 -0300 Subject: [PATCH 09/14] We change the description of the method --- src/FFMpeg/Filters/Video/VideoFilters.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/FFMpeg/Filters/Video/VideoFilters.php b/src/FFMpeg/Filters/Video/VideoFilters.php index 4978e80..af319c6 100644 --- a/src/FFMpeg/Filters/Video/VideoFilters.php +++ b/src/FFMpeg/Filters/Video/VideoFilters.php @@ -134,7 +134,7 @@ class VideoFilters extends AudioFilters } /** - * Resizes a video to a given dimension. + * Applies a custom filter: -vf foo bar * * @param string $parameters * From f0ca0c950fb53bff05a92683ee85955bd9fe20dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Malte=20Bl=C3=A4ttermann?= Date: Wed, 4 Jan 2017 10:12:45 +0100 Subject: [PATCH 10/14] Change installation method to composer require The composer.json SHOULD NOT be edited by hand for installation. --- README.md | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 62d47d5..81f809e 100644 --- a/README.md +++ b/README.md @@ -28,12 +28,8 @@ appear in latest ffmpeg version. The recommended way to install PHP-FFMpeg is through [Composer](https://getcomposer.org). -```json -{ - "require": { - "php-ffmpeg/php-ffmpeg": "~0.5" - } -} +```bash +$ composer require php-ffmpeg/php-ffmpeg ``` ## Basic Usage From 8cfb17682f368053ef3ccf6de2d4cc0f49b362dc Mon Sep 17 00:00:00 2001 From: shadrech Date: Mon, 9 Jan 2017 13:41:32 +0000 Subject: [PATCH 11/14] Add metadata to audio files - feature --- README.md | 21 +++++++++ .../Filters/Audio/AddMetadataFilter.php | 42 +++++++++++++++++ src/FFMpeg/Filters/Audio/AudioFilters.php | 22 +++++++++ .../Unit/Filters/Audio/AudioMetadataTest.php | 45 +++++++++++++++++++ 4 files changed, 130 insertions(+) create mode 100644 src/FFMpeg/Filters/Audio/AddMetadataFilter.php create mode 100644 tests/Unit/Filters/Audio/AudioMetadataTest.php diff --git a/README.md b/README.md index 81f809e..0e47a70 100644 --- a/README.md +++ b/README.md @@ -328,6 +328,27 @@ method. It only accepts audio filters. You can build your own filters and some are bundled in PHP-FFMpeg - they are accessible through the `FFMpeg\Media\Audio::filters` method. +#### Metadata + +Add metadata to audio files. Just pass an array of key=value pairs of all +metadata you would like to add. If no arguments are passed into the filter +all metadata will be removed from input file. Currently supported data is +title, artist, album, artist, composer, track, year, description, artwork + +```php +$audio->filters()->addMetadata(["title" => "Some Title", "track" => 1]); + +//remove all metadata and video streams from audio file +$audio->filters()->addMetadata(); +``` + +Add artwork to the audio file +```php +$audio->filters()->addMetadata(["artwork" => "/path/to/image/file.jpg"]); +``` +NOTE: at present ffmpeg (version 3.2.2) only supports artwork output for .mp3 +files + ###### Resample Resamples an audio file. diff --git a/src/FFMpeg/Filters/Audio/AddMetadataFilter.php b/src/FFMpeg/Filters/Audio/AddMetadataFilter.php new file mode 100644 index 0000000..d889f45 --- /dev/null +++ b/src/FFMpeg/Filters/Audio/AddMetadataFilter.php @@ -0,0 +1,42 @@ +metaArr = $data; + } + + public function getPriority() + { + //must be of high priority in case theres a second input stream (artwork) to register with audio + return 9; + } + + public function apply(Audio $audio, AudioInterface $format) + { + if (is_null($this->metaArr)) + return ['-map_metadata', '-1', '-vn']; + + $metadata = []; + + if (array_key_exists("artwork", $this->metaArr)) { + array_push($metadata, "-i", $this->metaArr['artwork'], "-map", "0", "-map", "1"); + unset($this->metaArr['artwork']); + } + + foreach ($this->metaArr as $k => $v) { + array_push($metadata, "-metadata", "$k=$v"); + } + + return $metadata; + } +} diff --git a/src/FFMpeg/Filters/Audio/AudioFilters.php b/src/FFMpeg/Filters/Audio/AudioFilters.php index fe328c5..0eca6f7 100644 --- a/src/FFMpeg/Filters/Audio/AudioFilters.php +++ b/src/FFMpeg/Filters/Audio/AudioFilters.php @@ -2,6 +2,7 @@ namespace FFMpeg\Filters\Audio; +use FFMpeg\Filters\Audio\AddMetadataFilter; use FFMpeg\Media\Audio; class AudioFilters @@ -26,4 +27,25 @@ class AudioFilters return $this; } + + /** + * Add metadata to an audio file. If no arguments are given then filter + * will remove all metadata from the audio file + * @param Array|Null $data If array must contain one of these key/value pairs: + * - "title": Title metadata + * - "artist": Artist metadata + * - "composer": Composer metadata + * - "album": Album metadata + * - "track": Track metadata + * - "artwork": Song artwork. String of file path + * - "year": Year metadata + * - "genre": Genre metadata + * - "description": Description metadata + */ + public function addMetadata($data = null) + { + $this->media->addFilter(new AddMetadataFilter($data)); + + return $this; + } } diff --git a/tests/Unit/Filters/Audio/AudioMetadataTest.php b/tests/Unit/Filters/Audio/AudioMetadataTest.php new file mode 100644 index 0000000..e719fd4 --- /dev/null +++ b/tests/Unit/Filters/Audio/AudioMetadataTest.php @@ -0,0 +1,45 @@ +getAudioMock(); + $audio->expects($this->once()) + ->method('addFilter') + ->with($this->isInstanceOf('FFMpeg\Filters\Audio\AddMetadataFilter')) + ->will($this->returnCallback(function ($filter) use (&$capturedFilter) { + $capturedFilter = $filter; + })); + $format = $this->getMock('FFMpeg\Format\AudioInterface'); + + $filters = new AudioFilters($audio); + $filters->addMetadata(array('title' => "Hello World")); + $this->assertEquals(array(0 => "-metadata", 1 => "title=Hello World"), $capturedFilter->apply($audio, $format)); + } + + public function testRemoveMetadata() + { + $capturedFilter = null; + + $audio = $this->getAudioMock(); + $audio->expects($this->once()) + ->method('addFilter') + ->with($this->isInstanceOf('FFMpeg\Filters\Audio\AddMetadataFilter')) + ->will($this->returnCallback(function ($filter) use (&$capturedFilter) { + $capturedFilter = $filter; + })); + $format = $this->getMock('FFMpeg\Format\AudioInterface'); + + $filters = new AudioFilters($audio); + $filters->addMetadata(); + $this->assertEquals(array(0 => "-map_metadata", 1 => "-1", 2 => "-vn"), $capturedFilter->apply($audio, $format)); + } +} From 89098b24a2a269b43f3efc6e66dedc4f091c7902 Mon Sep 17 00:00:00 2001 From: shadrech Date: Mon, 9 Jan 2017 14:26:40 +0000 Subject: [PATCH 12/14] Add metadata to audio files | completed tests --- tests/Unit/Filters/Audio/AudioMetadataTest.php | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/tests/Unit/Filters/Audio/AudioMetadataTest.php b/tests/Unit/Filters/Audio/AudioMetadataTest.php index e719fd4..33eb470 100644 --- a/tests/Unit/Filters/Audio/AudioMetadataTest.php +++ b/tests/Unit/Filters/Audio/AudioMetadataTest.php @@ -25,6 +25,24 @@ class AudioMetadataTest extends TestCase $this->assertEquals(array(0 => "-metadata", 1 => "title=Hello World"), $capturedFilter->apply($audio, $format)); } + public function testAddArtwork() + { + $capturedFilter = null; + + $audio = $this->getAudioMock(); + $audio->expects($this->once()) + ->method('addFilter') + ->with($this->isInstanceOf('FFMpeg\Filters\Audio\AddMetadataFilter')) + ->will($this->returnCallback(function ($filter) use (&$capturedFilter) { + $capturedFilter = $filter; + })); + $format = $this->getMock('FFMpeg\Format\AudioInterface'); + + $filters = new AudioFilters($audio); + $filters->addMetadata(array('genre' => 'Some Genre', 'artwork' => "/path/to/file.jpg")); + $this->assertEquals(array(0 => "-i", 1 => "/path/to/file.jpg", 2 => "-map", 3 => "0", 4 => "-map", 5 => "1", 6 => "-metadata", 7 => "genre=Some Genre"), $capturedFilter->apply($audio, $format)); + } + public function testRemoveMetadata() { $capturedFilter = null; From 35474279e1eebcc1cdac44b4ac24e939076c3728 Mon Sep 17 00:00:00 2001 From: shadrech Date: Mon, 9 Jan 2017 17:34:43 +0000 Subject: [PATCH 13/14] Added set priority to AddMetadataFilter class --- src/FFMpeg/Filters/Audio/AddMetadataFilter.php | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/FFMpeg/Filters/Audio/AddMetadataFilter.php b/src/FFMpeg/Filters/Audio/AddMetadataFilter.php index d889f45..aa1207b 100644 --- a/src/FFMpeg/Filters/Audio/AddMetadataFilter.php +++ b/src/FFMpeg/Filters/Audio/AddMetadataFilter.php @@ -9,16 +9,19 @@ class AddMetadataFilter implements AudioFilterInterface { /** @var Array */ private $metaArr; + /** @var Integer */ + private $priority; - function __construct($data = null) + function __construct($data = null, $priority = 9) { $this->metaArr = $data; + $this->priority = $priority; } public function getPriority() { //must be of high priority in case theres a second input stream (artwork) to register with audio - return 9; + return $this->priority; } public function apply(Audio $audio, AudioInterface $format) From 48a0bdc13b17d6b0f1829698c6e83c4f5f6c1f4b Mon Sep 17 00:00:00 2001 From: shadrech Date: Mon, 9 Jan 2017 17:41:32 +0000 Subject: [PATCH 14/14] Minor ammendment to README.md file --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0e47a70..c0fb38d 100644 --- a/README.md +++ b/README.md @@ -328,7 +328,7 @@ method. It only accepts audio filters. You can build your own filters and some are bundled in PHP-FFMpeg - they are accessible through the `FFMpeg\Media\Audio::filters` method. -#### Metadata +###### Metadata Add metadata to audio files. Just pass an array of key=value pairs of all metadata you would like to add. If no arguments are passed into the filter