首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 綜合知識

PHP FFmpeg 擷取視頻指定幀並修正手機拍攝旋轉問題

     編輯:PHP 綜合知識

核心需求

從視頻檔案擷取指定幀作為縮圖/封面。關鍵難點:**手機拍攝視頻常帶旋轉中繼資料 (rotate metadata)**,直接擷取畫面會呈現側躺/倒轉狀態,需讀取旋轉角度並修正。

環境需求

  • PHP ffmpeg 擴展 (php-ffmpeg / php-ffmpeg-php) 或直接呼叫 CLI
  • 系統安裝 ffmpeg、ffprobe (通常同套件)

方案一:PHP-FFmpeg 擴展 (物件導向,推薦)

use FFMpeg\FFMpeg;
use FFMpeg\Coordinate\TimeCode;

$ffmpeg = FFMpeg::create();
$video = $ffmpeg->open('input.mp4');

// 1. 讀取旋轉中繼資料
$rotation = 0;
$streams = $video->getStreams();
foreach ($streams as $stream) {
    if ($stream->get('codec_type') === 'video') {
        $rotation = (int)($stream->get('tags')['rotate'] ?? 0);
        break;
    }
}

// 2. 擷取第 1 秒畫面
$frame = $video->frame(TimeCode::fromSeconds(1));
$image = $frame->toGDImage();

// 3. 修正旋轉 (GD imagerotate 角度為逆時針)
if ($rotation !== 0) {
    // ffprobe 旋轉角度為順時針,GD 為逆時針
    $image = imagerotate($image, 360 - $rotation, 0);
}

// 4. 輸出
imagejpeg($image, 'thumb.jpg', 90);
imagedestroy($image);

方案二:純 CLI 呼叫 (無擴展依賴,效能最佳)

1. 讀取旋轉角度

function get_video_rotation($videoPath) {
    $cmd = "ffprobe -v error -select_streams v:0 -show_entries stream_tags=rotate -of default=nw=1:nk=1 " . escapeshellarg($videoPath);
    $output = shell_exec($cmd);
    return (int)trim($output);
}

2. 擷取並修正 (單指令完成,最高效)

function extract_thumb($videoPath, $outputPath, $time = '00:00:01', $rotation = 0) {
    $filter = '';
    switch ($rotation) {
        case 90:  $filter = 'transpose=1'; break;   // 逆時針 90
        case 180: $filter = 'transpose=2,transpose=2'; break; // 180
        case 270: $filter = 'transpose=2'; break;   // 逆時針 270 = 順時針 90
    }
    
    $cmd = "ffmpeg -y -ss " . escapeshellarg($time) . " -i " . escapeshellarg($videoPath);
    if ($filter) {
        $cmd .= " -vf " . escapeshellarg($filter);
    }
    $cmd .= " -vframes 1 -q:v 2 " . escapeshellarg($outputPath) . " 2>&1";
    
    exec($cmd, $output, $returnVar);
    return $returnVar === 0;
}

// 使用
$rotation = get_video_rotation('video.mp4');
extract_thumb('video.mp4', 'thumb.jpg', '00:00:01', $rotation);

3. 一步到位:擷取+修正+清除旋轉標記 (重新編碼輸出正向視頻)

function fix_video_rotation($input, $output) {
    // transpose=2 為 180 旋轉,metadata:s:v:0 rotate=0 清除標記
    $cmd = "ffmpeg -y -i " . escapeshellarg($input) . " -vf transpose=2 -metadata:s:v:0 rotate=0 -c:a copy " . escapeshellarg($output) . " 2>&1";
    exec($cmd, $out, $ret);
    return $ret === 0;
}

旋轉對照表 (ffprobe rotate → transpose)

rotate 標記實際畫面transpose 參數說明
0正常無無需處理
90順時針 90°transpose=1逆時針 90° 修正
180倒轉 180°transpose=2,transpose=2兩次 90°
270逆時針 90° (順時針 270°)transpose=2逆時針 270°

常見問題與解決

問題原因解決
imagerotate 黑邊/背景色第四參數背景色預設 0 (黑)用 imagecolorallocatealpha($img, 255,255,255, 127) 透明背景
大視頻擷取慢-ss 在 -i 後面會解碼到該時間點-ss 放在 -i 前面 (快速定位,非關鍵幀) 或用 -ss 00:00:01 -i input -vframes 1
關鍵幀不準確快速定位落在非關鍵幀接受近似幀、或用 -ss 在 -i 後 (慢但精確)
PHP 執行超時ffmpeg 轉碼耗時set_time_limit(0)、或異步佇列處理
權限被拒PHP 執行身份無 ffmpeg 執行權確保 www-data 可執行 /usr/bin/ffmpeg、輸出目錄可寫

效能優化建議

  • 批量處理:將擷取任務推入 Redis/RabbitMQ,Worker 進程批次執行 ffmpeg
  • 快取縮圖:同一視頻多次請求時,檢查縮圖是否已存在
  • 預生成:上傳完成即觸發擷取,而非用戶訪問時即時生成
  • 硬體加速:-hwaccel cuda -c:v h264_nvenc (需 NVIDIA GPU + NVENC)

總結

  1. **必須讀取 rotate 中繼資料**,手機視頻 90% 以上有旋轉標記
  2. **推薦 CLI 方案**:ffprobe 讀取角度 → ffmpeg -vf transpose=X 一步到位修正,效能最佳、無 GD 記憶體限制
  3. **輸出視頻時同步清除 rotate 標記** (-metadata:s:v:0 rotate=0),避免播放器重複旋轉
  4. 生產環境採用**異步佇列 + 預生成**架構,避免 HTTP 請求阻塞

掌握此流程,即可正確處理各種手機上傳視頻的縮圖生成與播放相容性問題。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved