如何让 FFmpeg 支持异步并行转码、截图等等操作?
直接贴代码了:
ffmpegTest02.cs
public partial class ffmpegTest02 : FormBase
{
private static readonly string TaskffmpegNETExeFullPath = ConfigurationManager.AppSettings["TaskffmpegNETExeFullPath"]; string _videoFileFullPath = @"D:\Workspace\TestVideo.mp4"; string _othereVideoFileFullPath = @"D:\Workspace\TestVideo{0}.mp4"; string snapshotParentDir = @"D:\Workspace\TestVideoSnapshot"; int exeMoreCrawlSnapshotCount = ; public ffmpegTest02()
{
base.InitForm();
InitializeComponent();
base.InitControls(this.listInfoLog);
} private void OnProgress(object sender, ConversionProgressEventArgs e)
{
ShowAndLog(string.Format("[{0} => {1}]", e.Input.FileInfo.Name, e.Output?.FileInfo.Name), false, null);
ShowAndLog(string.Format("Bitrate: {0}", e.Bitrate), false, null);
ShowAndLog(string.Format("Fps: {0}", e.Fps), false, null);
ShowAndLog(string.Format("Frame: {0}", e.Frame), false, null);
ShowAndLog(string.Format("ProcessedDuration: {0}", e.ProcessedDuration), false, null);
ShowAndLog(string.Format("Size: {0} kb", e.SizeKb), false, null);
ShowAndLog(string.Format("TotalDuration: {0}\n", e.TotalDuration), false, null);
} /// <summary>
/// 此事件短时间(比如:1秒以内)会调用多次
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void OnData(object sender, ConversionDataEventArgs e)
{
ShowAndLog(string.Format("[从源文件 {0} 到目标文件 {1}],数据 {2}", e.Input.FileInfo.Name, e.Output?.FileInfo.Name, e.Data),
false,
null);
} /// <summary>
/// 此事件短时间(比如:1秒以内)会调用多次
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void OnDataSimpleShow(object sender, ConversionDataEventArgs e)
{
ShowAndLog(string.Format("[从源文件 {0} 到目标文件 {1}]。", e.Input.FileInfo.Name, e.Output?.FileInfo.Name),
false,
null);
} private void OnComplete(object sender, ConversionCompleteEventArgs e)
{
ShowAndLog(string.Format("从 {0} 到 {1} 处理完成。 ", e.Input.FileInfo.FullName, e.Output?.FileInfo.FullName),
false,
null);
} private void OnError(object sender, ConversionErrorEventArgs e)
{
ShowAndLog(string.Format("[{0} => {1}]: 错误: {2}\n{3}", e.Input.FileInfo.Name, e.Output?.FileInfo.Name, e.Exception.ExitCode, e.Exception.InnerException),
false,
null);
} private IEnumerable<TimeSpan> CreateTimeSpanArray()
{
for (int i = ; i < ; i++)
{
yield return new TimeSpan(, i, );
}
} private ConversionOptions GetConversionOptions(TimeSpan tsItem)
{
return new ConversionOptions
{
Seek = tsItem,
//下面表示3行代码表示需要自定义截图的尺寸
VideoSize = VideoSize.Custom,
CustomWidth = , // 截图的宽度
CustomHeight = , // 截图的高度
FFmpegDrawTextArgs = string.Format("borderw=10:bordercolor=white:fontcolor=#A9A9A8:fontsize=100:fontfile=FreeSerif.ttf:text='{0}\\:{1}\\:{2}':x =(w-text_w-50):y=(h-text_h-50)",
tsItem.Hours.ToString().PadLeft(, ''),
tsItem.Minutes.ToString().PadLeft(, ''),
tsItem.Seconds.ToString().PadLeft(, '')
),
ExtraFFmpegArgs = " -y " // -y 表示目标文件已经存在,则覆盖输出文件
};
} private async void btnStartConvertAndSnapshot_Click(object sender, EventArgs e)
{
string mkvOutputFileFullPath = string.Format(@"D:\Workspace\TestVideo-{0}.mkv", DateTime.Now.ToString("yyyy-MM-dd_HH-mm-ss"));
string mkvThumbOutputFileFullPath = string.Format(@"{0}\TestVideo-mkv-thumb-{1}.png", snapshotParentDir, DateTime.Now.ToString("yyyy-MM-dd_HH-mm-ss"));
try
{
var inputFile = new MediaFile(_videoFileFullPath);
var outputFile = new MediaFile(mkvOutputFileFullPath);
var thumbNailFile = new MediaFile(mkvThumbOutputFileFullPath); var ffmpeg = new Engine(TaskffmpegNETExeFullPath);
//ffmpeg.Progress += OnProgress;
//ffmpeg.Data += OnDataSimpleShow;
ffmpeg.Error += OnError;
ffmpeg.Complete += OnComplete;
var output = await ffmpeg.ConvertAsync(inputFile, outputFile);
var thumbNail = await ffmpeg.GetThumbnailAsync(output, thumbNailFile, GetConversionOptions(TimeSpan.FromSeconds()));
var metadata = await ffmpeg.GetMetaDataAsync(output);
Console.WriteLine(metadata.FileInfo.FullName);
Console.WriteLine(metadata);
}
catch (Exception exc)
{
Console.WriteLine(exc);
}
} private async void btnGetVideoInfo_Click(object sender, EventArgs e)
{
ShowAndLog("ffmpeg 准备开始获取,请稍后...", false, null);
Stopwatch globalWatch = Stopwatch.StartNew();
var ffmpeg = new Engine(TaskffmpegNETExeFullPath);
//ffmpeg.Progress += OnProgress;
//ffmpeg.Data += OnDataSimpleShow;
ffmpeg.Error += OnError;
ffmpeg.Complete += OnComplete; var inputFile = new MediaFile(_videoFileFullPath);
MetaData md = await ffmpeg.GetMetaDataAsync(inputFile); ShowAndLog(string.Format("Duration:{0}", md.Duration), false, null);
ShowAndLog(string.Format("VideoData:{0}", JsonHelper.SerializeToJson(md.VideoData)), false, null);
ShowAndLog(string.Format("AudioData:{0}", JsonHelper.SerializeToJson(md.AudioData)), false, null); globalWatch.Stop();
ShowAndLog(string.Format("运行结束!共耗时 {0} 毫秒。", globalWatch.ElapsedMilliseconds), false, null); } private async void btnStartSingleSnapshot_Click(object sender, EventArgs e)
{
ShowAndLog("ffmpeg 准备开始转换,请稍后...", false, null);
Stopwatch globalWatch = Stopwatch.StartNew();
IEnumerable<TimeSpan> timeSpanArray = CreateTimeSpanArray();
var ffmpeg = new Engine(TaskffmpegNETExeFullPath);
//ffmpeg.Progress += OnProgress;
//ffmpeg.Data += OnDataSimpleShow;
ffmpeg.Error += OnError;
ffmpeg.Complete += OnComplete; var inputFile = new MediaFile(_videoFileFullPath); int i = ;
string mkvThumbOutputFileFullPath;
List<string> allThumbFullName = new List<string>();
foreach (TimeSpan tsItem in timeSpanArray)
{
i++;
mkvThumbOutputFileFullPath = string.Format(@"{0}\TestVideo-mp4-thumb-{1}-{2}.jpg", snapshotParentDir, DateTime.Now.ToString("yyyy-MM-dd_HH-mm-ss.fff"), i);
allThumbFullName.Add(mkvThumbOutputFileFullPath);
var thumbNailFile = new MediaFile(mkvThumbOutputFileFullPath);
await ffmpeg.GetThumbnailAsync(inputFile, thumbNailFile, GetConversionOptions(tsItem) );
}
ShowAndLog("ffmpeg 转换完成。结果如下:", false, null);
globalWatch.Stop();
ShowAndLog(string.Format("运行结束!共耗时 {0} 毫秒。", globalWatch.ElapsedMilliseconds), false, null);
} private async void btnParelleSyncStartMoreCrawlSnapshot_ClickAsync(object sender, EventArgs e)
{
ShowAndLog("准备开始同步多个 TestVideo{n}.mp4 上截图,请稍后...", false, null);
Stopwatch globalWatch = Stopwatch.StartNew(); for (int i = ; i < exeMoreCrawlSnapshotCount; i++)
{
await CreateSnapshotCoreAsync(i + );
}
ShowAndLog("同步多个 TestVideo{n}.mp4 上截图完成。结果如下:", false, null);
globalWatch.Stop();
ShowAndLog(string.Format("运行结束!共耗时 {0} 毫秒。", globalWatch.ElapsedMilliseconds), false, null);
} private async Task CreateSnapshotCoreAsync(int fileId)
{
IEnumerable<TimeSpan> timeSpanArray = CreateTimeSpanArray();
var ffmpeg = new Engine(TaskffmpegNETExeFullPath);
//ffmpeg.Progress += OnProgress;
//ffmpeg.Data += OnDataSimpleShow;
ffmpeg.Error += OnError;
ffmpeg.Complete += OnComplete; var inputFile = new MediaFile(string.Format(_othereVideoFileFullPath, fileId)); //_videoFileFullPath int i = ;
string mkvThumbOutputFileFullPath;
List<string> allThumbFullName = new List<string>();
foreach (TimeSpan tsItem in timeSpanArray)
{
i++;
mkvThumbOutputFileFullPath = string.Format(@"{0}\TestVideo{1}-mp4-thumb-{2}-{3}.jpg", snapshotParentDir, fileId, DateTime.Now.ToString("yyyy-MM-dd_HH-mm-ss.fff"), i);
allThumbFullName.Add(mkvThumbOutputFileFullPath);
var thumbNailFile = new MediaFile(mkvThumbOutputFileFullPath);
await ffmpeg.GetThumbnailAsync(inputFile, thumbNailFile, GetConversionOptions(tsItem));
}
} private async void btnParelleAsyncStartMoreCrawlSnapshot_ClickAsync(object sender, EventArgs e)
{
ShowAndLog("准备开始异步并行多个 TestVideo{n}.mp4 上截图,请稍后...", false, null);
Stopwatch globalWatch = Stopwatch.StartNew(); var tasks = Enumerable.Range(, exeMoreCrawlSnapshotCount).Select(i =>
{
return Task.Run(async () =>
{
await CreateSnapshotCoreAsync(i + );
});
});
await Task.WhenAll(tasks);
ShowAndLog("异步并行多个 TestVideo{n}.mp4 上截图完成。结果如下:", false, null);
globalWatch.Stop();
ShowAndLog(string.Format("运行结束!共耗时 {0} 毫秒。", globalWatch.ElapsedMilliseconds), false, null);
} private async void btnParelleAsyncStartMoreCrawlSnapshotLimitMaxDop_Click(object sender, EventArgs e)
{
ShowAndLog("准备开始异步并行多个 TestVideo{n}.mp4 上截图(限制最大异步处理单元),请稍后...", false, null);
Stopwatch globalWatch = Stopwatch.StartNew();
var tasks = Enumerable.Range(, exeMoreCrawlSnapshotCount).ParallelForEachAsync(i =>
{
return Task.Run(async () =>
{
await CreateSnapshotCoreAsync(i + );
});
}, Environment.ProcessorCount);
await Task.WhenAll(tasks);
ShowAndLog("异步并行多个 TestVideo{n}.mp4 上截图(限制最大异步处理单元)完成。结果如下:", false, null);
globalWatch.Stop();
ShowAndLog(string.Format("运行结束!共耗时 {0} 毫秒。", globalWatch.ElapsedMilliseconds), false, null);
}
}
ffmpegTest02.Designer.cs
partial class ffmpegTest02
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null; /// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
} #region Windows Form Designer generated code /// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.btnStartConvertAndSnapshot = new System.Windows.Forms.Button();
this.listInfoLog = new System.Windows.Forms.ListBox();
this.btnStartSingleSnapshot = new System.Windows.Forms.Button();
this.btnGetVideoInfo = new System.Windows.Forms.Button();
this.btnParelleSyncStartMoreCrawlSnapshot = new System.Windows.Forms.Button();
this.btnParelleAsyncStartMoreCrawlSnapshot = new System.Windows.Forms.Button();
this.btnParelleAsyncStartMoreCrawlSnapshotLimitMaxDop = new System.Windows.Forms.Button();
this.SuspendLayout();
//
// btnStartConvertAndSnapshot
//
this.btnStartConvertAndSnapshot.Location = new System.Drawing.Point(, );
this.btnStartConvertAndSnapshot.Name = "btnStartConvertAndSnapshot";
this.btnStartConvertAndSnapshot.Size = new System.Drawing.Size(, );
this.btnStartConvertAndSnapshot.TabIndex = ;
this.btnStartConvertAndSnapshot.Text = "1. 开始先把 TestVideo.mp4 转换 mkv,再在第 1 分钟的时候截图";
this.btnStartConvertAndSnapshot.UseVisualStyleBackColor = true;
this.btnStartConvertAndSnapshot.Click += new System.EventHandler(this.btnStartConvertAndSnapshot_Click);
//
// listInfoLog
//
this.listInfoLog.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.listInfoLog.Font = new System.Drawing.Font("宋体", 10F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)()));
this.listInfoLog.FormattingEnabled = true;
this.listInfoLog.HorizontalScrollbar = true;
this.listInfoLog.Location = new System.Drawing.Point(, );
this.listInfoLog.Name = "listInfoLog";
this.listInfoLog.ScrollAlwaysVisible = true;
this.listInfoLog.Size = new System.Drawing.Size(, );
this.listInfoLog.TabIndex = ;
//
// btnStartSingleSnapshot
//
this.btnStartSingleSnapshot.Location = new System.Drawing.Point(, );
this.btnStartSingleSnapshot.Name = "btnStartSingleSnapshot";
this.btnStartSingleSnapshot.Size = new System.Drawing.Size(, );
this.btnStartSingleSnapshot.TabIndex = ;
this.btnStartSingleSnapshot.Text = "2. 不转码,直接在第 1分钟的时候从 TestVideo.mp4 上截图";
this.btnStartSingleSnapshot.UseVisualStyleBackColor = true;
this.btnStartSingleSnapshot.Click += new System.EventHandler(this.btnStartSingleSnapshot_Click);
//
// btnGetVideoInfo
//
this.btnGetVideoInfo.Location = new System.Drawing.Point(, );
this.btnGetVideoInfo.Name = "btnGetVideoInfo";
this.btnGetVideoInfo.Size = new System.Drawing.Size(, );
this.btnGetVideoInfo.TabIndex = ;
this.btnGetVideoInfo.Text = "3. 仅仅获取 TestVideo.mp4 视频的信息";
this.btnGetVideoInfo.UseVisualStyleBackColor = true;
this.btnGetVideoInfo.Click += new System.EventHandler(this.btnGetVideoInfo_Click);
//
// btnParelleSyncStartMoreCrawlSnapshot
//
this.btnParelleSyncStartMoreCrawlSnapshot.Location = new System.Drawing.Point(, );
this.btnParelleSyncStartMoreCrawlSnapshot.Name = "btnParelleSyncStartMoreCrawlSnapshot";
this.btnParelleSyncStartMoreCrawlSnapshot.Size = new System.Drawing.Size(, );
this.btnParelleSyncStartMoreCrawlSnapshot.TabIndex = ;
this.btnParelleSyncStartMoreCrawlSnapshot.Text = "4. 同步多个 TestVideo{n}.mp4 上截图";
this.btnParelleSyncStartMoreCrawlSnapshot.UseVisualStyleBackColor = true;
this.btnParelleSyncStartMoreCrawlSnapshot.Click += new System.EventHandler(this.btnParelleSyncStartMoreCrawlSnapshot_ClickAsync);
//
// btnParelleAsyncStartMoreCrawlSnapshot
//
this.btnParelleAsyncStartMoreCrawlSnapshot.Location = new System.Drawing.Point(, );
this.btnParelleAsyncStartMoreCrawlSnapshot.Name = "btnParelleAsyncStartMoreCrawlSnapshot";
this.btnParelleAsyncStartMoreCrawlSnapshot.Size = new System.Drawing.Size(, );
this.btnParelleAsyncStartMoreCrawlSnapshot.TabIndex = ;
this.btnParelleAsyncStartMoreCrawlSnapshot.Text = "5. 异步并行多个 TestVideo{n}.mp4 上截图";
this.btnParelleAsyncStartMoreCrawlSnapshot.UseVisualStyleBackColor = true;
this.btnParelleAsyncStartMoreCrawlSnapshot.Click += new System.EventHandler(this.btnParelleAsyncStartMoreCrawlSnapshot_ClickAsync);
//
// btnParelleAsyncStartMoreCrawlSnapshotLimitMaxDop
//
this.btnParelleAsyncStartMoreCrawlSnapshotLimitMaxDop.Location = new System.Drawing.Point(, );
this.btnParelleAsyncStartMoreCrawlSnapshotLimitMaxDop.Name = "btnParelleAsyncStartMoreCrawlSnapshotLimitMaxDop";
this.btnParelleAsyncStartMoreCrawlSnapshotLimitMaxDop.Size = new System.Drawing.Size(, );
this.btnParelleAsyncStartMoreCrawlSnapshotLimitMaxDop.TabIndex = ;
this.btnParelleAsyncStartMoreCrawlSnapshotLimitMaxDop.Text = "6. 异步并行多个 TestVideo{n}.mp4 上截图(限制最大异步处理单元)";
this.btnParelleAsyncStartMoreCrawlSnapshotLimitMaxDop.UseVisualStyleBackColor = true;
this.btnParelleAsyncStartMoreCrawlSnapshotLimitMaxDop.Click += new System.EventHandler(this.btnParelleAsyncStartMoreCrawlSnapshotLimitMaxDop_Click);
//
// ffmpegTest02
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(, );
this.Controls.Add(this.btnParelleAsyncStartMoreCrawlSnapshotLimitMaxDop);
this.Controls.Add(this.btnParelleAsyncStartMoreCrawlSnapshot);
this.Controls.Add(this.btnParelleSyncStartMoreCrawlSnapshot);
this.Controls.Add(this.btnGetVideoInfo);
this.Controls.Add(this.btnStartSingleSnapshot);
this.Controls.Add(this.listInfoLog);
this.Controls.Add(this.btnStartConvertAndSnapshot);
this.Name = "ffmpegTest02";
this.Text = "ffmpegTest02";
this.ResumeLayout(false); } #endregion private System.Windows.Forms.Button btnStartConvertAndSnapshot;
private System.Windows.Forms.ListBox listInfoLog;
private System.Windows.Forms.Button btnStartSingleSnapshot;
private System.Windows.Forms.Button btnGetVideoInfo;
private System.Windows.Forms.Button btnParelleSyncStartMoreCrawlSnapshot;
private System.Windows.Forms.Button btnParelleAsyncStartMoreCrawlSnapshot;
private System.Windows.Forms.Button btnParelleAsyncStartMoreCrawlSnapshotLimitMaxDop;
}
运行结果
图 01
图 02
图 03
图 04
图 05
图 06
图 07
图 08
谢谢浏览!
如何让 FFmpeg 支持异步并行转码、截图等等操作?的更多相关文章
- Java Web 中使用ffmpeg实现视频转码、视频截图
Java Web 中使用ffmpeg实现视频转码.视频截图 转载自:[ http://www.cnblogs.com/dennisit/archive/2013/02/16/2913287.html ...
- windows下使用ffmpeg进行视频转换和截图。
author:fanfq(xiaoban) Email:fangqing.fan#gmail.comlink:http://fanfq.iteye.com/admin/blogs/655569chan ...
- C# 使用 ffmpeg 进行音频转码
先放一下 ffmpeg 的官方文档以及下载地址: 官方文档:http://ffmpeg.org/ffmpeg.html 下载地址:http://ffmpeg.org/download.html 用 f ...
- FFmpeg:视频转码、剪切、合并、播放速调整
原文:https://fzheng.me/2016/01/08/ffmpeg/ FFmpeg:视频转码.剪切.合并.播放速调整 2016-01-08 前阵子帮导师处理项目 ppt,因为插入视频的格式问 ...
- 使用ffmpeg.exe进行转码参数说明
使用ffmpeg.exe进行转码参数说明 摘自:https://blog.csdn.net/coloriy/article/details/47337641 2015年08月07日 13:04:32 ...
- ubuntu系统下安装gstreamer的ffmpeg支持
当您在安装gstreamer到您的ubuntu系统中时,为了更好地进行流媒体开发,需要安装ffmpeg支持,但一般情况下,直接使用 sudo apt-get install gstreamer0.10 ...
- [IBM][CLI Driver] SQL0270N 函数不受支持(原因码:"75")。 SQLSTATE=42997
db2 update dbm cfg using FEDERATED yes 与 自动维护 (AUTO_MAINT) = ON 自动数据库备份 (AUTO_DB_BACKUP) = OFF 自动表 ...
- Python3选择支持非ASCII码标识符的缘由
原文在: PEP 3131 -- Supporting Non-ASCII Identifiers. Python2并不支持非ASCII码标识符. PEP的全称是Python Enhancement ...
- API Studio 5.1.2 版本更新:加入全局搜索、支持批量测试API测试用例、读取代码注解生成文档支持Github与码云等
最近在EOLINKER的开发任务繁重,许久在博客园没有更新产品动态了,经过这些日子,EOLINKER又有了长足的进步,增加了更多易用的功能,比如加入全局搜索.支持批量测试API测试用例.读取代码注解生 ...
随机推荐
- RadioButtonList
RadioButtonList <asp:Label ID="txt_Gender" runat="server" Text="性别" ...
- Python远程linux执行命令
1.远程登录到linux上,使用到的模块paramiko #远程登陆操作系统 def ssh(sys_ip,username,password,cmds): try #创建ssh客户端 client ...
- UserControl关闭
直接 Application.Current.Shutdown();关闭程序.
- 最全的.NET Core跨平台微服务学习资源
一.Asp.net Core基础 微软中文官网:https://docs.microsoft.com/zh-cn/aspnet/core/getting-started/ 微软英文官网:https:/ ...
- webpack基本使用
webpack安装时的坑 高版本的webpack除了全局安装webpack外,还需安装webpack-cli,在本地使用时也一样需要这样,不然会出错 webpack使用是的坑 在原始启动webpack ...
- python基础(31):进程(一)
1. 什么是进程 进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础.在早期面向进程设计的计算机结构中,进程是程序的基本执行 ...
- java基础(16):正则表达式、Date、DateFormat、Calendar
1. 正则表达式 1.1 正则表达式的概念 正则表达式(英语:Regular Expression,在代码中常简写为regex). 正则表达式是一个字符串,使用单个字符串来描述.用来定义匹配规则,匹配 ...
- jqgrid后台处理搜索
jqgrid后台处理搜索, 如果点击jqgrid自带的搜索,则向后台传递“_search”参数,和searchField.searchOper.searchString三个值.如下所示: string ...
- 强大的Charles的使用,强大的flutter1.9
<a href="http://www.cocoachina.com/articles/37551?filter=ios"> 强大的Charles 强大的flutter
- nRF24L01+如何检测信道被占用-RSSI寄存器实战分享
检测信道占用的需求场景 在使用nRF24L01模块做一对多或多对一的组网通信中,大家都会担心一个问题就是在发送的时候,希望不要有其他的模块也进行发送,因为这样就会使无线信号发生碰撞,信道被堵塞,造成通 ...