How to implement loop feature in libVLC play video with Qt in c++

LibVLC doesn't have an option for looping a video, because it is thought to be a feature that GUI should implement, not a library itself, to which I agree. Loop is just "play again" function which can be completed if play function and stop events are implemented in library, which they are.

What you should basically do is to play again after you received stop event (defined as libvlc_MediaPlayerEndReached ). The way events are handled in libVLC you will probably end up catching event in static member function, from where you cannot call member functions as of within the object itself (they do not have an access to "this " pointer of the object) and they are not thread-safe.

First problem can be avoided simply by putting "this" pointer to vlc event handler and cast it back from void* to original class pointer in the callback function.

The Play() and Stop() functions are made public in the MyClass class, and real libvlc stop and play APIs are called there. Second problem is now the static function not being thread-safe and thus you cannot just call play and stop APIs, although they are called from within class' own non-static functions. Such implementation crashes the application.

To make sure those two functions are called from within the same thread you can implement slot/signal functionality of Qt. First you create stop/play slots in MyClass and move stop/play API calls to those slots. Then create play/stop signals in MyClass and just emit them in Stop() and Play() functions. This way you only leave an option to emit signals to any thread-unsafe calls. Signals are thread-safe if used like this (that is with no pointers to data). Finally you just have to connect signals and slots in the constructor of the MyClass itself.

The following sample code is for demonstration purposes only, it might not work or even compile:

Declaration:


class MyClass : public QWidget
{
  Q_OBJECT
public:
  MyClass();
  virtual ~MyClass();
  void OpenFile( char* source );
  // publicly available functions
  void Stop();
  void Play();
private:
  Ui::MyClass widget;
  libvlc_media_player_t* m_player;
  libvlc_media_t* m_media;
  libvlc_instance_t* m_inst;
  // event manager
  libvlc_event_manager_t *m_eventMgr;
  // event handler callback
  static void vlcEvent(const libvlc_event_t* event, void* vlcvideo_object);
signals:
  void signalPlay();
  void signalStop();
  private slots:
  void slotPlay();
  void slotStop();
};

Implementation:


MyClass::MyClass()
{
  widget.setupUi(this);
  m_inst = CVlcInstance::Instance(); // singleton vlc object
  m_media = NULL;
  m_player = NULL;
  m_eventMgr = NULL;
  // connect play signals to play slot functions on the same (this) object
  connect(this, SIGNAL(signalPlay()), this, SLOT(slotPlay()) );
  connect(this, SIGNAL(signalStop()), this, SLOT(slotStop()) );
}

MyClass::~MyClass()
{
}

void MyClass::OpenFile( char* source )
{
  m_media = libvlc_media_new (m_inst, source, CVlcInstance::getException() );
  m_player = libvlc_media_player_new_from_media (m_media, CVlcInstance::getException() );
  m_eventMgr = libvlc_media_player_event_manager( m_player, CVlcInstance::getException() );
  // attach event to defined event handler callback
  libvlc_event_attach( m_eventMgr, libvlc_MediaPlayerEndReached, vlcEvent, this, CVlcInstance::getException() );
}

void MyClass::Stop()
{
  // in publicly available function just emit the signal, don't call libVLC API
  emit signalStop();
}

void MyClass::Play()
{
  // in publicly available function just emit the signal, don't call libVLC API
  emit signalPlay();
}

void MyClass::vlcEvent(const libvlc_event_t* event, void* vlcvideo_object)
{
  // this check is not needed, because the event manager has linked this callback to
  // this specific event, but I'll leave it here for demo
  if( event->type == libvlc_MediaPlayerEndReached )
  {
    MyClass* player = (MyClass*)vlcvideo_object;
    // call publicly availabe play function that actually emits signal from within the object
    player->Play();
  }
}

void MyClass::slotPlay()
{
  // finally call libVLC API
  libvlc_media_player_play(m_player, CVlcInstance::getException());
}

void MyClass::slotStop()
{
  // finally call libVLC API
  libvlc_media_player_stop(m_player, CVlcInstance::getException());
}


Previous: Build application linked with static Qt library in Windows
Next: Refactoring code that uses libvlc 1.0 to using libvlc 1.1