libVLC 事件机制

1.简介

libVLC是一个开源的多媒体框架,它提供了丰富的功能,其中包括一个灵活且强大的事件机制。在libVLC中,事件机制主要用于通知应用程序有关播放、媒体状态更改或其他重要事件的信息。

libVLC的事件模型基于订阅-发布模式,主要包含以下关键组件:

  • 事件类型(libvlc_event_type_t):定义了一系列预定义的事件,如媒体打开、播放、暂停、停止、结束等。

  • 事件管理器(libvlc_event_manager_t):每个libVLC对象(如媒体播放器、媒体列表等)都有一个关联的事件管理器,用于注册和触发事件。

  • 注册事件监听器(libvlc_event_attach):应用程序通过调用此函数来订阅特定类型的事件,并提供一个回调函数,当该事件发生时,libVLC会调用这个回调函数。

  • 事件解注册(libvlc_event_detach):当不再需要监听某个事件时,可以调用此函数取消对该事件的订阅。

2.事件的类型

enum libvlc_event_e {
    /* Append new event types at the end of a category.
     * Do not remove, insert or re-order any entry.
     * Keep this in sync with lib/event.c:libvlc_event_type_name(). */
    libvlc_MediaMetaChanged=0,
    libvlc_MediaSubItemAdded,
    libvlc_MediaDurationChanged,
    libvlc_MediaParsedChanged,
    libvlc_MediaFreed,
    libvlc_MediaStateChanged,
    libvlc_MediaSubItemTreeAdded,

    libvlc_MediaPlayerMediaChanged=0x100,
    libvlc_MediaPlayerNothingSpecial,
    libvlc_MediaPlayerOpening,
    libvlc_MediaPlayerBuffering,
    libvlc_MediaPlayerPlaying,
    libvlc_MediaPlayerPaused,
    libvlc_MediaPlayerStopped,
    libvlc_MediaPlayerForward,
    libvlc_MediaPlayerBackward,
    libvlc_MediaPlayerEndReached,
    libvlc_MediaPlayerEncounteredError,
    libvlc_MediaPlayerTimeChanged,
    libvlc_MediaPlayerPositionChanged,
    libvlc_MediaPlayerSeekableChanged,
    libvlc_MediaPlayerPausableChanged,
    libvlc_MediaPlayerTitleChanged,
    libvlc_MediaPlayerSnapshotTaken,
    libvlc_MediaPlayerLengthChanged,
    libvlc_MediaPlayerVout,
    libvlc_MediaPlayerScrambledChanged,
    libvlc_MediaPlayerESAdded,
    libvlc_MediaPlayerESDeleted,
    libvlc_MediaPlayerESSelected,
    libvlc_MediaPlayerCorked,
    libvlc_MediaPlayerUncorked,
    libvlc_MediaPlayerMuted,
    libvlc_MediaPlayerUnmuted,
    libvlc_MediaPlayerAudioVolume,
    libvlc_MediaPlayerAudioDevice,
    libvlc_MediaPlayerChapterChanged,

    libvlc_MediaListItemAdded=0x200,
    libvlc_MediaListWillAddItem,
    libvlc_MediaListItemDeleted,
    libvlc_MediaListWillDeleteItem,
    libvlc_MediaListEndReached,

    libvlc_MediaListViewItemAdded=0x300,
    libvlc_MediaListViewWillAddItem,
    libvlc_MediaListViewItemDeleted,
    libvlc_MediaListViewWillDeleteItem,

    libvlc_MediaListPlayerPlayed=0x400,
    libvlc_MediaListPlayerNextItemSet,
    libvlc_MediaListPlayerStopped,

    /**
     * \deprecated Useless event, it will be triggered only when calling
     * libvlc_media_discoverer_start()
     */
    libvlc_MediaDiscovererStarted=0x500,
    /**
     * \deprecated Useless event, it will be triggered only when calling
     * libvlc_media_discoverer_stop()
     */
    libvlc_MediaDiscovererEnded,

    libvlc_RendererDiscovererItemAdded,
    libvlc_RendererDiscovererItemDeleted,

    libvlc_VlmMediaAdded=0x600,
    libvlc_VlmMediaRemoved,
    libvlc_VlmMediaChanged,
    libvlc_VlmMediaInstanceStarted,
    libvlc_VlmMediaInstanceStopped,
    libvlc_VlmMediaInstanceStatusInit,
    libvlc_VlmMediaInstanceStatusOpening,
    libvlc_VlmMediaInstanceStatusPlaying,
    libvlc_VlmMediaInstanceStatusPause,
    libvlc_VlmMediaInstanceStatusEnd,
    libvlc_VlmMediaInstanceStatusError
};

找几个常用的事件,如下所示。

switch (ev->type) {
	case libvlc_MediaPlayerTimeChanged:
		qDebug() << "VLC媒体播放器时间已更改";
		break;
	case libvlc_MediaPlayerEndReached:
		qDebug() << "VLC播放完毕.";
		break;
	case libvlc_MediaPlayerStopped:
		qDebug() << "VLC停止播放";
		break;
	case libvlc_MediaPlayerPlaying:
		qDebug() << "VLC开始播放";
		break;
	case libvlc_MediaPlayerPaused:
		qDebug() << "VLC暂停播放";
		break;
	}

3.代码示例

#pragma once

#include <QtWidgets/QWidget>
#include "ui_showWidget.h"
#include <QMenu>
#include <QActionGroup>
#include <vlc/vlc.h>
#include <QDebug>
#include <QFileDialog>
#include <QThread>

class showWidget : public QWidget
{
    Q_OBJECT

public:
    showWidget(QWidget *parent = nullptr);
    ~showWidget();

private slots:
	void slotOpenFile();
	void slotPlay();

private:
	//事件处理回调
	static void vlcEvents(const libvlc_event_t *ev, void *param);

private:
    Ui::showWidgetClass ui;

private:
	libvlc_instance_t *vlc_base = nullptr;
	libvlc_media_t *vlc_media = nullptr;
	libvlc_media_player_t *vlc_mediaPlayer = nullptr;
};



#include "showWidget.h"
#include <QTimer>

#pragma execution_character_set("utf-8")

showWidget::showWidget(QWidget *parent)
    : QWidget(parent)
{
    ui.setupUi(this);

	this->setWindowTitle("视频播放器");

	connect(ui.btnOpen, &QPushButton::clicked, this, &showWidget::slotOpenFile);
	connect(ui.btnPlay, &QPushButton::clicked, this, &showWidget::slotPlay);
}

showWidget::~showWidget()
{
	libvlc_release(vlc_base); //减少libvlc实例的引用计数,并销毁
}

void showWidget::slotOpenFile()
{
	/*选择文件*/
	QString filename = QFileDialog::getOpenFileName(this, "选择打开的文件", "D:/", tr("*.*"));
	std::replace(filename.begin(), filename.end(), QChar('/'), QChar('\\'));
	vlc_base = libvlc_new(0, NULL);
	vlc_media = libvlc_media_new_path(vlc_base, filename.toUtf8().data());
	if (!vlc_media) {
		return;
	}

	// 创建libvlc实例和媒体播放器
	vlc_mediaPlayer = libvlc_media_player_new_from_media(vlc_media);
	if (!vlc_mediaPlayer) {
		return;
	}
	libvlc_media_parse(vlc_media);

	//获取事件管理器
	libvlc_event_manager_t *em = libvlc_media_player_event_manager(vlc_mediaPlayer);

	// 注册事件监听器
	libvlc_event_attach(em, libvlc_MediaPlayerTimeChanged, vlcEvents, this);
	libvlc_event_attach(em, libvlc_MediaPlayerEndReached, vlcEvents, this);
	libvlc_event_attach(em, libvlc_MediaPlayerStopped, vlcEvents, this);
	libvlc_event_attach(em, libvlc_MediaPlayerPlaying, vlcEvents, this);
	libvlc_event_attach(em, libvlc_MediaPlayerPaused, vlcEvents, this);

	libvlc_media_player_set_hwnd(vlc_mediaPlayer, (void *)ui.widgetShow->winId());

	QTimer::singleShot(1000, this, &showWidget::slotPlay);

}

void showWidget::slotPlay()
{
	libvlc_media_player_play(vlc_mediaPlayer);
}

//事件回调
void showWidget::vlcEvents(const libvlc_event_t *ev, void *param)
{
	//处理不同的事件
	qint64 pos;
	switch (ev->type) {
	case libvlc_MediaPlayerTimeChanged:
		qDebug() << "VLC媒体播放器时间已更改";
		break;
	case libvlc_MediaPlayerEndReached:
		qDebug() << "VLC播放完毕.";
		break;
	case libvlc_MediaPlayerStopped:
		qDebug() << "VLC停止播放";
		break;
	case libvlc_MediaPlayerPlaying:
		qDebug() << "VLC开始播放";
		break;
	case libvlc_MediaPlayerPaused:
		qDebug() << "VLC暂停播放";
		break;
	}
}

上一篇:设计模式之状态模式


下一篇:移动无线信道衰落原因、分类及补偿技术