From 5443b92337fffddcb38190aac40270bebea844a6 Mon Sep 17 00:00:00 2001 From: DariusIII Date: Thu, 27 Sep 2018 16:00:30 +0200 Subject: [PATCH] Use php-ffmpeg/php-ffmpeg for ffmpeg files manipulation --- .../processing/post/ProcessAdditional.php | 99 +++-- Changelog | 2 + composer.json | 1 + composer.lock | 337 +++++++++++++++--- 4 files changed, 337 insertions(+), 102 deletions(-) diff --git a/Blacklight/processing/post/ProcessAdditional.php b/Blacklight/processing/post/ProcessAdditional.php index 50672bb78..d77ebf8c6 100755 --- a/Blacklight/processing/post/ProcessAdditional.php +++ b/Blacklight/processing/post/ProcessAdditional.php @@ -20,6 +20,13 @@ use Blacklight\SphinxSearch; use Blacklight\utility\Utility; use dariusiii\rarinfo\Par2Info; use dariusiii\rarinfo\ArchiveInfo; +use FFMpeg\Coordinate\Dimension; +use FFMpeg\Coordinate\TimeCode; +use FFMpeg\FFMpeg; +use FFMpeg\FFProbe; +use FFMpeg\Filters\Video\ResizeFilter; +use FFMpeg\Format\Audio\Vorbis; +use FFMpeg\Format\Video\Ogg; use Illuminate\Support\Facades\DB; class ProcessAdditional @@ -371,6 +378,16 @@ class ProcessAdditional */ protected $sphinx; + /** + * @var \FFMpeg\FFMpeg + */ + private $ffmpeg; + + /** + * @var \FFMpeg\FFProbe + */ + private $ffprobe; + /** * ProcessAdditional constructor. * @@ -408,6 +425,8 @@ class ProcessAdditional $this->_par2Info = new Par2Info(); $this->_nfo = ($options['Nfo'] instanceof Nfo ? $options['Nfo'] : new Nfo()); $this->sphinx = ($options['SphinxSearch'] instanceof SphinxSearch ? $options['SphinxSearch'] : new SphinxSearch()); + $this->ffmpeg = FFMpeg::create(['timeout' => Settings::settingValue('..timeoutseconds')]); + $this->ffprobe = FFProbe::create(); $this->_innerFileBlacklist = Settings::settingValue('indexer.ppa.innerfileblacklist') === '' ? false : Settings::settingValue('indexer.ppa.innerfileblacklist'); $this->_maxNestedLevels = (int) Settings::settingValue('..maxnestedlevels') === 0 ? 3 : (int) Settings::settingValue('..maxnestedlevels'); @@ -1782,15 +1801,12 @@ class ProcessAdditional $audioFileName = ($this->_release->guid.'.ogg'); // Create an audio sample. - runCmd( - $this->_killString. - Settings::settingValue('apps..ffmpegpath'). - '" -t 30 -i "'. - $fileLocation. - '" -acodec libvorbis -loglevel quiet -y "'. - $this->tmpPath.$audioFileName. - '"' - ); + if ($this->ffprobe->isValid($fileLocation)) { + $audioSample = $this->ffmpeg->open($fileLocation); + $format = new Vorbis(); + $audioSample->clip(TimeCode::fromSeconds(30), TimeCode::fromSeconds(30)); + $audioSample->save($format, $this->tmpPath.$audioFileName); + } // Check if the new file was created. if (is_file($this->tmpPath.$audioFileName)) { @@ -1854,7 +1870,7 @@ class ProcessAdditional } /** - * @param $videoLocation + * @param string $videoLocation * @return string * @throws \Exception */ @@ -1869,14 +1885,9 @@ class ProcessAdditional $tmpVideo = ($this->tmpPath.uniqid('', true).$extension); // Get the real duration of the file. - $time = runCmd( - $this->_killString. - Settings::settingValue('apps..ffmpegpath'). - '" -i "'.$videoLocation. - '" -vcodec copy -y 2>&1 "'. - $tmpVideo.'"', - false - ); + if ($this->ffprobe->isValid($videoLocation)) { + $time = $this->ffprobe->format($videoLocation)->get('duration'); + } @unlink($tmpVideo); if (empty($time) || ! preg_match('/time=(\d{1,2}:\d{1,2}:)?(\d{1,2})\.(\d{1,2})\s*bitrate=/i', $time, $numbers)) { @@ -1914,16 +1925,11 @@ class ProcessAdditional $time = $this->getVideoTime($fileLocation); // Create the image. - runCmd( - $this->_killString. - Settings::settingValue('apps..ffmpegpath'). - '" -i "'. - $fileLocation. - '" -ss '.($time === '' ? '00:00:03.00' : $time). - ' -vframes 1 -loglevel quiet -y "'. - $fileName. - '"' - ); + if ($this->ffprobe->isValid($fileLocation)) { + $video = $this->ffmpeg->open($fileLocation); + $sample = $video->frame(TimeCode::fromSeconds($time === '' ? 3 : $time)); + $sample->save($fileName); + } // Check if the file exists. if (is_file($fileName)) { @@ -2007,34 +2013,25 @@ class ProcessAdditional } // Try to get the sample (from the end instead of the start). - runCmd( - $this->_killString. - Settings::settingValue('apps..ffmpegpath'). - '" -i "'. - $fileLocation. - '" -ss '.$lowestLength. - ' -t '.$this->_ffMPEGDuration. - ' -vcodec libtheora -filter:v scale=320:-1 '. - ' -acodec libvorbis -loglevel quiet -y "'. - $fileName. - '"' - ); + if ($this->ffprobe->isValid($fileLocation)) { + $video = $this->ffmpeg->open($fileLocation); + $videoSample = $video->clip(TimeCode::fromString($lowestLength), TimeCode::fromSeconds($this->_ffMPEGDuration)); + $format = new Ogg(); + $videoSample->filters()->resize(new Dimension(320, -1), ResizeFilter::RESIZEMODE_SCALE_HEIGHT); + $videoSample->save($format, $fileName); + } } } if ($newMethod === false) { // If longer than 60 or we could not get the video length, run the old way. - runCmd( - $this->_killString. - Settings::settingValue('apps..ffmpegpath'). - '" -i "'. - $fileLocation. - '" -vcodec libtheora -filter:v scale=320:-1 -t '. - $this->_ffMPEGDuration. - ' -acodec libvorbis -loglevel quiet -y "'. - $fileName. - '"' - ); + if ($this->ffprobe->isValid($fileLocation)) { + $video = $this->ffmpeg->open($fileLocation); + $videoSample = $video->clip(TimeCode::fromSeconds(1), TimeCode::fromSeconds($this->_ffMPEGDuration)); + $format = new Ogg(); + $videoSample->filters()->resize(new Dimension(320, -1), ResizeFilter::RESIZEMODE_SCALE_HEIGHT); + $videoSample->save($format, $fileName); + } } // Until we find the video file. diff --git a/Changelog b/Changelog index b2db7ea12..0678ec445 100755 --- a/Changelog +++ b/Changelog @@ -1,3 +1,5 @@ +2018-09-27 DariusIII + * Chg: Use php-ffmpeg/php-ffmpeg for ffmpeg files manipulation 2018-09-26 DariusIII * Fix: Fix undefined offset 0 in Binaries class postdate function * Chg: Update tmux install script to use tmux 2.8-rc to compile tmux diff --git a/composer.json b/composer.json index cb8a75848..7d81d2729 100755 --- a/composer.json +++ b/composer.json @@ -155,6 +155,7 @@ "messerli90/igdb": "^1.0", "monolog/monolog": "^1.22", "nzedb/Git.php": "dev-master", + "php-ffmpeg/php-ffmpeg": "^0.13.0", "php-http/guzzle6-adapter": "^1.1", "php-http/message": "^1.6", "php-tmdb/api": "~2.1", diff --git a/composer.lock b/composer.lock index d00d0328f..e7981a68f 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "73d050456acb6fc2c38248a4f2c705ae", + "content-hash": "941be88eda29a68d6dcba35f3edac2b8", "packages": [ { "name": "aharen/omdbapi", @@ -48,6 +48,69 @@ ], "time": "2017-05-19T02:39:02+00:00" }, + { + "name": "alchemy/binary-driver", + "version": "v2.0.0", + "source": { + "type": "git", + "url": "https://github.com/alchemy-fr/BinaryDriver.git", + "reference": "6ccde0e19e81e54da77b08da1a176d43e089f3a3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/alchemy-fr/BinaryDriver/zipball/6ccde0e19e81e54da77b08da1a176d43e089f3a3", + "reference": "6ccde0e19e81e54da77b08da1a176d43e089f3a3", + "shasum": "" + }, + "require": { + "evenement/evenement": "^2.0|^1.0", + "monolog/monolog": "^1.3", + "php": ">=5.5", + "psr/log": "^1.0", + "symfony/process": "^2.3|^3.0|^4.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.0|^5.0" + }, + "type": "library", + "autoload": { + "psr-0": { + "Alchemy": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Romain Neutron", + "email": "imprec@gmail.com", + "homepage": "http://www.lickmychip.com/" + }, + { + "name": "Phraseanet Team", + "email": "info@alchemy.fr", + "homepage": "http://www.phraseanet.com/" + }, + { + "name": "Nicolas Le Goff", + "email": "legoff.n@gmail.com" + }, + { + "name": "Jens Hausdorf", + "email": "mail@jens-hausdorf.de", + "homepage": "https://jens-hausdorf.de", + "role": "Maintainer" + } + ], + "description": "A set of tools to build binary drivers", + "keywords": [ + "binary", + "driver" + ], + "time": "2018-08-06T10:18:33+00:00" + }, { "name": "anhskohbo/no-captcha", "version": "3.0.3", @@ -2514,6 +2577,54 @@ ], "time": "2018-03-08T01:11:30+00:00" }, + { + "name": "evenement/evenement", + "version": "v2.1.0", + "source": { + "type": "git", + "url": "https://github.com/igorw/evenement.git", + "reference": "6ba9a777870ab49f417e703229d53931ed40fd7a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/igorw/evenement/zipball/6ba9a777870ab49f417e703229d53931ed40fd7a", + "reference": "6ba9a777870ab49f417e703229d53931ed40fd7a", + "shasum": "" + }, + "require": { + "php": ">=5.4.0" + }, + "require-dev": { + "phpunit/phpunit": "^6.0||^5.7||^4.8.35" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "psr-0": { + "Evenement": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Igor Wiedler", + "email": "igor@wiedler.ch" + } + ], + "description": "Événement is a very simple event dispatching library for PHP", + "keywords": [ + "event-dispatcher", + "event-emitter" + ], + "time": "2017-07-17T17:39:19+00:00" + }, { "name": "exeu/apai-io", "version": "2.2.0", @@ -4573,6 +4684,46 @@ ], "time": "2018-09-20T19:36:25+00:00" }, + { + "name": "neutron/temporary-filesystem", + "version": "2.3.0", + "source": { + "type": "git", + "url": "https://github.com/romainneutron/Temporary-Filesystem.git", + "reference": "694aa3885f653dd429584e825ffbab79441d285f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/romainneutron/Temporary-Filesystem/zipball/694aa3885f653dd429584e825ffbab79441d285f", + "reference": "694aa3885f653dd429584e825ffbab79441d285f", + "shasum": "" + }, + "require": { + "php": "^5.6 || ^7.0", + "symfony/filesystem": "^2.3 || ^3.0 || ^4.0" + }, + "require-dev": { + "phpunit/phpunit": "^5.0" + }, + "type": "library", + "autoload": { + "psr-0": { + "Neutron": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Romain Neutron", + "email": "imprec@gmail.com" + } + ], + "description": "Symfony filesystem extension to handle temporary files", + "time": "2018-02-07T21:11:57+00:00" + }, { "name": "nikic/php-parser", "version": "v4.0.4", @@ -4694,6 +4845,90 @@ ], "time": "2018-07-02T15:55:56+00:00" }, + { + "name": "php-ffmpeg/php-ffmpeg", + "version": "v0.13", + "source": { + "type": "git", + "url": "https://github.com/PHP-FFMpeg/PHP-FFMpeg.git", + "reference": "c11b79ab5b0174aa1a56c54c67491169e78a4c17" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/PHP-FFMpeg/PHP-FFMpeg/zipball/c11b79ab5b0174aa1a56c54c67491169e78a4c17", + "reference": "c11b79ab5b0174aa1a56c54c67491169e78a4c17", + "shasum": "" + }, + "require": { + "alchemy/binary-driver": "^1.5 || ~2.0.0", + "doctrine/cache": "^1.0", + "evenement/evenement": "^2.0 || ^1.0", + "neutron/temporary-filesystem": "^2.1.1", + "php": "^5.3.9 || ^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.8.36", + "sami/sami": "~1.0", + "silex/silex": "~1.0" + }, + "suggest": { + "php-ffmpeg/extras": "A compilation of common audio & video drivers for PHP-FFMpeg" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "0.7-dev" + } + }, + "autoload": { + "psr-0": { + "FFMpeg": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Romain Neutron", + "email": "imprec@gmail.com", + "homepage": "http://www.lickmychip.com/" + }, + { + "name": "Phraseanet Team", + "email": "info@alchemy.fr", + "homepage": "http://www.phraseanet.com/" + }, + { + "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/" + }, + { + "name": "Jens Hausdorf", + "email": "hello@jens-hausdorf.de", + "homepage": "https://jens-hausdorf.de" + } + ], + "description": "FFMpeg PHP, an Object Oriented library to communicate with AVconv / ffmpeg", + "keywords": [ + "audio", + "audio processing", + "avconv", + "avprobe", + "ffmpeg", + "ffprobe", + "video", + "video processing" + ], + "time": "2018-08-06T20:02:43+00:00" + }, { "name": "php-http/guzzle6-adapter", "version": "v1.1.1", @@ -6203,6 +6438,56 @@ "homepage": "https://symfony.com", "time": "2018-07-26T09:10:45+00:00" }, + { + "name": "symfony/filesystem", + "version": "v4.1.4", + "source": { + "type": "git", + "url": "https://github.com/symfony/filesystem.git", + "reference": "c0f5f62db218fa72195b8b8700e4b9b9cf52eb5e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/c0f5f62db218fa72195b8b8700e4b9b9cf52eb5e", + "reference": "c0f5f62db218fa72195b8b8700e4b9b9cf52eb5e", + "shasum": "" + }, + "require": { + "php": "^7.1.3", + "symfony/polyfill-ctype": "~1.8" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.1-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Filesystem\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Filesystem Component", + "homepage": "https://symfony.com", + "time": "2018-08-18T16:52:46+00:00" + }, { "name": "symfony/finder", "version": "v4.1.4", @@ -10412,56 +10697,6 @@ "homepage": "https://symfony.com", "time": "2018-08-08T06:37:38+00:00" }, - { - "name": "symfony/filesystem", - "version": "v4.1.4", - "source": { - "type": "git", - "url": "https://github.com/symfony/filesystem.git", - "reference": "c0f5f62db218fa72195b8b8700e4b9b9cf52eb5e" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/c0f5f62db218fa72195b8b8700e4b9b9cf52eb5e", - "reference": "c0f5f62db218fa72195b8b8700e4b9b9cf52eb5e", - "shasum": "" - }, - "require": { - "php": "^7.1.3", - "symfony/polyfill-ctype": "~1.8" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "4.1-dev" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Component\\Filesystem\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony Filesystem Component", - "homepage": "https://symfony.com", - "time": "2018-08-18T16:52:46+00:00" - }, { "name": "symfony/stopwatch", "version": "v4.1.4",