2013-10-03 10 views
5

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

は、私のコードの一部です:

VlcWidget.h

QthreadPoolを使用して
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; 
     } 
    } 

私のソリューションは、ように見えた:

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(); 
    } 

そして、 AsyncVlcPl ay :: run()は、VlcWidget :: Play()が単純なロックを追加した場合とまったく同じ動作をします。また、VlcWidget :: Stop()にも同様のクラスが必要です。私は達成しようとしているものに対して2つの新しいクラスが本当に必要ではないので、私はこの解決策が嫌いです。それより悪い点は、VlcWidgetsプライベートメンバーを別のクラスのオブジェクトに渡す必要があるということです。私はあなたに気づいていない非常に簡単な方法があると確信しています。皆さんのうちの一人が私を助けてくれることを願っています。ありがとう!

(実際には、私は本当に別のスレッド上にある)(再生:: VlcWidgetは必要ありませんが、私はプレーを続けると対称を停止したい)

+0

たぶん[QtConcurrent](HTTP ://qt-project.org/doc/qt-4.8/qtconcurrentrun.html)があなたが探しているものです。 – thuga

+0

@thuga - ありがとう!それはまさに私が探していたものです:) – Kulki

+0

QtConcurrentを使うつもりなら、まずこれをお読みください:http://comments.gmane.org/gmane.comp.lib.qt.devel/7942 – TheDarkKnight

答えて

0

私はあなたがラムダを使用することに興味があると思うの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)); 
} 

に強調しSWI-Prologの構文を連結するためのコードの私(の一部)である...

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に停止を呼び出すと仮定すると、 VlcObjectのStopVlc関数に: - :

connect(pThread, &QThread::finished, pThread, &Qthread::deleteLater); 
-

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

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

+1

私は、あなたがヒープ上にスレッドを作成し、deleteLaterスロットに接続した後にそのすべてを忘れる部分が大好きです!私はあなたがそれを行うことができるとは考えていませんでした(私は今Qtでわずか1週間前です)。 – Kulki

+0

そして、 - > moveToThreadは、将来、pVlcObjが行うすべてのことが新しいスレッドになることを意味しますか?それはおそらく私が望むものではありません。 – Kulki

+0

@Kulki pVlcObjにシグナルを追加し、それらを接続して別のスレッドのスロットをトリガーさせることができます –

関連する問題