5
  • プラットフォーム: Qt 4.8.2、Win 7

次のロジック フローを検討してください。

1. App started
2. functionA() triggered
3. the app periodically capture some images to external files
4. end of functionA()
5. the app create a video from captured images, using ffmpeg as external program
6. [step 2 -> step 5] may be repeated.
7. App quit

フローを実現するために、QProcess を使用して外部プログラムを起動し、画像を結合しましたが、QProcess の適切な使用パターンに混乱しました。(ffmpeg のコンソール メッセージは気にしません。ビデオ ファイルが作成されているかどうかを確認することで、ステップ 5 の成功を判断します。)

試行 1

void MyWidget::createAVI()
{
    checkAndDeleteAVI();
    process = new QProcess(this); // process_ defined as class member;
    process->start("ffmpeg -f images2 ....");
    process->waitForFinished(-1);  // (a)
    // (b)
}

(a) で、この呼び出しでメイン GUI がフリーズする可能性があるドキュメントを読みました。QThread/QRunnable から呼び出す必要がありますか?

(b) で、ここで何か見逃していますか? アプリを閉じようとすると (フローのステップ 7)、アプリがクラッシュし、生成された QProcess が適切に解放されていないと思いました。

試行 2

QProcess のラッパー クラスを次のように記述しました。

Launcher.h

class Launcher : public QObject
{
    Q_OBJECT
public:
    /** constructor */
    explicit Launcher(QObject *parent = 0);
    /** destructor */
    ~Launcher() {
        if (started_ && process_->state() != QProcess::NotRunning)
            process_->kill();
    } // end_dtor(Launcher)
Q_SIGNALS:
    void feedbackLog(QString log);
public Q_SLOTS:
    void launch(QString program, QStringList argList);
private:
    QProcess * process_;
    bool started_;
private Q_SLOTS:
    void error(QProcess::ProcessError error);
    void finished(int exitCode, QProcess::ExitStatus status);
    void stateChanged(QProcess::ProcessState state);
}; // end_class(Launcher)

#endif // LAUNCHER_H

ランチャー.cpp

#include "launcher.h"
#include <QCoreApplication>
#include <QtDebug>

Launcher::Launcher(QObject *parent) : QObject(parent), started_(false)
{
    process_ = new QProcess(this);
    connect(process_,
            SIGNAL(error(QProcess::ProcessError)),
            SLOT(error(QProcess::ProcessError)));
    connect(process_,
            SIGNAL(finished(int, QProcess::ExitStatus)),
            SLOT(finished(int, QProcess::ExitStatus)));
    connect(process_,
            SIGNAL(stateChanged(QProcess::ProcessState)),
            SLOT(stateChanged(QProcess::ProcessState)));
} // end_ctor(ExternalLauncher)

void Launcher::launch(QString program, QStringList argList)
{
    started_ = true;
    process_->start(program, argList);
    process_->waitForFinished(-1); // (c)
    Q_EMIT feedbackLog(process_->readAllStandardOutput());
    process_->close();
} // end Launcher::launch()

void Launcher::error(QProcess::ProcessError error)
{
    /* just feedback some text about the error */
} // end_slot(Launcher::error)

void Launcher::finished(int exitCode, QProcess::ExitStatus status)
{
    started_ = false;
    /* feedback some text about finished */
} // end_slot (Launcher::finished)

void Launcher::stateChanged(QProcess::ProcessState state)
{
    qDebug() << "Luancher::stateChanged" << state;
}

ランチャーの使い方:

void MyWidget::createAVI()
{
    checkAndDeleteAVI();
    launcher_.launch("ffmpeg", "argsList"); // launcher_ defined as class member;
}

では、(c) では、waitForFinished() は不要でしょうか? (QProcessのwaitForXXX()とシグナル/スロットフレームワークを混同してはならないという情報を読んだので)

また、このアプローチを使用するとアプリのクラッシュも発生するため、Launcher クラスで見逃したものはありますか。

主な質問: 一般に、いつ QProcess::terminate() / QProcess::kill() を呼び出し、いつ QProcess オブジェクトを削除するのですか?

ありがとう

4

1 に答える 1