Просмотр исходного кода

优化提高视频分辨率的公共方法

lh 1 день назад
Родитель
Сommit
938a2eeb0f
1 измененных файлов с 88 добавлено и 6 удалено
  1. 88 6
      app/Libs/Helpers.php

+ 88 - 6
app/Libs/Helpers.php

@@ -4484,9 +4484,90 @@ function upgrade480pTo720p($videoUrl, $prefix = 'videos')
             'size_mb' => round($inputFileSize / 1024 / 1024, 2) . 'MB'
         ]);
 
-        // 使用FFmpeg将视频升级到720p,使用高质量的Lanczos算法和锐化滤镜
+        // 获取原视频的宽高信息
+        $ffprobePath = env('FFPROBE_PATH', 'ffprobe');
+        $probeCmd = "$ffprobePath -v error -select_streams v:0 -show_entries stream=width,height -of csv=s=x:p=0 \"$inputFile\"";
+        $dimensionOutput = trim(shell_exec($probeCmd));
+        
+        if (!$dimensionOutput || strpos($dimensionOutput, 'x') === false) {
+            dLog('video_upgrade')->error('无法获取视频分辨率', ['file' => $inputFile]);
+            @unlink($inputFile);
+            return $videoUrl;
+        }
+        
+        list($origWidth, $origHeight) = explode('x', $dimensionOutput);
+        $origWidth = (int)$origWidth;
+        $origHeight = (int)$origHeight;
+        $origAspectRatio = $origWidth / $origHeight;
+        
+        dLog('video_upgrade')->info('原视频分辨率', [
+            'width' => $origWidth,
+            'height' => $origHeight,
+            'aspect_ratio' => round($origAspectRatio, 4)
+        ]);
+        
+        // 判断视频是横屏还是竖屏
+        // 横屏(16:9): 宽高比 > 1, 目标分辨率 1280*720
+        // 竖屏(9:16): 宽高比 < 1, 目标分辨率 720*1280
+        
+        if ($origAspectRatio > 1) {
+            // 横屏视频 - 目标分辨率1280*720
+            $targetAspectRatio = 16 / 9; // 1280/720 ≈ 1.7778
+            
+            if (abs($origAspectRatio - $targetAspectRatio) < 0.01) {
+                // 原视频宽高比接近16:9,直接缩放到1280*720
+                $targetWidth = 1280;
+                $targetHeight = 720;
+            } else {
+                // 根据原视频宽高比,保持比例缩放
+                // 以较长边(高度720)为基准
+                $targetHeight = 720;
+                $targetWidth = (int)round($targetHeight * $origAspectRatio);
+                // 确保是偶数
+                if ($targetWidth % 2 != 0) $targetWidth += 1;
+                
+                // 如果计算出的宽度超过1280,则以宽度为基准重新计算
+                if ($targetWidth > 1280) {
+                    $targetWidth = 1280;
+                    $targetHeight = (int)round($targetWidth / $origAspectRatio);
+                    if ($targetHeight % 2 != 0) $targetHeight += 1;
+                }
+            }
+        } else {
+            // 竖屏视频 - 目标分辨率720*1280
+            $targetAspectRatio = 9 / 16; // 720/1280 = 0.5625
+            
+            if (abs($origAspectRatio - $targetAspectRatio) < 0.01) {
+                // 原视频宽高比接近9:16,直接缩放到720*1280
+                $targetWidth = 720;
+                $targetHeight = 1280;
+            } else {
+                // 根据原视频宽高比,保持比例缩放
+                // 以较长边(高度1280)为基准
+                $targetHeight = 1280;
+                $targetWidth = (int)round($targetHeight * $origAspectRatio);
+                // 确保是偶数
+                if ($targetWidth % 2 != 0) $targetWidth += 1;
+                
+                // 如果计算出的宽度超过720,则以宽度为基准重新计算
+                if ($targetWidth > 720) {
+                    $targetWidth = 720;
+                    $targetHeight = (int)round($targetWidth / $origAspectRatio);
+                    if ($targetHeight % 2 != 0) $targetHeight += 1;
+                }
+            }
+        }
+        
+        dLog('video_upgrade')->info('目标分辨率', [
+            'width' => $targetWidth,
+            'height' => $targetHeight,
+            'aspect_ratio' => round($targetWidth / $targetHeight, 4),
+            'orientation' => $origAspectRatio > 1 ? 'landscape' : 'portrait'
+        ]);
+
+        // 使用FFmpeg将视频升级到目标分辨率,使用高质量的Lanczos算法和锐化滤镜
         // 滤镜说明:
-        // 1. scale=-2:720:flags=lanczos: 使用Lanczos算法缩放,保持宽高比,高度720,宽度自动计算(-2确保是偶数)
+        // 1. scale={width}:{height}:flags=lanczos: 使用Lanczos算法缩放到精确分辨率
         // 2. unsharp=5:5:1.0:5:5:0.5: 锐化滤镜,增强细节
         //    - 5:5:1.0 表示亮度锐化(luma_msize_x:luma_msize_y:luma_amount)
         //    - 5:5:0.5 表示色度锐化(chroma_msize_x:chroma_msize_y:chroma_amount)
@@ -4494,8 +4575,8 @@ function upgrade480pTo720p($videoUrl, $prefix = 'videos')
         //    - 参数分别为亮度空间/时间和色度空间/时间
         // 编码参数:
         // -c:v libx264: 使用H.264编码器
-        // -preset veryslow: 使用最慢的编码速度以获得最佳画质(适合对画质要求高的场景)
-        // -crf 16: 恒定质量模式,16表示极高质量(0-51,数值越小画质越好,18是高质量,16是极高质量
+        // -preset veryslow: 使用最慢的编码速度以获得最佳画质
+        // -crf 16: 恒定质量模式,16表示极高质量(0-51,数值越小画质越好)
         // -tune film: 针对电影内容优化(适合AI生成的动画视频)
         // -profile:v high: 使用H.264 High Profile,支持更高级的压缩特性
         // -level 4.1: H.264 level 4.1,支持更高的码率和分辨率
@@ -4503,7 +4584,7 @@ function upgrade480pTo720p($videoUrl, $prefix = 'videos')
         // -c:a copy: 音频直接复制,不重新编码
         // -movflags +faststart: 优化网络播放
         $ffmpegPath = env('FFMPEG_PATH', 'ffmpeg');
-        $ffmpegCmd = "$ffmpegPath -i \"$inputFile\" -vf \"scale=-2:720:flags=lanczos,unsharp=5:5:1.0:5:5:0.5,hqdn3d=1.5:1.5:6:6\" -c:v libx264 -preset veryslow -crf 16 -tune film -profile:v high -level 4.1 -pix_fmt yuv420p -c:a copy -movflags +faststart -y \"$outputFile\" 2>&1";
+        $ffmpegCmd = "$ffmpegPath -i \"$inputFile\" -vf \"scale={$targetWidth}:{$targetHeight}:flags=lanczos,unsharp=5:5:1.0:5:5:0.5,hqdn3d=1.5:1.5:6:6\" -c:v libx264 -preset veryslow -crf 16 -tune film -profile:v high -level 4.1 -pix_fmt yuv420p -c:a copy -movflags +faststart -y \"$outputFile\" 2>&1";
         
         dLog('video_upgrade')->info('开始升级视频到720p', ['command' => $ffmpegCmd]);
         $output = shell_exec($ffmpegCmd);
@@ -4525,7 +4606,8 @@ function upgrade480pTo720p($videoUrl, $prefix = 'videos')
         dLog('video_upgrade')->info('视频升级成功', [
             'input_size' => round($inputFileSize / 1024 / 1024, 2) . 'MB',
             'output_size' => round($outputFileSize / 1024 / 1024, 2) . 'MB',
-            'size_ratio' => $sizeRatio
+            'size_ratio' => $sizeRatio,
+            'target_resolution' => "{$targetWidth}x{$targetHeight}"
         ]);
 
         // 上传到TOS - 使用普通的文件名,不暴露是升级后的视频