libVLC 设置视频宽高比

宽高比是指视频图像的宽度和高度之间的比率。

投影屏幕尺寸一般都按照对角线的大小来定义的。根据图像制式不同,屏幕的长宽比例也有几种格式:

传统影视的宽高比是 4:3,宽屏幕电影的宽高比是 1.85:1,高清晰度电视是 16:9,全景式格式电影是 2.35:1。

以下是VLC播放器中使用的宽高比,我们仿照这个宽高比例做一个界面。

使用libvlc_video_set_aspect_ratio设置视频宽高比。

首先做一个菜单:

cpp 复制代码
	//.h
    QMenu *m_menu = nullptr;
	QAction *m_default = nullptr;
	QAction *m_16_9 = nullptr;
	QAction *m_4_3 = nullptr;
	QAction *m_1_1 = nullptr;
	QAction *m_16_10 = nullptr;
	QAction *m_2_21_1 = nullptr;
	QAction *m_2_35_1= nullptr;
	QAction *m_2_38_1 = nullptr;
	QAction *m_5_4 = nullptr;

	QActionGroup *m_group = nullptr;


    //.cpp
    m_menu = new QMenu(this);
	m_default = m_menu->addAction("默认");
	m_16_9 = m_menu->addAction("16:9");
	m_4_3 = m_menu->addAction("4:3");
	m_1_1 = m_menu->addAction("1:1");
	m_16_10 = m_menu->addAction("16:10");
	m_2_21_1 = m_menu->addAction("2.21:1");
	m_2_35_1 = m_menu->addAction("2.35:1");
	m_2_38_1 = m_menu->addAction("2.38:1");
	m_5_4 = m_menu->addAction("5:4");

	m_group = new QActionGroup(this);
	m_group->addAction(m_default);
	m_group->addAction(m_16_9);
	m_group->addAction(m_4_3);
	m_group->addAction(m_1_1);
	m_group->addAction(m_16_10);
	m_group->addAction(m_2_21_1);
	m_group->addAction(m_2_35_1);
	m_group->addAction(m_2_38_1);
	m_group->addAction(m_5_4);

	connect(m_group, &QActionGroup::triggered, this, &showWidget::slotActionTriggered);

接受槽函数的响应事件:

cpp 复制代码
void showWidget::slotActionTriggered(QAction *action)
{
	if (!vlc_mediaPlayer)
		return;

	if (action == m_default)
		libvlc_video_set_aspect_ratio(vlc_mediaPlayer,m_defalutRate);
	else if(action == m_16_9)
		libvlc_video_set_aspect_ratio(vlc_mediaPlayer, "16:9");
	else if (action == m_4_3)
		libvlc_video_set_aspect_ratio(vlc_mediaPlayer, "4:3");
	else if (action == m_1_1)
		libvlc_video_set_aspect_ratio(vlc_mediaPlayer, "1:1");
	else if (action == m_16_10)
		libvlc_video_set_aspect_ratio(vlc_mediaPlayer, "16:10");
	else if (action == m_2_21_1)
		libvlc_video_set_aspect_ratio(vlc_mediaPlayer, "221:100");
	else if (action == m_2_35_1)
		libvlc_video_set_aspect_ratio(vlc_mediaPlayer, "235:100");
	else if (action == m_2_38_1)
		libvlc_video_set_aspect_ratio(vlc_mediaPlayer, "238:100");
	else if (action == m_5_4)
		libvlc_video_set_aspect_ratio(vlc_mediaPlayer, "5:4");
}

设置鼠标右键弹出菜单:重写鼠标点击事件。

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

完整代码:

cpp 复制代码
#include "showWidget.h"
#include <QTimer>
#include <QTime>

#pragma execution_character_set("utf-8")

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

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

	ui.cbxRate->setCurrentIndex(Rate1_0X);

	m_lstRate << 2.0 << 1.5 << 1.25 << 1.0 << 0.75 << 0.5;

	m_menu = new QMenu(this);
	m_default = m_menu->addAction("默认");
	m_16_9 = m_menu->addAction("16:9");
	m_4_3 = m_menu->addAction("4:3");
	m_1_1 = m_menu->addAction("1:1");
	m_16_10 = m_menu->addAction("16:10");
	m_2_21_1 = m_menu->addAction("2.21:1");
	m_2_35_1 = m_menu->addAction("2.35:1");
	m_2_38_1 = m_menu->addAction("2.38:1");
	m_5_4 = m_menu->addAction("5:4");

	m_group = new QActionGroup(this);
	m_group->addAction(m_default);
	m_group->addAction(m_16_9);
	m_group->addAction(m_4_3);
	m_group->addAction(m_1_1);
	m_group->addAction(m_16_10);
	m_group->addAction(m_2_21_1);
	m_group->addAction(m_2_35_1);
	m_group->addAction(m_2_38_1);
	m_group->addAction(m_5_4);

	connect(m_group, &QActionGroup::triggered, this, &showWidget::slotActionTriggered);

	connect(ui.btnOpen, &QPushButton::clicked, this, &showWidget::slotOpenFile);
	connect(ui.btnPlay, &QPushButton::clicked, this, &showWidget::slotPlay);
	connect(ui.btnPause, &QPushButton::clicked, this, &showWidget::slotPause);
	connect(ui.btnStop, &QPushButton::clicked, this, &showWidget::slotStop);
	connect(ui.hSliderVolumn, &QSlider::valueChanged, this, &showWidget::slotValueChanged);
	connect(ui.cbxRate,SIGNAL(currentIndexChanged(int)), this, SLOT(slotCurrentIndexChanged(int)));
}

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

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

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

	// 获取各种元数据
	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) {
			// 处理字幕轨道信息
		}
	}

	 设置 logo 叠加
	//libvlc_video_set_logo_int(vlc_mediaPlayer, libvlc_logo_enable, 1);
	//libvlc_video_set_logo_string(vlc_mediaPlayer, libvlc_logo_file, "D:\\2.png");
	libvlc_video_set_logo_int(vlc_mediaPlayer, libvlc_logo_position, libvlc_position_top_left);
	//libvlc_video_set_logo_int(vlc_mediaPlayer, libvlc_logo_x, 100);
	//libvlc_video_set_logo_int(vlc_mediaPlayer, libvlc_logo_y, 0);
	//libvlc_video_set_logo_int(vlc_mediaPlayer, libvlc_logo_opacity, 255);
	//libvlc_video_set_logo_int(vlc_mediaPlayer, libvlc_logo_repeat, 1);

	 创建并设置水印文本
	//libvlc_video_set_marquee_int(vlc_mediaPlayer, libvlc_marquee_Enable, 1);
	//libvlc_video_set_marquee_int(vlc_mediaPlayer, libvlc_marquee_Position, libvlc_position_center);
	//libvlc_video_set_marquee_int(vlc_mediaPlayer, libvlc_marquee_Refresh, 2000);
	//libvlc_video_set_marquee_int(vlc_mediaPlayer, libvlc_marquee_Size, 24);
	//libvlc_video_set_marquee_string(vlc_mediaPlayer, libvlc_marquee_Text, "这里是水印文本");
	libvlc_video_set_marquee_int(w->vlc_mediaPlayer, libvlc_marquee_Timeout, 5000);
	//libvlc_video_set_marquee_int(vlc_mediaPlayer, libvlc_marquee_Opacity, 255); // 不透明

	//获取事件管理器
	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()
{
	if (vlc_mediaPlayer)
		libvlc_media_player_play(vlc_mediaPlayer);
}

void showWidget::slotPause()
{
	if (vlc_mediaPlayer)
		libvlc_media_player_pause(vlc_mediaPlayer);
}

void showWidget::slotStop()
{
	if (vlc_mediaPlayer)
		libvlc_media_player_stop(vlc_mediaPlayer);
}

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

void showWidget::slotCurrentIndexChanged(int index)
{
	if (vlc_mediaPlayer)
		libvlc_media_player_set_rate(vlc_mediaPlayer, m_lstRate[index]);
}

void showWidget::slotActionTriggered(QAction *action)
{
	if (!vlc_mediaPlayer)
		return;

	if (action == m_default)
		libvlc_video_set_aspect_ratio(vlc_mediaPlayer,m_defalutRate);
	else if(action == m_16_9)
		libvlc_video_set_aspect_ratio(vlc_mediaPlayer, "16:9");
	else if (action == m_4_3)
		libvlc_video_set_aspect_ratio(vlc_mediaPlayer, "4:3");
	else if (action == m_1_1)
		libvlc_video_set_aspect_ratio(vlc_mediaPlayer, "1:1");
	else if (action == m_16_10)
		libvlc_video_set_aspect_ratio(vlc_mediaPlayer, "16:10");
	else if (action == m_2_21_1)
		libvlc_video_set_aspect_ratio(vlc_mediaPlayer, "221:100");
	else if (action == m_2_35_1)
		libvlc_video_set_aspect_ratio(vlc_mediaPlayer, "235:100");
	else if (action == m_2_38_1)
		libvlc_video_set_aspect_ratio(vlc_mediaPlayer, "238:100");
	else if (action == m_5_4)
		libvlc_video_set_aspect_ratio(vlc_mediaPlayer, "5:4");
}

//事件回调
void showWidget::vlcEvents(const libvlc_event_t *ev, void *param)
{
	showWidget *w = (showWidget*)param;
	//处理不同的事件
	switch (ev->type) {
	case libvlc_MediaPlayerTimeChanged:
	{
		//qDebug() << "VLC媒体播放器时间已更改";
		qint64 len = libvlc_media_player_get_time(w->vlc_mediaPlayer);
		libvlc_time_t lenSec = len / 1000;

		libvlc_time_t totalLen = libvlc_media_player_get_length(w->vlc_mediaPlayer);
		libvlc_time_t totalLenSec = totalLen / 1000;

		int thh, tmm, tss;
		thh = lenSec / 3600;
		tmm = (lenSec % 3600) / 60;
		tss = (lenSec % 60);
		QTime time(thh, tmm, tss);
		w->ui.lbCurTime->setText(time.toString("hh:mm:ss"));

		thh = totalLenSec / 3600;
		tmm = (totalLenSec % 3600) / 60;
		tss = (totalLenSec % 60);
		QTime TotalTime(thh, tmm, tss);
		w->ui.lbTotalTime->setText(TotalTime.toString("hh:mm:ss"));

		double pos = (double)lenSec / totalLenSec * 100;
		w->ui.horizontalSlider->setValue(pos);
	}
		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;
	}
}

更多参考:

libVLC 事件机制-CSDN博客

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

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

libVLC 元数据-CSDN博客

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

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