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

C# 使用 ffmpeg 從影片擷取縮圖完整實作

     編輯:關於C語言

架構概覽

  • 核心工具:ffmpeg.exe (需獨立下載,放置伺服器固定路徑)
  • 呼叫方式:System.Diagnostics.Process 啟動外部程序
  • 設定參數:儲存於 Web.config 的 <appSettings>
  • 適用格式:支援 ffmpeg 可解碼的所有格式 (MP4、FLV、AVI、MKV 等)

Web.config 設定

<appSettings>
  <!-- ffmpeg 執行檔完整路徑 -->
  <add key="ffmpegPath" value="E:\ffmpeg\ffmpeg.exe" />
  <!-- 縮圖解析度 寬x高 -->
  <add key="thumbnailSize" value="240x180" />
</appSettings>

核心擷取方法

using System;
using System.Configuration;
using System.Diagnostics;
using System.IO;
using System.Web;

public class VideoThumbnailer {
    private readonly string _ffmpegPath;
    private readonly string _size;

    public VideoThumbnailer() {
        _ffmpegPath = ConfigurationManager.AppSettings["ffmpegPath"];
        _size = ConfigurationManager.AppSettings["thumbnailSize"]; // 如 "240x180"
    }

    /// 
    /// 從影片擷取第 1 幀縮圖
    /// 
    /// 虛擬路徑,如 ~/Videos/abc.mp4
    /// 縮圖虛擬路徑;失敗回傳空字串
    public string CaptureThumbnail(string videoVirtualPath) {
        if (string.IsNullOrEmpty(_ffmpegPath) || !File.Exists(_ffmpegPath)) {
            LogError("ffmpeg.exe 不存在或未設定");
            return "";
        }

        string videoPhysicalPath = HttpContext.Current.Server.MapPath(videoVirtualPath);
        if (!File.Exists(videoPhysicalPath)) {
            LogError($"影片檔案不存在: {videoPhysicalPath}");
            return "";
        }

        // 輸出圖片路徑:同目錄,同檔名,副檔名改 .jpg
        string imagePhysicalPath = Path.ChangeExtension(videoPhysicalPath, ".jpg");
        string imageVirtualPath = Path.ChangeExtension(videoVirtualPath, ".jpg");

        // 組裝 ffmpeg 參數
        // -i 輸入檔 -y 覆蓋 -f image2 輸出格式 -t 0.001 只取 1ms -s 解析度
        string args = $"-i \"{videoPhysicalPath}\" -y -f image2 -t 0.001 -s {_size} \"{imagePhysicalPath}\"";

        var startInfo = new ProcessStartInfo {
            FileName = _ffmpegPath,
            Arguments = args,
            WindowStyle = ProcessWindowStyle.Hidden,
            CreateNoWindow = true,
            UseShellExecute = false,
            RedirectStandardError = true,  // 捕捉錯誤輸出
            RedirectStandardOutput = true
        };

        try {
            using (Process proc = Process.Start(startInfo)) {
                // 等待完成,最長 30 秒
                if (!proc.WaitForExit(30000)) {
                    proc.Kill();
                    LogError("ffmpeg 執行逾時");
                    return "";
                }
                string stderr = proc.StandardError.ReadToEnd();
                if (proc.ExitCode != 0) {
                    LogError($"ffmpeg 失敗 (ExitCode={proc.ExitCode}): {stderr}");
                    return "";
                }
            }
        } catch (Exception ex) {
            LogError($"啟動 ffmpeg 例外: {ex.Message}");
            return "";
        }

        // 檔案系統寫入可能延遲,輪詢確認
        for (int i = 0; i < 10; i++) { // 最多等 5 秒
            if (File.Exists(imagePhysicalPath) && new FileInfo(imagePhysicalPath).Length > 0) {
                return imageVirtualPath;
            }
            System.Threading.Thread.Sleep(500);
        }

        LogError("縮圖檔案未在預期時間內生成");
        return "";
    }

    private void LogError(string msg) {
        // 實務請接入 log4net / Serilog / ILogger
        System.Diagnostics.Debug.WriteLine($"[VideoThumbnailer] {msg}");
    }
}

ASP.NET 網頁呼叫範例

protected void btnUpload_Click(object sender, EventArgs e) {
    if (fuVideo.HasFile) {
        string savePath = "~/Videos/" + Guid.NewGuid() + Path.GetExtension(fuVideo.FileName);
        string physical = Server.MapPath(savePath);
        fuVideo.SaveAs(physical);

        var thumbner = new VideoThumbnailer();
        string thumbUrl = thumbner.CaptureThumbnail(savePath);

        if (!string.IsNullOrEmpty(thumbUrl)) {
            imgThumb.ImageUrl = thumbUrl;
            lblMsg.Text = "上傳並擷取縮圖成功!";
        } else {
            lblMsg.Text = "影片上傳成功,但縮圖擷取失敗。";
        }
    }
}

常見問題與解決

現象原因與對策
縮圖生成失敗1. ffmpeg 版本不支援該編碼 (如 H.265 需較新版)
2. 影片加密/損壞
3. 路徑含中文/空格未加雙引號
權限錯誤IIS_IUSRS 需有影片資料夾寫入權限、ffmpeg.exe 讀取/執行權限
執行緒阻塞改用非同步 Task.Run 或掛載訊息佇列 (Hangfire/Quartz) 背景處理
無法取得錯誤訊息已在範例中加入 RedirectStandardError 讀取 stderr
FLV 線上錄製影片通常相容性最好,幾乎不會失敗

替代方案:純 .NET 實作 (無需 ffmpeg)

若不想部署外部 exe,可考慮:

  • MediaToolkit (NuGet) - 封裝 ffmpeg 的 .NET 包裝器
  • FFmpeg.AutoGen - P/Invoke 直接呼叫 ffmpeg DLL
  • SkiaSharp / ImageSharp - 僅支援部分容器格式,需自行解碼影格
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved