如何使用MediaToolkit无需读写磁盘从内存视频中提取缩略图
内存视频缩略图提取方案(无磁盘读写)
核心思路是利用FFmpeg的标准输入输出能力,直接在内存中完成视频输入、帧提取、缩略图输出全流程,无需任何磁盘IO操作。
实现步骤
你无需额外引入MediaToolkit等封装库,仅需要准备FFmpeg可执行文件(无需安装,仅需放在程序可访问路径下),通过进程调用实现全内存操作:
- 优先直接使用
IFormFile自带的Stream,不需要额外转成byte[],可以节省内存开销;如果已有byte[]格式的视频数据,包装成MemoryStream即可使用。 - 启动FFmpeg进程,配置为从标准输入读取视频数据,将提取到的缩略图输出到标准输出。
- 将内存中的视频流写入FFmpeg的标准输入,再从FFmpeg的标准输出读取缩略图二进制数据。
代码示例
using System.Diagnostics; using System.IO; /// <summary> /// 从内存视频流提取缩略图 /// </summary> /// <param name="videoStream">内存视频流</param> /// <param name="frameOffsetSeconds">取第N秒的帧作为缩略图</param> /// <param name="thumbnailWidth">缩略图宽度,高度自动适配宽高比</param> /// <returns>JPEG格式的缩略图二进制数据</returns> public async Task<byte[]> ExtractThumbnailAsync(Stream videoStream, int frameOffsetSeconds = 1, int thumbnailWidth = 320) { // 替换为你的FFmpeg可执行文件路径 var ffmpegExecutablePath = Path.Combine(AppContext.BaseDirectory, "ffmpeg.exe"); var processStartInfo = new ProcessStartInfo { FileName = ffmpegExecutablePath, // 命令参数说明: // -ss {x} 跳转到第x秒,放在-i前可实现快速 seek 无需解码全视频 // -i - 从标准输入读取视频数据 // -vframes 1 仅提取1帧 // -vf scale={w}:-1 保持宽高比缩放缩略图 // -f image2pipe 以图片格式输出到管道 // -q:v 2 最高JPEG质量 // - 输出内容到标准输出 Arguments = $"-ss {frameOffsetSeconds} -i - -vframes 1 -vf \"scale={thumbnailWidth}:-1\" -f image2pipe -q:v 2 -", RedirectStandardInput = true, RedirectStandardOutput = true, RedirectStandardError = true, UseShellExecute = false, CreateNoWindow = true }; using var ffmpegProcess = Process.Start(processStartInfo); if (ffmpegProcess == null) { throw new InvalidOperationException("FFmpeg进程启动失败"); } // 将内存视频流写入FFmpeg标准输入 await videoStream.CopyToAsync(ffmpegProcess.StandardInput.BaseStream); ffmpegProcess.StandardInput.Close(); // 从标准输出读取生成的缩略图 using var thumbnailStream = new MemoryStream(); await ffmpegProcess.StandardOutput.BaseStream.CopyToAsync(thumbnailStream); await ffmpegProcess.WaitForExitAsync(); if (ffmpegProcess.ExitCode != 0) { // 可通过 ffmpegProcess.StandardError.ReadToEnd() 查看错误详情 throw new InvalidOperationException("缩略图提取失败,请检查视频格式是否合法"); } return thumbnailStream.ToArray(); }
调用方法
- 输入为
IFormFile:直接传入formFile.OpenReadStream()即可调用方法 - 输入为
byte[]:传入new MemoryStream(videoByteArray)即可调用方法
注意事项
- 如需输出PNG格式缩略图,将参数中的
-f image2pipe替换为-f pngpipe即可 - 可根据业务需求调整
frameOffsetSeconds参数,避免取到黑帧 - 该方案支持所有FFmpeg兼容的视频格式,兼容性优于大部分第三方封装库
内容的提问来源于stack exchange,提问作者Joe Morgan
相关产品推荐
相关产品推荐

