You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在循环中逐个执行Process进程,单进程调用ffmpeg处理视频文件

问题描述

在for循环中向Process传入文件路径,让ffmpeg.exe每次仅读取一个视频文件的格式,但文本框显示第一个视频的内容后程序就停止了。尝试使用process.close()和process.hasExited,但无法阻止程序启动多个进程,导致委托输出大量涌入文本框(输出顺序混乱,无法区分对应视频,还存在输出缺失或重复的情况)。需要实现循环中每次仅执行一个进程,完成后再启动下一个进程。

用户原代码:

foreach (String file in inputList)
{
    if (flag == true)
    {
        flag = false;
        //textBox1.Text += file + Environment.NewLine;
        checkvideoFormat(file);
    }
}
}
catch (Exception err)
{
    MessageBox.Show(err.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
private void checkvideoFormat(String filePath)
{
    Process process1 = new Process();
    process1.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
    process1.StartInfo.CreateNoWindow = true;
    process1.StartInfo.UseShellExecute = false;
    process1.StartInfo.FileName = ".\\ffmpeg.exe";
    process1.StartInfo.WorkingDirectory = ".\\";
    process1.EnableRaisingEvents = true;
    process1.StartInfo.RedirectStandardOutput = true; //if this is true, UseShellExecute must be false. true if output should be written to StandardOutput
    process1.StartInfo.RedirectStandardError = true;
    //indicates that the associated Process has written a line that's terminated with a newline
    process1.ErrorDataReceived += new DataReceivedEventHandler(inputHandler);

    process1.Exited += (ending, p) =>
    {
        flag = true;
        Console.WriteLine(flag);
        //textBox1.Text += "Hey " + file + Environment.NewLine;
        //process1.CancelOutputRead();
        //process1.CancelErrorRead();//
    };

    process1.StartInfo.Arguments = "-i " + " \"" + filePath + "\"";
    Console.WriteLine(process1.StartInfo.Arguments);
    process1.Start();
    process1.BeginOutputReadLine();
    process1.BeginErrorReadLine();
    //process1.Close();
    //process1.WaitForExit();
    /*
    if(process1.HasExited == true)
    {
        //process1.Refresh();
        flag = true;
        //process1.Close();
        //process1.Kill();
        Thread.Sleep(1000);
    }
    */
}

int test_123 = 0;
private void inputHandler(object sender, DataReceivedEventArgs l)
{
    cba.Append(test_123 + l.Data + "\n");
    videoInput = test_123 + l.Data + Environment.NewLine;
    //Console.WriteLine(cba);
    //Process p = sender as Process;
    Console.WriteLine(videoInput);

    this.Invoke(new MethodInvoker(() =>
    {
        if (!String.IsNullOrEmpty(videoInput))
        {
            textBox1.Text += videoInput;
        }
    }));
    test_123++;
}
解决方案

核心问题是原代码用flag异步控制循环,但UI线程会直接跑完循环逻辑,不会等待Exited事件触发。以下两种方式可实现逐个执行进程:

方式一:后台线程同步等待(简单直接)

把循环放到后台线程,用WaitForExit()等待当前进程结束后再处理下一个文件,避免阻塞UI:

// 示例:按钮点击触发处理
private void btnStart_Click(object sender, EventArgs e)
{
    // 启动后台线程执行循环,不卡UI
    Task.Run(() =>
    {
        foreach (string file in inputList)
        {
            ProcessSingleFile(file);
            // 给UI更新处理完成状态
            this.Invoke(() => textBox1.Text += $"✅ 完成处理:{Path.GetFileName(file)}{Environment.NewLine}");
        }
    });
}

private void ProcessSingleFile(string filePath)
{
    // using自动释放进程资源
    using (Process ffmpegProcess = new Process())
    {
        ffmpegProcess.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
        ffmpegProcess.StartInfo.CreateNoWindow = true;
        ffmpegProcess.StartInfo.UseShellExecute = false;
        ffmpegProcess.StartInfo.FileName = ".\\ffmpeg.exe";
        ffmpegProcess.StartInfo.WorkingDirectory = ".\\";
        ffmpegProcess.StartInfo.RedirectStandardError = true;

        // 绑定错误输出处理,关联当前文件名,避免输出混乱
        ffmpegProcess.ErrorDataReceived += (sender, args) =>
        {
            if (!string.IsNullOrEmpty(args.Data))
            {
                string output = $"[{Path.GetFileName(filePath)}] {args.Data}{Environment.NewLine}";
                this.Invoke(() => textBox1.Text += output);
            }
        };

        ffmpegProcess.StartInfo.Arguments = $"-i \"{filePath}\"";
        ffmpegProcess.Start();
        ffmpegProcess.BeginErrorReadLine();
        // 等待进程执行完毕
        ffmpegProcess.WaitForExit();
        // 确保所有输出都被读取
        ffmpegProcess.CancelErrorRead();
    }
}

方式二:队列+事件驱动(非阻塞UI)

用队列存储待处理文件,当前进程结束后通过Exited事件触发下一个文件的处理,全程保持UI响应:

private Queue<string> _pendingFiles;

// 示例:按钮点击触发处理
private void btnStart_Click(object sender, EventArgs e)
{
    _pendingFiles = new Queue<string>(inputList);
    // 启动第一个文件的处理
    ProcessNextFile();
}

private void ProcessNextFile()
{
    if (_pendingFiles.Count == 0)
    {
        this.Invoke(() => textBox1.Text += "🎉 所有文件处理完成!" + Environment.NewLine);
        return;
    }

    string currentFile = _pendingFiles.Dequeue();
    using (Process ffmpegProcess = new Process())
    {
        ffmpegProcess.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
        ffmpegProcess.StartInfo.CreateNoWindow = true;
        ffmpegProcess.StartInfo.UseShellExecute = false;
        ffmpegProcess.StartInfo.FileName = ".\\ffmpeg.exe";
        ffmpegProcess.StartInfo.WorkingDirectory = ".\\";
        ffmpegProcess.EnableRaisingEvents = true;
        ffmpegProcess.StartInfo.RedirectStandardError = true;

        // 绑定输出处理,关联当前文件名
        ffmpegProcess.ErrorDataReceived += (sender, args) =>
        {
            if (!string.IsNullOrEmpty(args.Data))
            {
                string output = $"[{Path.GetFileName(currentFile)}] {args.Data}{Environment.NewLine}";
                this.Invoke(() => textBox1.Text += output);
            }
        };

        // 进程结束后自动启动下一个
        ffmpegProcess.Exited += (sender, args) =>
        {
            ffmpegProcess.CancelErrorRead();
            this.Invoke(ProcessNextFile);
        };

        ffmpegProcess.StartInfo.Arguments = $"-i \"{currentFile}\"";
        ffmpegProcess.Start();
        ffmpegProcess.BeginErrorReadLine();
    }
}

关键修复点

  • 输出区分:每个进程的输出绑定当前文件名,解决顺序混乱、无法区分的问题。
  • 流程控制:要么用后台线程同步等待,要么用队列+事件驱动,确保一个进程结束后再启动下一个。
  • 资源释放:用using包裹Process对象,自动释放进程资源,避免泄漏。
  • 移除共享计数器:原代码的test_123会被所有进程共享,导致计数混乱,改为按文件区分输出更清晰。

内容的提问来源于stack exchange,提问作者TSLee

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.20 13:28:11