winform小工具的设计
- 未来批量对视频的操作,我们设计一款winform小工具。可以批量选择多个视频文件,并且把视频切片成相应的文件。
核心实现与代码要点
- 设计目的:为了未来批量对视频进行操作,通过 WinForm 界面实现多选视频文件,并自动调用 ffmpeg 将其切片为 m3u8 格式。
- 核心调用:使用
System.Diagnostics.Process启动外部程序ffmpeg.exe。 - 关键参数配置:
UseShellExecute = false:必须设为 false,以便重定向输出。RedirectStandardError = true:特别注意,ffmpeg 的输出信息(包括进度和日志)全部走错误输出流,需用StandardError捕获,用StandardOutput会抓不到。CreateNoWindow = true:隐藏 ffmpeg 的黑框控制台。BeginErrorReadLine():异步读取输出流,配合ErrorDataReceived事件(代码中用于随机变色展示)。
- 切片参数:
-c:v libx264 -c:a aac -strict -2 -f hls -hls_list_size 0 -hls_time 5,表示转码为 H.264+AAC,切片为 hls,列表大小不限,每片 5 秒。 - 批量与路径:
- 使用
OpenFileDialog开启多选(Multiselect隐含),遍历FileNames。 - 输出目录默认为视频同目录下的
m3u8\随机名,支持通过按钮自定义输出路径(textBox1+folderBrowserDialog1)。 - 生成 GUID 作为子文件夹名,避免重名,最终生成
v.m3u8及.ts文件。
- 使用
- 进度与UI:
progressBar1设置最大最小值为文件总数,循环内更新Value。Control.CheckForIllegalCrossThreadCalls = false允许跨线程操作控件(非最优但简化演示),richTextBox1展示处理日志。- 处理完自动打开资源管理器展示输出目录。
- 注意事项:
- 需确保
ffmpeg.exe在程序运行目录(或配置绝对路径),依赖上节环境变量或直接放置 bin 目录。 - 代码中
p.WaitForExit()会阻塞当前线程,批量大文件时界面可能假死,实际可结合后台线程/Task 优化(图中注释了 Thread 启动)。 - 随机颜色
GetRandomColor()仅为视觉反馈,非核心功能。
- 需确保
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace VideoTool
{
public partial class Form1 : Form
{
public Form1()
{
System.Windows.Forms.Control.CheckForIllegalCrossThreadCalls = false;
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
//Thread thread = new Thread(new ThreadStart(NewMethod));
//thread.Start();
NewMethod();
}
private void NewMethod()
{
if (openFileDialog1.ShowDialog() == DialogResult.OK)
{
var fileNames = openFileDialog1.FileNames;
if (fileNames.Count() == 0)
{
return;
}
var path = string.IsNullOrEmpty(this.textBox1.Text) ? openFileDialog1.FileName.Replace("\\" + openFileDialog1.SafeFileName, string.Empty) : this.textBox1.Text;
this.progressBar1.Maximum = fileNames.Count();
this.progressBar1.Minimum = 1;
for (int i = 0; i < fileNames.Count(); i++)
{
Process p = new Process();//建立外部调用线程
p.StartInfo.FileName = @"ffmpeg.exe";//要调用外部程序的绝对路径
p.StartInfo.UseShellExecute = false;//不使用操作系统外壳程序启动线程(一定为FALSE,详细的请看MSDN)
p.StartInfo.RedirectStandardError = true;//把外部程序错误输出写到StandardError流中(这个一定要注意,FFMPEG的所有输出信息,都为错误输出流,用StandardOutput是捕获不到任何消息的...这是我耗费了2个多月得出来的经验...mencoder就是用standardOutput来捕获的)
p.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
p.StartInfo.CreateNoWindow = true;//不创建进程窗口
p.StartInfo.StandardErrorEncoding = Encoding.Default;
p.ErrorDataReceived += new DataReceivedEventHandler(Output);//外部程序(这里是FFMPEG)输出流时候产生的事件,这里是把流的处理过程转移到下面的方法中,详细请查阅MSDN
var fileName = openFileDialog1.SafeFileNames[i].Remove(openFileDialog1.SafeFileNames[i].LastIndexOf('.'));
string name = Guid.NewGuid().ToString().Substring(0, 16);
string link = openFileDialog1.SafeFileNames[i] + ": " + name;
//var mpath = path + "\\m3u8\\" + (fileName.Contains("-")?fileName.Remove(fileName.LastIndexOf("-")):fileName);
var mpath = path + "\\m3u8\\" + name;
if (!Directory.Exists(mpath))
{
Directory.CreateDirectory(mpath);
}
p.StartInfo.Arguments = " -i \"" + fileNames[i] + "\" -c:v libx264 -c:a aac -strict -2 -f hls -hls_list_size 0 -hls_time 5 \"" + mpath.Trim() + "\\v.m3u8\" ";//参数(这里就是FFMPEG的参数了)
p.Start();//启动线程
p.BeginErrorReadLine();//开始异步读取
p.WaitForExit();//阻塞等待进程结束
p.Close();//关闭进程
p.Dispose();//释放资源
this.richTextBox1.Text = link + "\n" + this.richTextBox1.Text;
this.progressBar1.Value = i + 1;
}
Process.Start("Explorer.exe", path + "\\m3u8\\");
}
}
static string link = string.Empty;
private void Output(object sender, DataReceivedEventArgs e)
{
if (!String.IsNullOrEmpty(e.Data))
{
//this.richTextBox1.Text = this.richTextBox1.Text;
//if (e.Data.Contains(", from") || e.Data.Contains("hls, to"))
//{
// this.richTextBox1.Text = e.Data + this.richTextBox1.Text;
//}
//if (e.Data.Contains("Qavg:"))
//{
// this.richTextBox1.Text = this.richTextBox1.Text + "\n" + link;
//}
this.richTextBox1.BackColor = GetRandomColor();
}
}
public Color GetRandomColor()
{
int iSeed = 10;
Random ro = new Random(10);
long tick = DateTime.Now.Ticks;
Random ran = new Random((int)(tick & 0xffffffffL) | (int)(tick >> 32));
int R = ran.Next(255);
int G = ran.Next(255);
int B = ran.Next(255);
B = (R + G > 400) ? R + G - 400 : B;//0 : 380 - R - G;
B = (B > 255) ? 255 : B;
return Color.FromArgb(R, G, B);
}
private void button2_Click(object sender, EventArgs e)
{
if (folderBrowserDialog1.ShowDialog() == DialogResult.OK)
{
this.textBox1.Text = folderBrowserDialog1.SelectedPath;
}
}
}
}
Code language: HTML, XML (xml)
Previous: ffmepg介绍和切片操作
Next: C#操作ffmpeg(附源码)