別の質問で、プログレスバーなどを備えたffmpegパーサーに取り組んでいると述べました。
次の問題は 100% 再現できません。私のプログラムでビデオファイルを変換するとき、ほとんどの場合、何でも問題ありません。小さなファイル(〜100MB出力)では完全に動作しますが、大きなファイル(〜1GB出力)ではGUIがフリーズすることがありますが、ffmpegは動作しています(デバッガーは引き続きffmpegから出力を取得して表示するため、フォームスレッドは実行しますフリーズしないでください、コンソールの GUI のみ)
また、ffmpeg は、フリーズを引き起こす可能性のあるエラーなしで、必要な作業を行うことにも気付きました。
Debug-Environment の外でフォームを実行すると、フォームもフリーズします。
解析は、ffmpeg async の出力を処理するために追加のスレッドで機能します。
このスレッドはフリーズし、ffmpeg の終了後にメイン プログラムがハングアップすると思います。これは、パーサーがcommand == null
メイン プログラムに変換が完了したというメッセージを表示するためです。atmではフリーズを再現できず、最後にデバッガーが出力する"======== #"
かどうかを忘れていたため、実際にはこれを言うことはできません。
ソース (debug-folder の ffmpeg を含む)は、ConvertApp.zip としてここにあります。
プロセス間で話す:
// message directors for threading
private BlockingCollection<string> commandsForParser = new BlockingCollection<string>();
private BlockingCollection<string> commandsForMain = new BlockingCollection<string>();
// sending commands to threads
public void SendCommmandParser(string command)
{
commandsForParser.Add(command);
//Debug.WriteLine("P: " + command);
}
public void SendCommmandMain(string command)
{
commandsForMain.Add(command);
//Debug.WriteLine("M: " + command);
}
解析の呼び出し:
private void showParsedConsole()
{
ConsoleOutput dlg = new ConsoleOutput();
dlg.Show();
//...
while (true)
{
System.Windows.Forms.Application.DoEvents();
string command = commandsForParser.Take();
// if null, ffmpeg finished
if (command == null || command == "..break..")
{
SendCommmandMain("..break..");
dlg.Close();
break;
}
if (dlg.toClose)
{
SendCommmandMain("..cancel..");
dlg.Close();
break;
}
else if (command != null)
{
//... actualizing form (output, progress things)
}
else
dlg.addMessage("\n");
}
}
変換の開始:
public string RunExternalExe(string info, string filename, string arguments = null)
{
// parse console in new thread
var thread = new Thread(showParsedConsole);
thread.Start();
//...
#region init process to run
var process = new Process();
process.StartInfo.FileName = filename;
if (!string.IsNullOrEmpty(arguments))
{
process.StartInfo.Arguments = arguments;
}
process.StartInfo.CreateNoWindow = true;
process.StartInfo.WindowStyle = ProcessWindowStyle.Minimized;
process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardError = true;
process.StartInfo.RedirectStandardOutput = true;
var stdOutput = new StringBuilder();
var errOutput = new StringBuilder();
#endregion
#region redirect stdOut/stdError
process.OutputDataReceived += (sender, args) =>
{
SendCommmandParser(args.Data);
stdOutput.Append(args.Data + "\n");
Debug.WriteLine("S: " + args.Data);
};
process.ErrorDataReceived += (sender, args) =>
{
SendCommmandParser(args.Data);
errOutput.Append(args.Data + "\n");
// if the form is freezing, the debugger will still output these
Debug.WriteLine("E: " + args.Data);
};
#endregion
#region run process
try
{
process.Start();
process.BeginOutputReadLine();
process.BeginErrorReadLine();
while (!process.HasExited)
{
System.Windows.Forms.Application.DoEvents();
string command = commandsForMain.Take();
if (command == "..cancel..")
{
Debug.WriteLine("============== 1");
process.Kill();
while (process != null && !process.HasExited)
{
//wait
}
// return if canceled to provide excetion (process == null)
return "C";
}
if (command == "..break..")
{
Debug.WriteLine("============== 2");
process.WaitForExit();
break;
}
/*...*/
}
Debug.WriteLine("============== 3");
SendCommmandParser("..break..");
}
catch
{
}
#endregion
Debug.WriteLine("============== 4");
//... handling OK, CANCEL, ERROR
}
このフリーズを引き起こす構造的な問題を誰かが見つけることができますか? (実際、エラーなしで 2 回の変換を実行しましたが、コードは変更していません)
ご協力いただきありがとうございます。
~ADD~ フリーズランが発生し、デバッガーが を出力しない"============== #"
ため、解析スレッドが実際にフリーズしました... しかし、なぜですか?