From 6b99c5b8c00cc401706ca1594804c49fc83b4227 Mon Sep 17 00:00:00 2001 From: Andrew Welch Date: Mon, 6 Mar 2017 23:55:45 -0500 Subject: [PATCH] ### Added - Added a summary option to `getFileInfo()` ### Changed - Refactored the `config.php` options to be more consistent --- CHANGELOG.md | 7 +++ README.md | 32 ++++++++--- composer.json | 2 +- src/config.php | 13 +++-- src/services/Transcoder.php | 84 ++++++++++++++++++++++++---- src/variables/TranscoderVariable.php | 4 +- 6 files changed, 116 insertions(+), 26 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ee63712..abb8e87 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Transcoder Changelog +## 1.0.2 - 2017.03.07 +### Added +- Added a summary option to `getFileInfo()` + +### Changed +- Refactored the `config.php` options to be more consistent + ## 1.0.1 - 2017.03.06 ### Added - Added `height` and `width` options for resizing the videos diff --git a/README.md b/README.md index ea82fcd..c4fe22b 100644 --- a/README.md +++ b/README.md @@ -66,7 +66,7 @@ It will return to you a URL to the transcoded video if it already exists, or if In the array you pass in, the default values are used if the key/value pair does not exist: { - "videoFormat" => "mp4", + "videoEncoder" => "h264", "videoBitRate" => "800k", "videoFrameRate" => 15, "aspectRatio" => "letterbox", @@ -102,7 +102,7 @@ You can control the color of the letterboxed area (it's `black` by default) via The `sharpen` option determines whether an unsharp mask filter should be applied to the scaled video. -The file format setting `videoFormat` is preset to what you'll need to generate `mp4` videos, but it can also generate `webm` videos, or any other format that `ffmpeg` supports. See the `config.php` file for details +The file format setting `videoEncoder` is preset to what you'll need to generate `h264` videos, but it can also generate `webm` videos, or any other format that `ffmpeg` supports. See the `config.php` file for details ### Generating a Transcoded Audio File @@ -128,7 +128,7 @@ It will return to you a URL to the transcoded audio file if it already exists, o In the array you pass in, the default values are used if the key/value pair does not exist: { - "audioFormat" => "mp3", + "audioEncoder" => "mp3", "audioBitRate" => "128k", "audioSampleRate" => "44100", "audioChannels" => "2", @@ -146,7 +146,7 @@ If you want to have the Transcoder not change a parameter, pass in an empty valu The above example would cause it to not change the audio of the source audio file at all (not recommended for client-proofing purposes). -The file format setting `audioFormat` is preset to what you'll need to generate `mp3` audio files, but it can also generate `m4a`, `ogg`, or any other format that `ffmpeg` supports. See the `config.php` file for details +The file format setting `audioEncoder` is preset to what you'll need to generate `mp3` audio files, but it can also generate `aac`, `ogg`, or any other format that `ffmpeg` supports. See the `config.php` file for details ### Getting Transcoding Progress @@ -242,14 +242,31 @@ The `sharpen` option determines whether an unsharp mask filter should be applied To get information about an existing video/audio file, you can use `craft.transcoder.getFileInfo()`: - {% set fileInfo = craft.transcoder.getFileInfo('/home/vagrant/sites/nystudio107/public/oceans.mp4') %} + {% set fileInfo = craft.transcoder.getFileInfo('/home/vagrant/sites/nystudio107/public/oceans.mp4', true) %} You can also pass in an `Asset`: {% set myAsset = entry.someAsset.first() %} - {% set fileInfo = craft.transcoder.getFileInfo(myAsset) %} + {% set fileInfo = craft.transcoder.getFileInfo(myAsset, true) %} -This returns an array with two top-level keys: +By passing in `true` as the second argument, we get just a summary of the video/audio file information in an array: + + [ + 'videoEncoder' => 'h264' + 'videoBitRate' => '3859635' + 'videoFrameRate' => 23.976023976024 + 'height' => 400 + 'width' => 960 + 'audioEncoder' => 'aac' + 'audioBitRate' => '92926' + 'audioSampleRate' => '48000' + 'audioChannels' => 2 + 'filename' => '/htdocs/craft3/public/assets/oceans.mp4' + 'duration' => '46.613333' + 'size' => '23014356' + ] + +If you instead pass in `false` as the second parameter (or omit it), then `craft.transcoder.getFileInfo()` returns the full video/audio file info an array with two top-level keys: * `format` - information about the container file format * `streams` - information about each stream in the container; many videos have multiple streams, for instance, one for the video streams, and another for the audio stream. There can even be multiple video or audio streams in a container. @@ -387,7 +404,6 @@ The file must reside in the webroot (thus a URL or URI must be passed in as a pa Some things to do, and ideas for potential features: -* Add a simpler way to extract the most common video/audio info from a file * Add a console command for doing encodings via console * Figure out a way to reliably do multi-pass video encoding * Add audio normalization via `loudnorm` http://k.ylo.ph/2016/04/04/loudnorm.html diff --git a/composer.json b/composer.json index 3ab9002..f7d66c3 100644 --- a/composer.json +++ b/composer.json @@ -2,7 +2,7 @@ "name": "nystudio107/craft3-transcoder", "description": "Transcode video & audio files to various formats, and provide video thumbnails", "type": "craft-plugin", - "version": "1.0.1", + "version": "1.0.2", "keywords": [ "craft", "cms", diff --git a/src/config.php b/src/config.php index ea9367d..e6be7aa 100644 --- a/src/config.php +++ b/src/config.php @@ -45,8 +45,9 @@ // Preset video encoders "videoEncoders" => [ - "mp4" => [ + "h264" => [ "fileSuffix" => ".mp4", + "fileFormat" => "mp4", "videoCodec" => "libx264", "videoCodecOptions" => "-vprofile high -preset slow -crf 22", "audioCodec" => "libfdk_aac", @@ -54,6 +55,7 @@ ], "webm" => [ "fileSuffix" => ".webm", + "fileFormat" => "webm", "videoCodec" => "libvpx", "videoCodecOptions" => "-quality good -cpu-used 0", "audioCodec" => "libvorbis", @@ -65,17 +67,20 @@ "audioEncoders" => [ "mp3" => [ "fileSuffix" => ".mp3", + "fileFormat" => "mp3", "audioCodec" => "libmp3lame", "audioCodecOptions" => "", ], - "m4a" => [ + "aac" => [ "fileSuffix" => ".m4a", + "fileFormat" => "aac", "audioCodec" => "libfdk_aac", "audioCodecOptions" => "", ], "ogg" => [ "fileSuffix" => ".ogg", + "fileFormat" => "ogg", "audioCodec" => "libvorbis", "audioCodecOptions" => "", ], @@ -84,7 +89,7 @@ // Default options for encoded videos "defaultVideoOptions" => [ // Video settings - "videoFormat" => "mp4", + "videoEncoder" => "h264", "videoBitRate" => "800k", "videoFrameRate" => 15, // Audio settings @@ -114,7 +119,7 @@ // Default options for encoded videos "defaultAudioOptions" => [ - "audioFormat" => "mp3", + "audioEncoder" => "mp3", "audioBitRate" => "128k", "audioSampleRate" => "44100", "audioChannels" => "2", diff --git a/src/services/Transcoder.php b/src/services/Transcoder.php index ba78162..9f39c55 100644 --- a/src/services/Transcoder.php +++ b/src/services/Transcoder.php @@ -12,7 +12,6 @@ use Craft; use craft\base\Component; -use craft\console\Request; use craft\elements\Asset; use craft\volumes\Local; @@ -41,12 +40,34 @@ class Transcoder extends Component // Params that should be excluded from being part of the generated filename protected $excludeParams = [ - 'videoFormat', - 'audioFormat', + 'videoEncoder', + 'audioEncoder', 'fileSuffix', 'sharpen' ]; + // Mappings for getFileInfo() summary values + protected $infoSummary = [ + 'format' => [ + 'filename' => 'filename', + 'duration' => 'duration', + 'size' => 'size', + ], + 'audio' => [ + 'codec_name' => 'audioEncoder', + 'bit_rate' => 'audioBitRate', + 'sample_rate' => 'audioSampleRate', + 'channels' => 'audioChannels', + ], + 'video' => [ + 'codec_name' => 'videoEncoder', + 'bit_rate' => 'videoBitRate', + 'avg_frame_rate' => 'videoFrameRate', + 'height' => 'height', + 'width' => 'width', + ], + ]; + // Public Methods // ========================================================================= @@ -72,7 +93,7 @@ public function getVideoUrl($filePath, $videoOptions): string // Get the video encoder presets to use $videoEncoders = Craft::$app->config->get("videoEncoders", "transcoder"); - $thisEncoder = $videoEncoders[$videoOptions['videoFormat']]; + $thisEncoder = $videoEncoders[$videoOptions['videoEncoder']]; $videoOptions['fileSuffix'] = $thisEncoder['fileSuffix']; @@ -135,7 +156,7 @@ public function getVideoUrl($filePath, $videoOptions): string // Assemble the destination path and final ffmpeg command $destVideoPath = $destVideoPath.$destVideoFile; $ffmpegCmd .= ' -f ' - .$videoOptions['videoFormat'] + .$thisEncoder['fileFormat'] .' -y '.escapeshellarg($destVideoPath) .' 1> '.$progressFile.' 2>&1 & echo $!'; @@ -249,7 +270,7 @@ public function getAudioUrl($filePath, $audioOptions): string // Get the audio encoder presets to use $audioEncoders = Craft::$app->config->get("audioEncoders", "transcoder"); - $thisEncoder = $audioEncoders[$audioOptions['audioFormat']]; + $thisEncoder = $audioEncoders[$audioOptions['audioEncoder']]; $audioOptions['fileSuffix'] = $thisEncoder['fileSuffix']; @@ -289,7 +310,7 @@ public function getAudioUrl($filePath, $audioOptions): string // Assemble the destination path and final ffmpeg command $destAudioPath = $destAudioPath.$destAudioFile; $ffmpegCmd .= ' -f ' - .$audioOptions['audioFormat'] + .$thisEncoder['fileFormat'] .' -y '.escapeshellarg($destAudioPath) .' 1> '.$progressFile.' 2>&1 & echo $!'; @@ -325,11 +346,12 @@ public function getAudioUrl($filePath, $audioOptions): string /** * Extract information from a video/audio file * - * @param $filePath + * @param $filePath + * @param bool $summary * * @return array */ - public function getFileInfo($filePath): array + public function getFileInfo($filePath, $summary = false): array { $result = null; @@ -346,6 +368,46 @@ public function getFileInfo($filePath): array Craft::info($ffprobeCmd, __METHOD__); $result = json_decode($shellOutput, true); Craft::info(print_r($result, true), __METHOD__); + + // Trim down the arrays to just a summary + if ($summary && !empty($result)) { + $summaryResult = []; + foreach ($result as $topLevelKey => $topLevelValue) { + switch ($topLevelKey) { + // Format info + case "format": + foreach ($this->infoSummary['format'] as $settingKey => $settingValue) { + if (!empty($topLevelValue[$settingKey])) { + $summaryResult[$settingValue] = $topLevelValue[$settingKey]; + } + } + break; + // Stream info + case "streams": + foreach ($topLevelValue as $stream) { + $infoSummaryType = $stream['codec_type']; + foreach ($this->infoSummary[$infoSummaryType] as $settingKey => $settingValue) { + if (!empty($stream[$settingKey])) { + $summaryResult[$settingValue] = $stream[$settingKey]; + } + } + + } + break; + // Unknown info + default: + break; + } + } + // Handle cases where the framerate is returned as XX/YY + if (!empty($summaryResult['videoFrameRate']) + && (strpos($summaryResult['videoFrameRate'], '/') !== false) + ) { + $parts = explode('/', $summaryResult['videoFrameRate']); + $summaryResult['videoFrameRate'] = floatval($parts[0]) / floatval($parts[1]); + } + $result = $summaryResult; + } } return $result; @@ -365,7 +427,7 @@ public function getVideoFilename($filePath, $videoOptions): string // Get the video encoder presets to use $videoEncoders = Craft::$app->config->get("videoEncoders", "transcoder"); - $thisEncoder = $videoEncoders[$videoOptions['videoFormat']]; + $thisEncoder = $videoEncoders[$videoOptions['videoEncoder']]; $videoOptions['fileSuffix'] = $thisEncoder['fileSuffix']; @@ -388,7 +450,7 @@ public function getAudioFilename($filePath, $audioOptions): string // Get the video encoder presets to use $audioEncoders = Craft::$app->config->get("audioEncoders", "transcoder"); - $thisEncoder = $audioEncoders[$audioOptions['audioFormat']]; + $thisEncoder = $audioEncoders[$audioOptions['audioEncoder']]; $audioOptions['fileSuffix'] = $thisEncoder['fileSuffix']; diff --git a/src/variables/TranscoderVariable.php b/src/variables/TranscoderVariable.php index 14148b5..8377614 100644 --- a/src/variables/TranscoderVariable.php +++ b/src/variables/TranscoderVariable.php @@ -79,9 +79,9 @@ public function getAudioUrl($filePath, $audioOptions): string * * @return array */ - public function getFileInfo($filePath): array + public function getFileInfo($filePath, $summary = false): array { - $result = Transcoder::$plugin->transcoder->getFileInfo($filePath); + $result = Transcoder::$plugin->transcoder->getFileInfo($filePath, $summary); return $result; }