5

Qt を使用して同時に実行される複数の libVlc インスタンスを埋め込むアプリを作成しています。Qt の GUI スレッドから呼び出されると libvlc_media_player_stop がデッドロックすることがある vlc ライブラリにバグがあるようです。videolan フォーラムの 1 つで受け入れられた解決策は、別のスレッドから stop 関数を呼び出すことでした。私は、別のスレッドから停止を呼び出すための、最も関与が少なく、あまり醜くない方法を探しています。この種の状況を正確に意味する QThreadPool の使用を検討しましたが、私の特定のケースでは、解決策がうまくいきません。

これが私のコードの一部です:

VlcWidget.h

    class VlcWidget : public QWidget
    {
        Q_OBJECT

    private:

        // State
        bool _isPlaying;

        // The streaming source, title and quality data
        VideoData _videoData;
        VIDEO_QUALITY _quality;

        // LibVlc related members
        libvlc_instance_t *_vlcInstance;
        libvlc_media_player_t *_vlcMediaPlayer;
        libvlc_media_t *_vlcMedia;
        int _vlcTrackID;
    }

VlcWidget.c

    void VlcWidget::Play()
    {
        if(_videoData.Source() != "" && !_isPlaying)
        {
            // Create a new media descriptor
            _vlcMedia = libvlc_media_new_location(
                          _vlcInstance,
                          _videoData.Source().toStdString().c_str());

            // Tell the user about incorrect URL
            if(_vlcMedia == NULL)
            {
                QMessageBox::information(this,
                                         _videoData.Title(),
                                         "Unable to open source Url.\nPlease check the source and try again.");
                return;
            }

            libvlc_media_player_set_media(_vlcMediaPlayer, _vlcMedia);
            libvlc_media_release(_vlcMedia);
            libvlc_media_player_set_xwindow(_vlcMediaPlayer, parentWidget()->winId());
            libvlc_media_player_play(_vlcMediaPlayer);
            _vlcTrackID = libvlc_audio_get_track(_vlcMediaPlayer);
            _isPlaying = true;
        }
    }

    void VlcWidget::Stop()
    {
        if(_isPlaying)
        {
            libvlc_media_player_stop(_vlcMediaPlayer);
            _vlcTrackID = -1;
            _isPlaying = false;
        }
    }

QthreadPool を使用した私のソリューションは次のようになりました。

    class AsyncVlcPlay : public QRunnable
    {
    private:
         // State
        bool *_isPlaying;

        // LibVlc related members
        libvlc_instance_t *_vlcInstance;
        libvlc_media_player_t *_vlcMediaPlayer;
        libvlc_media_t *_vlcMedia;
        int *_vlcTrackID;

    public:
        virtual void run();
    }

そして、AsyncVlcPlay::run() は、VlcWidget::Play() が単純なロックを追加して行うこととまったく同じことを行います。また、VlcWidget::Stop() にも同様のクラスが必要です。私が達成しようとしていることのために2つの新しいクラスを本当に必要とするべきではないので、私はこの解決策が好きではありません。さらに悪いことに、VlcWidgets プライベート メンバーを別のクラスのオブジェクトに渡さなければなりません。私が気付いていない非常に簡単な方法があると確信しており、あなたの一人がここで私を助けてくれることを願っています. ありがとう!

(実際、VlcWidget::Play() を別のスレッドに配置する必要はありませんが、Play と Stop の対称性を維持したいと考えています)

4

2 に答える 2

1

私は QThread でこの問題に取り組みます。実際にはスレッドではなく、スレッドコントローラーであり、非常に使いやすいため、その名前は実際には誤解を招きます。

QObject から継承された任意のクラスをスレッドに移動することができ、スレッド間の通信はシグナル/スロット メカニズムで行うことができます。したがって、次のようなことができます: -

class VlcObject : public QObject
{
    Q_OBJECT

    public slots:
        void Run();

    private slots;
        void StopVlc();
};

このクラスには、すべての Vlc オブジェクト / インスタンスを含めることができます。次に、スレッド コントローラ オブジェクトを作成し、VlcObject インスタンスを新しいスレッドに移動します。

QThread* pThread = new QThread(this); // where this is a parent, running on the main thread
VlcObject* pVlcObj = new VlcObject;

pVlcObj->moveToThread(pThread);

// Note, this is Qt 5 connect style - Qt 4 connections also work
connect(pThread, &QThread::started, pVlcOj, &VlcObject::Run();

// Start the thread running
pThread->start();

QVlcWidget が pStopVlc というボタンを持つ GUI クラスであると仮定すると、ボタンを VlcObject の StopVlc 関数に接続して、他のスレッドの VlcObject で停止を呼び出します。

connect(pStopVlc, &QPushButton::released, pVlcObj, &VlcObject::StopVlc);

または、スレッドが終了したときに StopVlc を呼び出し、QThread が停止したときにそれ自体をクリーンアップすることができます。

connect(pThread, &QThread::finished, pThread, &Qthread::deleteLater);
于 2013-10-04T09:44:10.340 に答える
0

SWI-Prolog構文の強調表示をQtに結合するための私の(一部の)コードは次のとおりです

// start highlighting, using SWI-Prolog syntax analyzer to collect structured data
//
void pqSource::startHighliter() {
    auto f = [](QString file, pqSyntaxData* psd) {
        SwiPrologEngine::in_thread _it;
        try {
            // ?? PlCall("consult", V(A(file)));
            qDebug() << "running syntax color on" << file << "thread" << CT;
            int rc = PlCall("syncol", PlTermv(A(file), PlTerm(psd)));
            qDebug() << "syncol" << rc;
        }
        catch(PlException e) {
            qDebug() << t2w(e);
        }
    };

    // collect structure asyncronously
    auto w = new QFutureWatcher<void>;
    connect(w, SIGNAL(finished()), this, SLOT(runHighliter()));

    // since could be a slow task, place a visual hint to what's going on...
    CenterWidgets((sd = new pqSyntaxData)->pgb = new QProgressBar(this));
    QTextCursor c = textCursor();
    c.movePosition(c.End);
    sd->pgb->setMaximum(c.position());
    connect(sd, SIGNAL(onProgress(int)), sd->pgb, SLOT(setValue(int)));
    sd->pgb->show();

    // run the Prolog snippet in background (hl pointer)
    w->setFuture(QtConcurrent::run(f, file, sd));
}

ラムダの使用に興味があると思います...

于 2013-10-04T11:17:43.987 に答える