libVLC 视频界面分割

先看看分割后的界面吧,根据分割的数量,来分割视频画面。

其实视频界面分割很简单,看过叠加窗口的这篇文章,不难理解,如何分割。

libVLC 视频窗口上叠加透明窗口-CSDN博客

如果还是不懂的话,我讲解一下原理,其实就是在上面叠加透明窗口界面,在叠加的窗口上面调用

paintEvent绘制线条,很简单吧。

void TopWidget::paintEvent(QPaintEvent *pEvent)
{//创建QPainter对象,指明父对象,否则不能看见QPainter painter(this);//先画一条线QPen pen;//设置线宽pen.setWidth(10);//设置颜色pen.setColor(Qt::white);//设置线的样式 实线、虚线pen.setStyle(Qt::SolidLine);//设置线端点样式pen.setCapStyle(Qt::RoundCap);//设置画笔painter.setPen(pen);for (int i = 0; i < m_num; i++){//画竖线painter.drawLine(QPoint(width() * (i+1)/ (m_num+1), 0), QPoint(width() * (i + 1) / (m_num + 1), height()));//画横线painter.drawLine(QPoint(0, height() * (i + 1) / (m_num + 1)), QPoint(width(), height() * (i + 1) / (m_num + 1)));}}

更多QPainter相关的东西,请看:

Qt QPainter绘图_qt painter-CSDN博客

还是像之前的文章一样,先创建一个叠加界面,设置窗体无边框和透明。

	//窗口无边框setWindowFlags(Qt::FramelessWindowHint | Qt::Window);// 窗口透明this->setAttribute(Qt::WA_TranslucentBackground);

界面源码如下,ui上面没有任何控件。 

#pragma once#include <QWidget>
#include <QPaintEvent>
#include <QPainter>
#include "ui_TopWidget.h"class TopWidget : public QWidget
{Q_OBJECTpublic:TopWidget(QWidget *parent = nullptr);~TopWidget();void setNum(int num);protected:void paintEvent(QPaintEvent *pEvent);private:Ui::TopWidgetClass ui;int m_num = 0;
};#include "TopWidget.h"TopWidget::TopWidget(QWidget *parent): QWidget(parent)
{ui.setupUi(this);//窗口无边框setWindowFlags(Qt::FramelessWindowHint | Qt::Window);// 窗口透明this->setAttribute(Qt::WA_TranslucentBackground);
}TopWidget::~TopWidget()
{}void TopWidget::setNum(int num)
{m_num = num;update();
}void TopWidget::paintEvent(QPaintEvent *pEvent)
{//创建QPainter对象,指明父对象,否则不能看见QPainter painter(this);//先画一条线QPen pen;//设置线宽pen.setWidth(10);//设置颜色pen.setColor(Qt::white);//设置线的样式 实线、虚线pen.setStyle(Qt::SolidLine);//设置线端点样式pen.setCapStyle(Qt::RoundCap);//设置画笔painter.setPen(pen);for (int i = 0; i < m_num; i++){//画竖线painter.drawLine(QPoint(width() * (i+1)/ (m_num+1), 0), QPoint(width() * (i + 1) / (m_num + 1), height()));//画横线painter.drawLine(QPoint(0, height() * (i + 1) / (m_num + 1)), QPoint(width(), height() * (i + 1) / (m_num + 1)));}}

主界面重写绘图和窗体移动事件:我们需要在主窗体移动的时候,叠加窗体跟随着主窗体移动。

void showWidget::paintEvent(QPaintEvent *event)
{QPoint pos_form = ui.widgetShow->mapToGlobal(ui.widgetShow->pos());m_widget->move(pos_form);m_widget->setGeometry(pos_form.x(), pos_form.y(), ui.widgetShow->width(), ui.widgetShow->height());
}
void showWidget::moveEvent(QMoveEvent *event)
{QPoint pos_form = ui.widgetShow->mapToGlobal(ui.widgetShow->pos());m_widget->move(pos_form);m_widget->setGeometry(pos_form.x(), pos_form.y(), ui.widgetShow->width(), ui.widgetShow->height());
}

完整源码:

#pragma once
#define LIBVLC_USE_PTHREAD_CANCEL 1
#include <QtWidgets/QWidget>
#include "ui_showWidget.h"
#include <QMenu>
#include <QActionGroup>
#include <vlc/vlc.h>#include <QDebug>
#include <QFileDialog>
#include <QThread>
#include <QMouseEvent>
#include <QKeyEvent>
#include <QPainter>
#include "TopWidget.h"enum Rate
{Rate2X,Rate1_5X,Rate1_25X,Rate1_0X,Rate0_75X,Rate0_5X
};class showWidget : public QWidget
{Q_OBJECTpublic:showWidget(QWidget *parent = nullptr);~showWidget();protected:virtual void mouseDoubleClickEvent(QMouseEvent *event);virtual void keyPressEvent(QKeyEvent *event);virtual bool eventFilter(QObject *watched, QEvent *event);virtual void paintEvent(QPaintEvent *event);virtual void moveEvent(QMoveEvent *event);private slots:void slotOpenFile();void slotPlay();void slotPause();void slotStop();void slotValueChanged(int value);void slotCurrentIndexChanged(int index);void slotSnap();void slotCurrentSplitChanged(int index);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;QList<float> m_lstRate;TopWidget *m_widget = nullptr;
};//=========================================================#include "showWidget.h"
#include <QTimer>
#include <QTime>
#include <QFileDialog>#pragma execution_character_set("utf-8")showWidget::showWidget(QWidget *parent): QWidget(parent)
{ui.setupUi(this);this->setWindowTitle("视频播放器");m_widget = new TopWidget(this);//m_widget->setStyleSheet(QString("background-color: rgba(255, 0, 0, 0%);"));m_widget->show();ui.cbxRate->setCurrentIndex(Rate1_0X);m_lstRate << 2.0 << 1.5 << 1.25 << 1.0 << 0.75 << 0.5;vlc_base = libvlc_new(0, NULL);ui.btnOpen->setFocusPolicy(Qt::NoFocus);ui.btnPlay->setFocusPolicy(Qt::NoFocus);ui.btnPause->setFocusPolicy(Qt::NoFocus);ui.btnStop->setFocusPolicy(Qt::NoFocus);ui.hSliderVolumn->setFocusPolicy(Qt::NoFocus);ui.cbxRate->setFocusPolicy(Qt::NoFocus);ui.horizontalSlider->installEventFilter(this);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.btnSnap, &QPushButton::clicked, this, &showWidget::slotSnap);connect(ui.hSliderVolumn, &QSlider::valueChanged, this, &showWidget::slotValueChanged);connect(ui.cbxRate,SIGNAL(currentIndexChanged(int)), this, SLOT(slotCurrentIndexChanged(int)));connect(ui.comboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(slotCurrentSplitChanged(int)));
}showWidget::~showWidget()
{libvlc_release(vlc_base); //减少libvlc实例的引用计数,并销毁
}void showWidget::mouseDoubleClickEvent(QMouseEvent *event)
{if (this->isFullScreen()){this->showNormal();}else{this->showFullScreen();}
}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);}}
}bool showWidget::eventFilter(QObject *watched, QEvent *event)
{if (watched == ui.horizontalSlider) {if (event->type() == QEvent::MouseButtonPress) {if (!vlc_mediaPlayer)return false;QMouseEvent *mouse = static_cast<QMouseEvent*>(event);libvlc_time_t totalLen = libvlc_media_player_get_length(vlc_mediaPlayer);QPoint pos = mouse->pos();libvlc_time_t time = 0;time = (double)pos.x() / ui.horizontalSlider->width() * totalLen;libvlc_media_player_set_time(vlc_mediaPlayer, time);return true;}else {return false;}}else {// pass the event on to the parent classreturn QWidget::eventFilter(watched, event);}
}void showWidget::paintEvent(QPaintEvent *event)
{QPoint pos_form = ui.widgetShow->mapToGlobal(ui.widgetShow->pos());m_widget->move(pos_form);m_widget->setGeometry(pos_form.x(), pos_form.y(), ui.widgetShow->width(), ui.widgetShow->height());
}
void showWidget::moveEvent(QMoveEvent *event)
{QPoint pos_form = ui.widgetShow->mapToGlobal(ui.widgetShow->pos());m_widget->move(pos_form);m_widget->setGeometry(pos_form.x(), pos_form.y(), ui.widgetShow->width(), ui.widgetShow->height());
}void showWidget::slotOpenFile()
{/*选择文件*/QString filename = QFileDialog::getOpenFileName(this, "选择打开的文件", "D:/", tr("*.*"));std::replace(filename.begin(), filename.end(), QChar('/'), QChar('\\'));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_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) {// 处理字幕轨道信息qDebug("psz_encoding = %s", track->subtitle->psz_encoding);}}//获取事件管理器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::slotSnap()
{if (vlc_mediaPlayer){QString path = "./snap.png";libvlc_video_take_snapshot(vlc_mediaPlayer, 0, path.toUtf8().data(), 0, 0);}
}void showWidget::slotCurrentSplitChanged(int index)
{m_widget->setNum(index);
}//事件回调
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;}
}

以下是ui原型图:

Qt+FFmpeg+opengl从零制作视频播放器-1.项目介绍_qt opengl视频播放器-CSDN博客

libVLC 提取视频帧使用OpenGL渲染-CSDN博客

QT UDP通信(单播、广播、组播)-CSDN博客

QCharts -1.概述-CSDN博客

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/808262.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【c++】-对象的初始化-构造函数和析构函数区别联系-总结

对象的初始化 1.构造函数和析构函数 构造函数和析构函数是在类体中说明的两种特殊的成员函数。构造函数的功能是在创建对象时&#xff0c;使用给定的值来将对象初化。析构函数的功能是用来释放一个对象的&#xff0c;在对象删除前&#xff0c;用它来做一些清理工作&#xff0…

原码的除法运算

目录 王道考研ppt&#xff1a; 个人理解&#xff1a; 手算整数的除法&#xff1a; ​编辑 手算二进制的除法&#xff1a; 用机器实现除法&#xff1a; 方法一&#xff1a;恢复余数法 第二种方法&#xff1a;加减交替法 王道考研ppt&#xff1a; 个人理解&#xff1a; 手…

政安晨:【深度学习神经网络基础】(三)—— 激活函数

目录 线性激活函数 阶跃激活函数 S型激活函数 双曲正切激活函数 修正线性单元 Softmax激活函数 偏置扮演什么角色&#xff1f; 政安晨的个人主页&#xff1a;政安晨 欢迎 &#x1f44d;点赞✍评论⭐收藏 收录专栏: 政安晨的机器学习笔记 希望政安晨的博客能够对您有所裨…

【完全背包求方案数问题】AcWing1023.买书(赋练习题目)

【题目链接】活动 - AcWing 输入样例1&#xff1a; 20输出样例1&#xff1a; 2输入样例2&#xff1a; 15输出样例2&#xff1a; 0输入样例3&#xff1a; 0输出样例3&#xff1a; 1 【代码】 //1023.买书——完全背包问题#include<bits/stdc.h>using namespace st…

IP定位的原理及应用场景

IP定位&#xff0c;即通过IP地址来确定一个设备或用户所在的大致地理位置&#xff0c;是一项在现代网络时代中愈发重要的技术。它广泛应用于网络安全、数据分析、广告投放等多个领域&#xff0c;为人们的生活和工作带来了极大的便利。本文将从IP定位的原理、实现方式、应用场景…

基于springboot的大型商场应急预案管理系统源码数据库

摘要 随着信息技术在管理上越来越深入而广泛的应用&#xff0c;管理信息系统的实施在技术上已逐步成熟。本文介绍了大型商场应急预案管理系统的开发全过程。通过分析大型商场应急预案管理系统管理的不足&#xff0c;创建了一个计算机管理大型商场应急预案管理系统的方案。文章…

百度Create AI开发者大会剧透丨用好三大AI神器 ,人人都是开发者

程序员会消失&#xff0c;真的吗&#xff1f;大模型的下一站是什么&#xff1f;开发者的机会在哪里&#xff1f;什么才是最好用的AI应用开发工具&#xff1f;在4月16日举办的2024百度Create AI开发者大会上&#xff0c;百度创始人、董事长兼首席执行官李彦宏将就这些备受瞩目的…

算法刷题day45

目录 引言一、母亲的牛奶二、奶牛回家三、扫雷 引言 今天主要复习了图论里的最短路、 B F S 、 D F S 、 F l o o d F i l l BFS、DFS、Flood\ Fill BFS、DFS、Flood Fill 算法&#xff0c;其实到现在感觉暴搜其实还挺好写的&#xff0c;现在刚好反过来了&#xff0c;不喜欢写…

Vue的学习之旅-part4

Vue的学习之旅-part1 vue的自带指令v-if v-else-if v-else虚拟DOM的复用v-show 与 v-if 的不同之处&#xff1a;v-if v-show各自合适的使用位置&#xff1a; v-for 循环v-for 循环遍历 :key"item" 绑定key&#xff0c;区分循环的内容循环的应用&#xff1a; 前几篇博…

257.二叉树的所有路径

给你一个二叉树的根节点 root &#xff0c;按 任意顺序 &#xff0c;返回所有从根节点到叶子节点的路径。 叶子节点 是指没有子节点的节点。 class Solution{public List<String> binaryTreePaths(TreeNode root){List<String> paths new ArrayList<>():c…

单片机蓝牙数据传输刚开始正常然后乱码什么原因

单片机蓝牙数据传输在开始时正常&#xff0c;但随后出现乱码的情况可能由多种原因引起。以下是一些可能的原因及解决方法&#xff1a; 波特率不匹配&#xff1a;单片机与蓝牙模块之间的波特率设置不一致可能导致数据传输错误。确保两者使用的波特率相同&#xff0c;并检查是否…

宏观认知第一篇--AI 是否就是第四次工业革命?

今年春节期间李一舟老师突然爆火&#xff0c;成功晋升为能与 ChatGPT 公司 CEO 齐名的中国 AI 大佬&#xff0c;赚到几个小目标后又火速被封&#xff0c;于是想着有空写篇小文章讲一讲跟普通人切身相关的话题-- AI 是否就是第四次工业革命&#xff1f; “AI 是否就是第四次工业…

【Java核心技术】第4章 对象与类

1 面向对象 2 自定义类 形式&#xff1a; class ClassName { field // 字段 constructor // 构造器&#xff08;构造函数&#xff09; method // 方法 } 如&#xff1a; class Employee {private String name;private double salary;private LocalDate hireDay;public Emp…

“桃花庵主”是我国哪位古代名人的称号?2024年4月12日蚂蚁庄园今日答案

原文来源&#xff1a;蚂蚁庄园今日答案 - 词令 蚂蚁庄园是一款爱心公益游戏&#xff0c;用户可以通过喂养小鸡&#xff0c;产生鸡蛋&#xff0c;并通过捐赠鸡蛋参与公益项目。用户每日完成答题就可以领取鸡饲料&#xff0c;使用鸡饲料喂鸡之后&#xff0c;会可以获得鸡蛋&…

.a和.so库文件是什么?

我们在编译开源代码后&#xff0c;通常会生成.a和.so这两个库文件&#xff0c;这两个文件有什么区别&#xff1f;又如何使用&#xff1f; 在 Linux 中&#xff0c;.a 和 .so 文件都是库文件&#xff0c;但它们有一些区别&#xff1a; 静态库文件&#xff08;.a&#xff09;&am…

全量知识系统 程序详细设计之 原型库(QA百度搜索)

Q1. 今天聊聊全知系统中的原型库设计 全知系统中的原型库设计是一个关键环节&#xff0c;它涉及到系统的整体架构、功能需求、用户体验等多个方面。以下是一些关于全知系统中原型库设计的讨论&#xff1a; 明确设计目标&#xff1a;在设计原型库之前&#xff0c;需要明确设计…

fixed固定定位transofrm失效的解决

<div class"container"><div class"fixed"></div><div class"content"><div class"centered">Centered Content</div></div></div> 固定定位&#xff08;position: fixed&#xff0…

docker安装Neo4j

1、创建文件夹用作目录映射 mkdir -p /mydata/neo4j/{conf,data,import,logs,plugins} chmod -R 777 /mydata/neo4j/{conf,data,import,logs,plugins}2、拉去镜像 docker pull neo4j3、启动容器 docker run \ -d --name neo4j \ -p 7474:7474 -p 7687:7687 \ -v /mydata/neo…

pygame第7课——实现简单一个打砖块游戏

目录 专栏导读之前的课程1、小球类设计2、挡板类的设计3、砖块类4、砖块与小球的边界碰撞检测5、检测到碰撞&#xff0c;删除砖块&#xff0c;改变运动方向完整版代码总结 专栏导读 &#x1f338; 欢迎来到Python办公自动化专栏—Python处理办公问题&#xff0c;解放您的双手 …

简单的架构模板

大纲 现状 业务背景技术背景 需求 业务需求业务痛点性能需求 方案描述 方案1 概述详细说明性能目标性能评估方案优缺点 方案2方案对比 线上方案 架构图关键设计点和设计折衷业务流程模块划分异常边界&#xff08;重要&#xff09;统计&#xff0c;监控灰度&#xff0c;回滚策略…