【发布时间】:2023-04-01 07:34:01
【问题描述】:
我知道stackoverflow上有很多这方面的信息,但没有找到任何解决我问题的方法。
我制作了一个程序来使用 ffmpeg 处理一些视频文件。这个过程可能需要几分钟,所以,我正在尝试在另一个表单上制作进度条。
基本上,当我单击主表单 (FormSync) 上的按钮时,会显示一个新表单。这个表单只有一个进度条和一个取消按钮(让我们调用FormProgress)。
为了执行ffmpeg,我使用另一个类(VideoProcessing)来创建一个新进程,执行ffmpeg,并监控stderror(ffmpeg show progress on stderror)。每次 ffmpeg 显示一个进度时,这个类都会解析输出,计算进度,并引发一个事件(OnMergeProgress)。
基本上就是这样的代码:
FormSync:
public partial class FormSync : Form
{
// this form show the progress of job
private FormProgress _formProgress;
// start the ffmpeg when click on button
private void mergeButton_click(object sender, EventArgs e)
{
var files = new List<string>() {"file1.mp4", "file2.mp4"};
MergeFiles(files);
}
// join all video files on a single file (using ffmpeg)
private void MergeFiles(IEnumerable<string> videoFiles)
{
// instantiate the class that execute ffmpeg
VideoProcessing videoProcessing = new VideoProcessing();
// this class has a a event to show current progress
// seconds = total seconds of video (sum length of all video files)
// currentSeconds = current progress
videoProcessing.OnMergeProgress += (seconds, currentSeconds) =>
{
Invoke((MethodInvoker) delegate()
{
// Instantiate the form of progress if not visible
if (_formProgress = null)
{
// define the minimum and maximum value of progressbar on constructor
_formProgress = new FormProgress(0, seconds);
_formProgress.ShowDialog(this);
}
// update the progress bar value
_formProgress.SetProgress(currentSeconds);
}
}
}
}
FormProgress:
public partial class FormProgress : Form
{
public FormProgress(int min, int max)
{
InitializeComponent();
progressBar.Minimum = min;
progressBar.Maximum = max;
}
public void SetProgress(int value)
{
value = (value <= progressBar.Minimum)
? progressBar.Minimum
: (value >= progressBar.Maximum) ? progressBar.Maximum : value;
progressBar.Value = value;
Refresh();
}
}
视频处理:
internal class VideoProcessing
{
// Events
public delegate void MergeProgressHandler(int totalSeconds, int currentSeconds);
public event MergeProgressHandler OnMergeProgress;
private int _totalTimeVideos;
public void MergeFiles(string[] videoFiles)
{
// calculate total time of all videos
_totalTimeVideos = SomeFunctionToCalculateTotalTime();
// create the Process object to execute FFMPEG (with stdout and stderr redirection)
_process = CreateFFMPEGProcess(videoFiles);
}
// capture the stdout and stderr of ffmpeg
private void MergeOutputHandler(object sendingProcess, DataReceivedEventArgs outline)
{
// capture the current progress
// here will go a regex, and some other code to parse the info from ffmpeg
// Raise the event
OnMergeProgress?.Invoke(_totalTimeVideos, progressSeconds);
}
}
基本上,FFMPEG 执行和捕获过程使用以下代码: C# execute external program and capture (stream) the output
当我尝试执行代码时出现问题。
当我单击 que 按钮时,会显示 FormProgress,但在此之后,进度条会“冻结”。程序运行良好,此处没有挂起,但进度条没有更新。
如果,在FormSync,InvokeMethod,我用下面的内容替换原来的代码,我可以看到ffmpeg在工作,我的事件也在工作:
videoProcessing.OnMergeProgress += (seconds, currentSeconds) =>
{
Debug.WriteLine($"{currentSeconds}/{seconds}");
}
所以,问题不是 ffmpeg 或我的视频类,而是更新 UI 的问题。
如果我再次更改Invoke,但这次使用Debug,如下面的代码,Debug 仅打印第一次更新,仅此而已:
videoProcessing.OnMergeProgress += (seconds, currentSeconds) =>
{
Invoke((MethodInvoker) delegate() {
if (_formProgress == null) {
_formProgress = new FormProgress(Resources.merging_video_files, 0, seconds);
_formProgress.ShowDialog(this);
}
_formProgress.SetProgress(currentSeconds);
});
Debug.WriteLine($"{currentSeconds}/{seconds}");
}
【问题讨论】:
标签: c# multithreading