winform小工具的设计

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)

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注