0

別の質問で、プログレスバーなどを備えた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~ フリーズランが発生し、デバッガーが を出力しない"============== #"ため、解析スレッドが実際にフリーズしました... しかし、なぜですか?

4

1 に答える 1

0

マシューのおかげでApplication.DoEvents()、フリーズが発生したようです。理由はわかりませんが、コードを完全に再編成したので、メイン GUI は変換要求を に送信しBlockingCollection<>、新しいスレッドによって処理されます。

ウィンドウがフリーズしないようにするために、main-gui-thread でウィンドウを初期化し、作業スレッドからInvokes で更新しました。

別のプロジェクトを再編成するのは大変でした。なぜなら、メイン フォームは、成功することを条件としてさまざまな変換を呼び出していたからです。しかし、実際には機能します。

そして、私が知っている将来のために:クラスの1回の呼び出しだけで集中的な作業を呼び出すだけで、後の並列化が容易になります;)

于 2013-05-17T19:20:21.850 に答える