From 07b4e57ad3a7856f2d4e8e3a33293e25a0f07cb5 Mon Sep 17 00:00:00 2001 From: Trevor Slocum Date: Wed, 14 Apr 2021 20:35:25 -0700 Subject: [PATCH] Use ffmpeg instead of medianinfo and ffmpegthumbnailer --- README.md | 5 ++- imgboard.php | 6 ++-- inc/functions.php | 74 ++++++++++++++++++++++++++++++++++++++++---- settings.default.php | 4 +-- 4 files changed, 76 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index b54efcc..3c99199 100644 --- a/README.md +++ b/README.md @@ -79,9 +79,12 @@ support in mind. - Moderate posts by visiting the management panel. - To allow video uploads: - Ensure your web host is running Linux. - - Install [mediainfo](https://mediaarea.net/en/MediaInfo) and [ffmpegthumbnailer](https://code.google.com/p/ffmpegthumbnailer/). On Ubuntu, run ``sudo apt-get install mediainfo ffmpegthumbnailer``. + - Install [ffmpeg](https://ffmpeg.org). On Ubuntu, run ``sudo apt-get install ffmpeg``. - Add desired video file types to ``$tinyib_uploads``. - To remove the play icon from .SWF and .WebM thumbnails, delete or rename **video_overlay.png** + - To use FFMPEG to create thumbnails: + - Install FFMPEG and ensure the ``ffmpeg`` and ``ffprobe`` commands are available. + - Set ``TINYIB_THUMBNAIL`` to ``ffmpeg``. - To use ImageMagick instead of GD when creating thumbnails: - Install ImageMagick and ensure that the ``convert`` command is available. - Set ``TINYIB_THUMBNAIL`` to ``imagemagick``. diff --git a/imgboard.php b/imgboard.php index 263af55..2541646 100644 --- a/imgboard.php +++ b/imgboard.php @@ -38,8 +38,7 @@ while (ob_get_level() > 0) { ob_end_flush(); } -function fancyDie($message) -{ +function fancyDie($message) { $back = 'Click here to go back'; if (function_exists('__')) { $back = __('Click here to go back'); @@ -55,8 +54,7 @@ require 'inc/defines.php'; global $tinyib_capcodes, $tinyib_embeds, $tinyib_hidefields, $tinyib_hidefieldsop; if (!defined('TINYIB_LOCALE') || TINYIB_LOCALE == '') { - function __($string) - { + function __($string) { return $string; } } else { diff --git a/inc/functions.php b/inc/functions.php index 787e196..4e958f5 100644 --- a/inc/functions.php +++ b/inc/functions.php @@ -469,6 +469,67 @@ function thumbnailDimensions($post) { return ($post['image_width'] > $max_width || $post['image_height'] > $max_height) ? array($max_width, $max_height) : array($post['image_width'], $post['image_height']); } +function videoDimensions($file_location) { + $discard = ''; + $exit_status = 1; + exec("ffprobe -version", $discard, $exit_status); + if ($exit_status != 0) { + fancyDie('FFMPEG is not installed, or the commands ffmpeg and ffprobe are not in the server\'s $PATH.
Install FFMPEG, or set TINYIB_THUMBNAIL to \'gd\' or \'imagemagick\'.'); + } + + $dimensions = ''; + $exit_status = 1; + exec("ffprobe -hide_banner -loglevel error -of csv=p=0 -show_entries stream=width,height $file_location", $dimensions, $exit_status); + if ($exit_status != 0) { + return array(0, 0); + } + if (is_array($dimensions)) { + $dimensions = $dimensions[0]; + } + $split = explode(',', $dimensions); + if (count($split) != 2) { + return array(0, 0); + } + return array(intval($split[0]), intval($split[1])); +} + +function videoDuration($file_location) { + $discard = ''; + $exit_status = 1; + exec("ffprobe -version", $discard, $exit_status); + if ($exit_status != 0) { + fancyDie('FFMPEG is not installed, or the commands ffmpeg and ffprobe are not in the server\'s $PATH.
Install FFMPEG, or set TINYIB_THUMBNAIL to \'gd\' or \'imagemagick\'.'); + } + + $duration = ''; + $exit_status = 1; + exec("ffprobe -hide_banner -loglevel error -of csv=p=0 -show_entries format=duration $file_location", $duration, $exit_status); + if ($exit_status != 0) { + return 0; + } + if (is_array($duration)) { + $duration = $duration[0]; + } + return floatval($duration); +} + +function ffmpegThumbnail($file_location, $thumb_location, $new_w, $new_h) { + $discard = ''; + $exit_status = 1; + exec("ffmpeg -version", $discard, $exit_status); + if ($exit_status != 0) { + fancyDie('FFMPEG is not installed, or the commands ffmpeg and ffprobe are not in the server\'s $PATH.
Install FFMPEG, or set TINYIB_THUMBNAIL to \'gd\' or \'imagemagick\'.'); + } + + $quarter = videoDuration($file_location) / 4; + + $exit_status = 1; + exec("ffmpeg -hide_banner -loglevel error -ss $quarter -i $file_location -frames:v 1 -vf \"thumbnail,scale='if(gt(iw,ih),$new_w,trunc(oh*a/2)*2)':'if(gt(iw,ih),trunc(ow/a/2)*2,$new_h)'\" $thumb_location", $discard, $exit_status); + if ($exit_status != 0) { + return false; + } +} + function createThumbnail($file_location, $thumb_location, $new_w, $new_h) { if (TINYIB_THUMBNAIL == 'gd') { $system = explode(".", $thumb_location); @@ -523,13 +584,15 @@ function createThumbnail($file_location, $thumb_location, $new_w, $new_h) { imagedestroy($dst_img); imagedestroy($src_img); + } else if (TINYIB_THUMBNAIL == 'ffmpeg') { + ffmpegThumbnail($file_location, $thumb_location, $new_w, $new_h); } else { // ImageMagick $discard = ''; $exit_status = 1; exec("convert -version", $discard, $exit_status); if ($exit_status != 0) { - fancyDie('ImageMagick is not installed, or the convert command is not in the server\'s $PATH.
Install ImageMagick, or set TINYIB_THUMBNAIL to \'gd\'.'); + fancyDie('ImageMagick is not installed, or the convert command is not in the server\'s $PATH.
Install ImageMagick, or set TINYIB_THUMBNAIL to \'gd\' or \'ffmpeg\'.'); } $exit_status = 1; @@ -575,7 +638,7 @@ function addVideoOverlay($thumb_location) { return; } - if (TINYIB_THUMBNAIL == 'gd') { + if (TINYIB_THUMBNAIL == 'gd' || TINYIB_THUMBNAIL == 'ffmpeg') { if (substr($thumb_location, -4) == ".jpg") { $thumbnail = imagecreatefromjpeg($thumb_location); } else { @@ -721,13 +784,12 @@ function attachFile($post, $filepath, $filename, $uploaded) { } if ($file_mime == 'audio/webm' || $file_mime == 'video/webm' || $file_mime == 'audio/mp4' || $file_mime == 'video/mp4') { - $post['image_width'] = max(0, intval(shell_exec('mediainfo --Inform="Video;%Width%" ' . $file_location))); - $post['image_height'] = max(0, intval(shell_exec('mediainfo --Inform="Video;%Height%" ' . $file_location))); + list($post['image_width'], $post['image_height']) = videoDimensions($file_location); if ($post['image_width'] > 0 && $post['image_height'] > 0) { list($thumb_maxwidth, $thumb_maxheight) = thumbnailDimensions($post); $post['thumb'] = $file_name . 's.jpg'; - shell_exec("ffmpegthumbnailer -s " . max($thumb_maxwidth, $thumb_maxheight) . " -i $file_location -o thumb/{$post['thumb']}"); + ffmpegThumbnail($file_location, 'thumb/' . $post['thumb'], $thumb_maxwidth, $thumb_maxheight); $thumb_info = getimagesize('thumb/' . $post['thumb']); $post['thumb_width'] = $thumb_info[0]; @@ -742,7 +804,7 @@ function attachFile($post, $filepath, $filename, $uploaded) { addVideoOverlay('thumb/' . $post['thumb']); } - $duration = intval(shell_exec('mediainfo --Inform="General;%Duration%" ' . $file_location)); + $duration = videoDuration($file_location); if ($duration > 0) { $mins = floor(round($duration / 1000) / 60); $secs = str_pad(floor(round($duration / 1000) % 60), 2, '0', STR_PAD_LEFT); diff --git a/settings.default.php b/settings.default.php index 4098ade..3a4ede1 100644 --- a/settings.default.php +++ b/settings.default.php @@ -76,7 +76,7 @@ $tinyib_uploads = array('image/jpeg' => array('jpg'), // 'audio/mp4' => array('mp4'); // 'audio/wav' => array('wav'); // 'audio/webm' => array('webm'); -// 'video/mp4' => array('mp4'); // Video uploads require mediainfo and ffmpegthumbnailer (see README for instructions) +// 'video/mp4' => array('mp4'); // Video uploads require ffmpeg (see README for instructions) // 'video/webm' => array('webm'); // oEmbed APIs @@ -88,7 +88,7 @@ $tinyib_embeds = array('SoundCloud' => 'https://soundcloud.com/oembed?format=jso // File control define('TINYIB_MAXKB', 2048); // Maximum file size in kilobytes [0 to disable] define('TINYIB_MAXKBDESC', '2 MB'); // Human-readable representation of the maximum file size -define('TINYIB_THUMBNAIL', 'gd'); // Thumbnail method to use: gd / imagemagick (see README for instructions) +define('TINYIB_THUMBNAIL', 'gd'); // Thumbnail method to use: gd / ffmpeg / imagemagick (see README for instructions) define('TINYIB_UPLOADVIAURL', false); // Allow files to be uploaded via URL define('TINYIB_NOFILEOK', false); // Allow the creation of new threads without uploading a file