下面這張圖是我這次要做的事。

thumbnail

把影片每一秒畫面轉成圖檔,可以玩出好玩應用。例如,傳奇作品如甄嬛傳、少林足球、九品芝麻官,幕幕皆經典,幀幀能當梗,抓畫面可以做梗圖,像是甄嬛梗圖機器人背後就有 11,500 張照片作為圖庫。

thumbnail

另外,將影片轉成圖片後,可寫程式做靜態影像處理。甚至反過來,處理完再將圖片還原成影片,發展更多花式應用。

至於要將影片特定時點畫面另存圖片,我第一個想到的是強大的萬用開源工具 - FFmpeg,但如要批次處理加入客製邏輯,還是寫程式比較方便。

我查到一個好用的 .NET 程式庫 - Xabe.FFmpeg,基本上只是個 FFmpeg 的 Wrapper,方便以 .NET 函式 API 取代執行檔參數操作 FFmpeg。呼叫 API 傳入參數會轉為 FFmpeg 參數啟動 ffmpeg 執行檔,以外部程序執行。Xabe.FFmpeg 程式庫開源,非商業使用免費。

Xabe.FFmpeg 的 API 挺直覺好寫,本次要用的擷圖功能,核心是使用 ExtractEveryNthFrame() 函式,它能每隔 N 個 Frame 儲存一張 .png,若影片 FrameRate 為 24,每隔 24 幀存一次便相當於每秒存一張。Start() 後必須等外部程序的 ffmpeg 跑完,中間如想知道進度可實作 OnProgress 事件,顯示目前播放時間、總長度及播放比例。

這段將每秒畫面另存 .png 的程式碼很短也很簡單,應不需要大多解釋。

using System.Runtime.CompilerServices;
using Xabe.FFmpeg;

var mediaInfo = await FFmpeg.GetMediaInfo("English.webm");

/* 將聲音轉 MP3
var audioStream = mediaInfo.AudioStreams.FirstOrDefault();
var result = await FFmpeg.Conversions.New()
    .AddStream(audioStream)
    .SetOutput("extracted_audio.mp3")
    .Start();
*/

const string outputFolder = "snapshots";
if (Directory.Exists(outputFolder)) Directory.Delete(outputFolder, true);
Directory.CreateDirectory(outputFolder);
var videoStream = mediaInfo.VideoStreams.FirstOrDefault()?.SetCodec(VideoCodec.png)!;
// 取得幀率
int framesPerSecond = (int)Math.Round(videoStream.Framerate);
Console.WriteLine($"Frames per second: {framesPerSecond}");
// 每隔每秒幀數存一張影像,等於一秒一張
var conversion = FFmpeg.Conversions.New()
    .AddStream(videoStream)
    .ExtractEveryNthFrame(framesPerSecond, (number) => Path.Combine(outputFolder, $"F_{number:000000}.png"));
// 取得進度資訊
conversion.OnProgress += (sender, args) =>
{
    Console.Write($"\r[{args.Duration}/{args.TotalLength}] {args.Percent}%       ");
};
await conversion.Start();
Console.WriteLine("\n匯出完成");
// 更名檔案將秒數轉為時分秒
foreach (var file in Directory.GetFiles(outputFolder, "F_*.png"))
{
    var secs = int.Parse(Path.GetFileNameWithoutExtension(file).Split('_').Last());
    TimeSpan time = TimeSpan.FromSeconds(secs);
    string newFilePath = Path.Combine(outputFolder, $"{time.Hours:D2}_{time.Minutes:D2}_{time.Seconds:D2}#{secs:0000}.png");
    File.Move(file, newFilePath);
}

另外,FFmpeg 處理過程是多工平行運算,我的 i5 CPU 難得一見火力全開。

搞了很久的智慧插座監測這回也派上用場,由圖表可知我的迷你工作機全速運轉的耗電量是 100W。

就醬,我們就能將影片轉成圖片,搞一些有趣的應用囉~

Demonstrates how to extract video frames as images using Xabe.FFmpeg for meme creation and image processing in .NET.


Comments

Be the first to post a comment

Post a comment