libVLC 捕获鼠标、键盘事件

在实现播放器的时候,我们需要捕获键盘、鼠标事件进行视频快进、快退,或者双击全屏/退出全屏窗口、鼠标右键弹出菜单栏。默认情况下,在使用libVLC库的时候,我们无法捕获这些事件,因为我们将Qt的视频窗口传递给了libVLC。

cpp 复制代码
libvlc_media_player_set_hwnd(vlc_mediaPlayer, (void *)ui.widgetShow->winId());

但是libVLC提供了两个接口,使得忽略了对鼠标键盘事件的处理,让事件返回到原始Qt的widget上。

cpp 复制代码
	libvlc_video_set_mouse_input(vlc_mediaPlayer, 0);
	libvlc_video_set_key_input(vlc_mediaPlayer, 0);

好了,知道了如何操作了之后,下面开始实现代码。

首先打开文件的时候禁用鼠标、键盘事件,并且设置视频窗口为Qt的Widget控件,libvlc_media_player_set_hwnd。

cpp 复制代码
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);

	m_defalutRate = libvlc_video_get_aspect_ratio(vlc_mediaPlayer);
	m_defalutCrop = libvlc_video_get_crop_geometry(vlc_mediaPlayer);

	libvlc_video_set_mouse_input(vlc_mediaPlayer, 0);
	libvlc_video_set_key_input(vlc_mediaPlayer, 0);

	// 获取各种元数据
	const char *title = libvlc_media_get_meta(vlc_media, libvlc_meta_Title);
	const char *artist = libvlc_media_get_meta(vlc_media, libvlc_meta_Artist);
	const char *album = libvlc_media_get_meta(vlc_media, libvlc_meta_Album);
	const char *url = libvlc_media_get_meta(vlc_media, libvlc_meta_URL);
	const char *date = libvlc_media_get_meta(vlc_media, libvlc_meta_Date);
	const char *lang = libvlc_media_get_meta(vlc_media, libvlc_meta_Language);
	int duration = libvlc_media_get_duration(vlc_media);  // 获取时长(单位:毫秒)

	qDebug("Title: %s", title ? title : "N/A");
	qDebug("Artist: %s", artist ? artist : "N/A");
	qDebug("Album: %s", album ? album : "N/A");
	qDebug("Duration: %d ms", duration);
	qDebug("url: %s", url ? url : "N/A");
	qDebug("date: %s", date ? date : "N/A");
	qDebug("lang: %s", lang ? lang : "N/A");
	
	libvlc_media_track_t **tracks;
	int track_count = libvlc_media_tracks_get(vlc_media,&tracks);
	for (unsigned i = 0; i < track_count; i++) 
	{
		libvlc_media_track_t* track = tracks[i];

		// 显示轨道信息
		printf("Track #%u: %s\n", i, track->psz_description);

		// 这里可以获取到每一个轨道的信息,比如轨道类型 track->i_type
		// 可能是 libvlc_track_video, libvlc_track_audio 或者 libvlc_track_text (字幕)

		if (track->i_type == libvlc_track_video) {
			// 处理视频轨道信息
			qDebug("width = %d",track->video->i_width);
			qDebug("height = %d", track->video->i_height);
			qDebug("rate_num = %d", track->video->i_frame_rate_num);
			qDebug("rate_den = %d", track->video->i_frame_rate_den);
		}
		else if (track->i_type == libvlc_track_audio) {
			// 处理音频轨道信息
			qDebug("channels = %d", track->audio->i_channels);
			qDebug("rate = %d", track->audio->i_rate);
		}
		else if (track->i_type == libvlc_track_text) {
			// 处理字幕轨道信息
		}
	}

	//获取事件管理器
	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);
}

然后鼠标右键显示菜单:

代码实现:

cpp 复制代码
	//.h
    QMenu *m_menu = nullptr;
	QAction *m_video = nullptr;

	QAction *m_scaleAction = nullptr;	//缩放
	QAction *m_aspectRatioAction = nullptr;	//宽高比
	QAction *m_cropAction = nullptr;	//裁剪

	QMenu *m_videoMenu = nullptr;
    
    //.cpp
    //总菜单
	m_menu = new QMenu(this);
	m_video = m_menu->addAction("视频");

	//视频菜单
	m_videoMenu = new QMenu(this);
	m_scaleAction = m_videoMenu->addAction("缩放");
	m_aspectRatioAction = m_videoMenu->addAction("宽高比");
	m_cropAction = m_videoMenu->addAction("裁剪");

	m_video->setMenu(m_videoMenu);

	//宽高比菜单
	m_aspectRatioMenu = new QMenu(this);
	m_aspectRatioAction->setMenu(m_aspectRatioMenu);



    

重写鼠标和键盘事件。

cpp 复制代码
protected:
	virtual void mousePressEvent(QMouseEvent *event);
	virtual void mouseDoubleClickEvent(QMouseEvent *event);
	virtual void keyPressEvent(QKeyEvent *event);

鼠标双击全屏。

cpp 复制代码
void showWidget::mouseDoubleClickEvent(QMouseEvent *event)
{
	if (this->isFullScreen())
	{
		this->showNormal();
	}
	else
	{
		this->showFullScreen();
	}
}

键盘事件:调节W、S键音量大小和space键暂停和播放。

cpp 复制代码
void showWidget::keyPressEvent(QKeyEvent *event)
{
	if (!vlc_mediaPlayer)
		return;

	int value = ui.hSliderVolumn->value();
	if (event->key() == Qt::Key_W)	//添加音量
	{
		qDebug() << "up";
		slotValueChanged(value+10);
	}
	else if (event->key() == Qt::Key_S)	//减小音量
	{
		slotValueChanged(value - 10);
	}
	else if (event->key() == Qt::Key_Space)
	{
		if (vlc_mediaPlayer && libvlc_media_player_get_state(vlc_mediaPlayer) == libvlc_Playing)
		{
			libvlc_media_player_pause(vlc_mediaPlayer);
		}
		else if (vlc_mediaPlayer && libvlc_media_player_get_state(vlc_mediaPlayer) == libvlc_Paused)
		{
			libvlc_media_player_play(vlc_mediaPlayer);
		}
	}
}


void showWidget::slotValueChanged(int value)
{
	if (vlc_mediaPlayer)
		libvlc_audio_set_volume(vlc_mediaPlayer, value);
}

鼠标点击弹出菜单。

cpp 复制代码
void showWidget::mousePressEvent(QMouseEvent *event)
{
	switch (event->button())
	{
	case Qt::RightButton:
		//this->setWindowState(Qt::WindowMinimized);
		m_menu->exec(event->globalPos());
		break;
	default:
		QWidget::mousePressEvent(event);
	}
}

更多参考:

libVLC 事件机制-CSDN博客

libVLC windows开发环境搭建-CSDN博客

https://sunnnnnn666.blog.csdn.net/article/details/136854500

libVLC 元数据-CSDN博客

libVLC 添加图片和文本水印-CSDN博客

https://sunnnnnn666.blog.csdn.net/article/details/136920169

https://sunnnnnn666.blog.csdn.net/article/details/137023036

相关推荐
RTC实战笔记1 天前
实时互动数字人怎么做,才不是一个只会说话的视频?
音视频·数字人·rtc·数字人接入
用户805533698033 天前
不止三件套:QObject 属性系统全关键字与运行时反射!
c++·qt
xcyxiner3 天前
DicomViewer (vcpkg Windows和ubuntu编译)7
qt
Quz8 天前
QML Hello World 入门示例
qt
xcyxiner11 天前
DicomViewer (dcmtk读取dcm文件)5
qt
xcyxiner11 天前
DicomViewer (后台线程处理文件)4
qt
xcyxiner12 天前
DicomViewer (添加模型类)3
qt
xcyxiner12 天前
DicomViewer (目录调整) 2
qt
xcyxiner12 天前
dcmtk vtk vtk-dicom(gdcm) 编译(debug) v2
qt
RTC实战笔记13 天前
Android 实时音视频接入教程:媒体补充增强信息(SEI)
音视频·媒体·rtc