From a14cf857639a0b095dbb9c275ee44ba8e248dee4 Mon Sep 17 00:00:00 2001 From: Kijin Sung Date: Wed, 24 May 2023 13:16:11 +0900 Subject: [PATCH] Implement video auto resizing and reencoding --- modules/file/file.controller.php | 111 +++++++++++++++++++++++++++++-- modules/file/lang/en.php | 3 + modules/file/lang/ko.php | 3 + 3 files changed, 111 insertions(+), 6 deletions(-) diff --git a/modules/file/file.controller.php b/modules/file/file.controller.php index a60f0f283..45e29a056 100644 --- a/modules/file/file.controller.php +++ b/modules/file/file.controller.php @@ -838,7 +838,7 @@ class FileController extends File } // video - if(in_array($file_info['extension'], ['mp4', 'webm', 'ogv'])) + if(in_array($file_info['extension'], ['mp4', 'webm', 'ogv', 'avi', 'mkv', 'mov', 'mpg', 'mpe', 'mpeg', 'wmv', 'm4v', 'flv'])) { $file_info = $this->adjustUploadedVideo($file_info, $config); } @@ -1221,16 +1221,115 @@ class FileController extends File return $file_info; } - // Set video size + // Get video size and duration $file_info['width'] = (int)$stream_info['video']['width']; $file_info['height'] = (int)$stream_info['video']['height']; $file_info['duration'] = (int)$stream_info['video']['duration']; + $adjusted = [ + 'width' => $file_info['width'], + 'height' => $file_info['height'], + 'type' => $file_info['extension'], + 'force' => false, + ]; - // MP4 - if ($file_info['extension'] === 'mp4') + // Check video size + if (!empty($config->max_video_size_action) && ($config->max_video_width || $config->max_video_height) && (!$this->user->isAdmin() || $config->max_video_size_admin === 'Y')) { - // Treat as GIF - if ($config->video_mp4_gif_time && $file_info['duration'] <= $config->video_mp4_gif_time && empty($stream_info['audio'])) + $exceeded = 0; + $resize_width = $adjusted['width']; + $resize_height = $adjusted['height']; + if ($config->max_video_width > 0 && $adjusted['width'] > $config->max_video_width) + { + $resize_width = $config->max_video_width; + $resize_height = $adjusted['height'] * ($config->max_video_width / $adjusted['width']); + $exceeded++; + } + if ($config->max_video_height > 0 && $resize_height > $config->max_video_height) + { + $resize_width = $resize_width * ($config->max_video_height / $resize_height); + $resize_height = $config->max_video_height; + $exceeded++; + } + + if ($exceeded) + { + // Block upload + if ($config->max_video_size_action === 'block') + { + if ($config->max_video_width && $config->max_video_height) + { + $message = sprintf(lang('msg_exceeds_max_video_size'), $config->max_video_width, $config->max_video_height); + } + elseif ($config->max_video_width) + { + $message = sprintf(lang('msg_exceeds_max_video_width'), $config->max_video_width); + } + else + { + $message = sprintf(lang('msg_exceeds_max_video_height'), $config->max_video_height); + } + throw new Rhymix\Framework\Exception($message); + } + + $adjusted['width'] = (int)$resize_width; + $adjusted['height'] = (int)$resize_height; + $adjusted['type'] = 'mp4'; + } + } + + // Check if this video should be force-converted to MP4 + if (isset($config->video_autoconv['any2mp4']) && $config->video_autoconv['any2mp4'] && $file_info['extension'] !== 'mp4') + { + $adjusted['type'] = 'mp4'; + } + + // Check if this video should be reencoded anyway + if (isset($config->video_always_reencode) && $config->video_always_reencode) + { + $adjusted['force'] = true; + $adjusted['type'] = 'mp4'; + } + + // Convert + if ($adjusted['width'] !== $file_info['width'] || + $adjusted['height'] !== $file_info['height'] || + $adjusted['type'] !== $file_info['extension'] || + $adjusted['force'] + ) + { + $output_name = $file_info['tmp_name'] . '.converted.mp4'; + + // Width and height of video must be even + $adjusted['width'] -= $adjusted['width'] % 2; + $adjusted['height'] -= $adjusted['height'] % 2; + + // Convert using ffmpeg + $command = \RX_WINDOWS ? escapeshellarg($config->ffmpeg_command) : $config->ffmpeg_command; + $command .= ' -nostdin -i ' . escapeshellarg($file_info['tmp_name']); + $command .= ' -movflags +faststart -pix_fmt yuv420p -c:v libx264 -crf 23'; + $command .= empty($stream_info['audio']) ? ' -an' : ' -acodec aac'; + $command .= sprintf(' -vf "scale=%d:%d"', $adjusted['width'], $adjusted['height']); + $command .= ' ' . escapeshellarg($output_name); + @exec($command, $output, $return_var); + $result = $return_var === 0 ? true : false; + + // Update file info + if ($result) + { + $file_info['tmp_name'] = $output_name; + $file_info['size'] = filesize($output_name); + $file_info['type'] = Rhymix\Framework\MIME::getContentType($output_name); + $file_info['extension'] = $adjusted['type']; + $file_info['width'] = $adjusted['width']; + $file_info['height'] = $adjusted['height']; + $file_info['converted'] = true; + } + } + + // Set original type to GIF if this video is short and has no audio stream. + if (isset($config->video_mp4_gif_time) && $config->video_mp4_gif_time) + { + if ($file_info['extension'] === 'mp4' && $file_info['duration'] <= $config->video_mp4_gif_time && empty($stream_info['audio'])) { $file_info['original_type'] = 'image/gif'; } diff --git a/modules/file/lang/en.php b/modules/file/lang/en.php index e78966db5..fab3c0640 100644 --- a/modules/file/lang/en.php +++ b/modules/file/lang/en.php @@ -54,6 +54,9 @@ $lang->msg_exceeds_limit_size = 'This file exceeds the attachment limit.'; $lang->msg_exceeds_max_image_size = 'This image is too large. Images must be no larger than %dx%dpx.'; $lang->msg_exceeds_max_image_width = 'This image is too large. The maximum permitted width is %dpx.'; $lang->msg_exceeds_max_image_height = 'This image is too large. The maximum permitted height is %dpx.'; +$lang->msg_exceeds_max_video_size = 'This video is too large. Videos must be no larger than %dx%dpx.'; +$lang->msg_exceeds_max_video_width = 'This video is too large. The maximum permitted width is %dpx.'; +$lang->msg_exceeds_max_video_height = 'This video is too large. The maximum permitted height is %dpx.'; $lang->msg_file_not_found = 'Could not find requested file.'; $lang->msg_file_key_expired = 'This download link is expired. Please initiate the download again.'; $lang->file_search_target_list['filename'] = 'File Name'; diff --git a/modules/file/lang/ko.php b/modules/file/lang/ko.php index 5cc6f3e79..0d2b0f96c 100644 --- a/modules/file/lang/ko.php +++ b/modules/file/lang/ko.php @@ -55,6 +55,9 @@ $lang->msg_not_allowed_filetype = '업로드할 수 없는 파일 형식입니 $lang->msg_exceeds_max_image_size = '이미지가 너무 큽니다. %dx%dpx 이하의 이미지만 허용됩니다.'; $lang->msg_exceeds_max_image_width = '이미지가 너무 큽니다. 폭 %dpx 이하의 이미지만 허용됩니다.'; $lang->msg_exceeds_max_image_height = '이미지가 너무 큽니다. 높이 %dpx 이하의 이미지만 허용됩니다.'; +$lang->msg_exceeds_max_video_size = '동영상이 너무 큽니다. %dx%dpx 이하의 동영상만 허용됩니다.'; +$lang->msg_exceeds_max_video_width = '동영상이 너무 큽니다. 폭 %dpx 이하의 동영상만 허용됩니다.'; +$lang->msg_exceeds_max_video_height = '동영상이 너무 큽니다. 높이 %dpx 이하의 동영상만 허용됩니다.'; $lang->msg_file_not_found = '요청한 파일을 찾을 수 없습니다.'; $lang->msg_file_key_expired = '다운로드 링크의 유효기간이 지났습니다. 다시 다운로드하여 주시기 바랍니다.'; $lang->file_search_target_list['filename'] = '파일 이름';