获取本地 qt_用QT实现视频/音乐播放组件

13850e1e7a5d37e216ac6833d21c0cf7.png

前言

我已经有四五天没有发布文章了,趁着这个周末有空,就又开始构思我们自己的QT组件库中的新组件,思考还有哪些有用、有趣、值得研究学习并构建实现的组件,于是又有了两个新的目标,即多媒体播放组件和地图组件。之所以准备实现这两个小组件,是因为现在流行的很多软件应用中几乎都能用得到音频视频播放和地图导航或定位功能。所以我们在自己的软件开发中如果也遇到类似的需求,能有一个使用方便、快捷灵活的多媒体或地图组件,肯定能够节省我们很多的工作量和精力,QT虽然有相关的类但是没有相关的组件,如是我就开始了自己的实现。

功能展示

今天先跟大家分享一下我自己实现的多媒体播放组件,使用该组件可以很方便的用来播放音乐和视频。而且所有功能完全是基于QT自带的QMediaPlayer类和QVideoWidget类进行实现,没有使用任何第三方库,所以上手也比较容易。目前已实现的基本功能有:

  • 音乐/视频播放、暂停功能
  • 时长和进度显示
  • 音量调节和静音功能
  • 播放进度调整,支持时间轴点选、拖拉和键盘控制
  • 全屏

因为录制的gif没有声音,所以我只展示视频播放功能,具体实现效果如下方动图所示:

播放、暂停功能,点击按钮或视频窗口都能实现该功能:

4f2dfbd39eb0fc7c817d3cc544e072e8.gif

进度调节和音量调节:

0bd84859-6c55-eb11-8da9-e4434bdf6706.png

静音:

0dd84859-6c55-eb11-8da9-e4434bdf6706.png

全屏:

3766bbf761eb52978f7481de483e211b.gif

实现方法

1、怎么使用QMediaPlayer类播放音乐和视频?

播放音乐只需要设置好源即可,源既可以是本地路径也可以是网址,如果播放使用本地文件的话,需要使用

QUrl::fromLocalFile函数,方法如下:

m_pPlayer = new QMediaPlayer;m_pPlayer->setMedia(QMediaContent(QUrl::fromLocalFile(strPath)));m_pPlayer->play();

播放视频的话还需要设置视频输出位置,所以QMediaPlayer通常需要连接一个QVideoWidget来进行视频的播放,方法如下:

m_pPlayer = new QMediaPlayer;m_pVideoWidget = new QVideoWidget;m_pPlayer->setMedia(QMediaContent(QUrl::fromLocalFile(strPath)));m_pPlayer->setVideoOutput(m_pVideoWidget);m_pVideoWidget->show();

2、怎么显示视频总时长和当前播放进度?

总时长可以通过m_pPlayer->duration()获取,当前播放进度可以通过m_pPlayer->position()获取,这两个函数返回的都是毫秒数,我们只需要将该毫秒数转换为时间并显示到标签上即可,我为了这两个值能够与时间轴对应起来,所以我都是先转换成秒,然后再对秒进行处理:

//将秒数转换为HH:mm::ss格式QString MediaPlayer::changeSecondsToStr(int nMesc){    m_nHour = nSeconds / 3600;    nSeconds %= 3600;    m_nMinute = nSeconds / 60;    nSeconds %= 60;    m_nSecond = nSeconds;    return QString("%1:%2:%3").arg(m_nHour, 2, 10, QLatin1Char('0')).arg(m_nMinute, 2, 10, QLatin1Char('0')).arg(m_nSecond, 2, 10, QLatin1Char('0'));}

为了能够实时更新当前的播放进度,我设置了一个定时器,每50ms检查一次当前秒数是否变化并对界面进行刷新:

//定时器超时处理void MediaPlayer::onTimerOut(){       if (m_pSlider->sliderPosition() != m_nLastPosition)    {        //之所以会出现这种情况,是因为触发了键盘事件,比如用户按下了方向键、PgUp、PgDn、Home、End        m_nLastPosition = m_pSlider->sliderPosition();        m_pSlider->setValue(m_nLastPosition);        m_pPlayer->setPosition(m_nLastPosition * 1000);        setPlayTime(m_nLastPosition);        return;    }    int nCurPosition = m_pPlayer->position() / 1000;    if (m_nLastPosition != nCurPosition)    {        m_nLastPosition = nCurPosition;        //检查是否播放完毕        if (nCurPosition >= m_pPlayer->duration() / 1000)            play();        m_pSlider->setValue(nCurPosition);        setPlayTime(nCurPosition);    }}
32a8d8c3bacf4572a9b827ff21a3762b.png

3、如何使用QSlider对视频进行进行展示和控制?

展示功能是很好实现的,只需要设置好QSlider的范围并在定时器中setValue即可,QSlider本身也支持拖动控制,但是当我自定义了QSlider上滑块的样式后,发现拖动滑块不是很灵敏且经常无法选中滑块,且QSlider本身并不支持点击改变当前值,因此我对QSlider添加了事件过滤器,并自己处理了它的鼠标点击事件和鼠标移动事件。

m_pSlider = new QSlider(Qt::Horizontal, this);    m_pSlider->setObjectName("m_pSlider");    m_pSlider->setCursor(Qt::PointingHandCursor);    m_pSlider->setSingleStep(1);    m_pSlider->setPageStep(10);    m_pSlider->installEventFilter(this);    m_pSlider->setEnabled(false);
bool MediaPlayer::eventFilter(QObject *watched, QEvent *event){    //进度滑动条    if(watched == m_pSlider)    {        if (event->type() == QEvent::MouseButtonPress)        {            QMouseEvent *mouseEvent = static_cast(event);            if (mouseEvent->button() == Qt::LeftButton)//判断左键            {                QSlider* pSlider = (QSlider*)watched;                int dur = pSlider->maximum() - pSlider->minimum();                int pos = pSlider->minimum() + dur * ((double)mouseEvent->x() / pSlider->width());                if (pos != pSlider->sliderPosition())                {                    //if (pSlider == m_pSlider)                    {                        if (m_pSlider->isEnabled())                        {                            m_pSlider->setValue(pos);                            onSliderPressed();                            onSliderMoved(pos);                            onSliderReleased();                            return true;                        }                    }                }            }        }        else if (event->type() == QEvent::MouseMove)        {            QMouseEvent *mouseEvent = static_cast(event);            //if (mouseEvent->button() == Qt::LeftButton)//判断左键            {                QSlider* pSlider = (QSlider*)watched;                int dur = pSlider->maximum() - pSlider->minimum();                int pos = pSlider->minimum() + dur * ((double)mouseEvent->x() / pSlider->width());                //防止超出范围                if (pos > pSlider->maximum())                    pos = pSlider->maximum();                if (pos < pSlider->minimum())                    pos = pSlider->minimum();                if (pos != pSlider->sliderPosition())                {                    //if (pSlider == m_pSlider)                    {                        if (m_pSlider->isEnabled())                        {                            m_pSlider->setValue(pos);                            onSliderPressed();                            onSliderMoved(pos);                            onSliderReleased();                            return true;                        }                    }                }            }        }    }    return QObject::eventFilter(watched, event);}  

如果在视频播放过程中改变进度的话,定时器还在运行,可能也会同时修改视频的进度,所以在用m_pSlider改变播放进度时,需要先停止视频播放和定时器,这个操作我们通过管理QSlider的鼠标按下响应、鼠标移动响应和鼠标释放响应进行处理。当鼠标按下时停止视频播放和定时器,鼠标移动时修改视频进度,鼠标释放时恢复视频播放和重启定时器。

connect(m_pSlider, SIGNAL(sliderPressed()), this, SLOT(onSliderPressed()));connect(m_pSlider, SIGNAL(sliderMoved(int)), this, SLOT(onSliderMoved(int)));connect(m_pSlider, SIGNAL(sliderReleased()), this, SLOT(onSliderReleased()));
//滑动条鼠标点击响应void MediaPlayer::onSliderPressed(){    m_bIsLastPlay = m_bIsPlay;}//滑动条滑动响应void MediaPlayer::onSliderMoved(int nPosition){    Q_UNUSED(nPosition);    //在拖动过程中暂停播放    if (m_bIsPlay)        play();    if (m_nLastPosition != nPosition)    {        m_nLastPosition = nPosition;        m_pSlider->setValue(m_nLastPosition);        m_pPlayer->setPosition(m_nLastPosition * 1000);        setPlayTime(m_nLastPosition);    }}//滑动条鼠标释放响应void MediaPlayer::onSliderReleased(){    if (m_bIsLastPlay)        play();}

4、如何实现音量控制和音量控制窗口的自动显示和隐藏?

音量修改也是使用滑动条进行控制,实现方法和改变播放进度类似,就不再细说。这里只说一下怎么控制音量窗口的自动出现和隐藏。当鼠标移动到音量按钮上方时,音量窗口自动显示,当鼠标移动到音量窗口上方时,音量窗口一直保持显示状态,当鼠标从音量窗口移出1s以后,音量窗口自动隐藏。了解这个过程以后,其实不难发现,还是需要对鼠标事件进行过滤和自定义处理。至于怎么使窗口延迟1s后隐藏,使用QTimer::singleShot进行单次触发最为方便合适。

bool MediaPlayer::eventFilter(QObject *watched, QEvent *event){    if (watched == m_pVolumeButton) //音量键    {        if (event->type() == QEvent::Enter)        {            changeVolume(m_pPlayer->volume());            m_pVolumeSlider->setValue(m_pPlayer->volume());            //计算位置,使其位于音量控制按钮的上方            m_pVolumeWidget->setGeometry(QRect(m_pVolumeButton->pos().rx()+0.5*m_pVolumeButton->width()-m_pVolumeWidget->width()/2,                                               m_pControlWidget->y()-110 , m_pVolumeWidget->width(), 100));            m_pVolumeWidget->show();            m_bVolume = true;        }        if (event->type() == QEvent::Leave)        {            m_bVolume = false;            QTimer::singleShot(1000, this, SLOT(hideSlider()));        }    }    else if (watched == m_pVolumeWidget) //音量窗口    {        if (event->type() == QEvent::Enter)            m_bVolume = true;        else if(event->type() == QEvent::Leave)        {            m_bVolume = false;            QTimer::singleShot(1000, this, SLOT(hideSlider()));        }    }    return QObject::eventFilter(watched, event);}

5、如何实现实现静音和全屏显示?

当我们点击音量按钮的时候进行打开静音或关闭静音操作,当然静音时手动的设置音量为0也无可厚非,但是QMediaPlayer中也提高了相关接口,使用方法如下:

//打开或关闭静音void MediaPlayer::openOrCloseMute(){    if (m_pPlayer->isMuted())        m_pVolumeButton->setIcon(QIcon(":/Images/MediaPlayer_Icon/sound.png"));    else        m_pVolumeButton->setIcon(QIcon(":/Images/MediaPlayer_Icon/mute.png"));    m_pPlayer->setMuted(!m_pPlayer->isMuted());

全屏方法也是调用接口,直接上代码:

//打开或关闭全屏显示void MediaPlayer::openOrCloseFullScreen(){    if (this->isFullScreen())    {        m_pFullScreenButton->setIcon(QIcon(":/Images/MediaPlayer_Icon/showMax.png"));        m_pFullScreenButton->setToolTip("进入全屏");        this->showNormal();    }    else    {        m_pFullScreenButton->setIcon(QIcon(":/Images/MediaPlayer_Icon/showNormal.png"));        m_pFullScreenButton->setToolTip("退出全屏");        this->showFullScreen();    }}

总结

33474d5bb256c70ac33b410f4497b2c7.png

其实整个实现过程也很简单,主要是QSlider的使用和对鼠标移动事件的处理,该组件的下方控制窗口也可以实现自动隐藏,实现方法和音量窗口类似。还可以集成之前我们自己做的弹幕组件,从而支持发送弹幕功能,由于时间关系,我就没有实现。该组件的使用方法也非常方便:

MediaPlayer *pMediaPlayer = new MediaPlayer;pMediaPlayer->show();//pMediaPlayer->playMusic("D:/CloudMusic/1.mp3"); //播放音乐pMediaPlayer->playVideo("C:/Users/金/Desktop/2.mp4");  //播放视频

源码大概有500行左右,这里就不再贴出来了,否则篇幅太长,主要功能实现,上面也都放了源码,如果有需要也可以评论留言,后期也会统一上传github。

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

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

相关文章

c++文件读写

http://stlchina.huhoo.net/bin/view.pl/Main/STLDetailString 添加#include <fstream> using namespace std; View Code 1 //ofstream myfile("c:\\1.txt",ios::out|ios::trunc);2 //3 //myfile<<"中国国国" << endl<< "网…

天龙八部网单服务器技能修改,天龙八部3门派技能修改介绍

该楼层疑似违规已被系统折叠 隐藏此楼查看此楼少林伏虎拳 对该技能的攻击动作进行了修改弥勒护身 释放不再消耗真气明镜台 现在此技能可以对队友释放金刚不坏体 减伤效果提高到了70%天龙正气浩然 释放不再消耗真气静影沉璧 减少了此技能的打蓝效果截拳式 现在这个状态可以增加内…

【Codeforces #130 Div2】Solutions

【208A Dubstep】 http://codeforces.ru/problemset/problem/208/A 题目大意&#xff1a;一个句子被添加了若干“WUB”&#xff0c;问原句。 将WUB去掉就行了&#xff0c;在句首或句尾直接删除&#xff0c;在句中替换成空格&#xff0c;注意多个“WUB”相连时特判。 #include …

服务器此时无法接受控制信息,您无法修改域或信任信息,因为无法联系一个主域控制器(PDC)仿真器,请确认当前域的PDC仿真器和网络都联机并正常运行。...

问题补充&#xff1a;PS C:\Users\administrator.TF> netdom query fsmo架构主机 AD-server.tf.com域命名主机 AD-server.tf.comPDC AD-server.tf.comRID 池管理器 AD-server.tf.com结构主机 AD-server.tf.c…

VC++6.0如何创建与调用动态链接库(dll)

VC支持的DLL&#xff1a; DLL的编制与具体的编程语言及编译器无关&#xff0c;动态链接库随处可见&#xff0c;VC支持三种DLL&#xff1a;非MFC动态库、MFC规则DLL和MFC扩展DLL。DLL导出函数&#xff08;或变量、类&#xff09;可供应用程序调用&#xff1b;DLL内部函数只能在D…

谁在窥屏_TheShy直播被窥屏搞怕了,为了防止被窥屏,这个做法绝了

前言&#xff1a;英雄联盟LPL赛区已经发展了十年&#xff0c;请你大胆试想下&#xff0c;如果终有一天英雄联盟会被其他游戏所淹没替代&#xff0c;让你选出自己心目中最强的游戏玩家&#xff0c;你的脑海里首先浮现的是谁的身影呢&#xff1f;笔者的脑海里首先是TheShy。TheSh…

前端学习(516):两列布局的第三种解决方案

<!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>第三种实现方案</title><style>.parent…

如何在Linux下安装nginx

如何在Linux下安装nginx 1.http://nginx.org 下载对应平台的安装初始配置文件 2.yum install nginxposted on 2012-07-25 15:41 ericyuan 阅读(...) 评论(...) 编辑 收藏 转载于:https://www.cnblogs.com/ericyuan/archive/2012/07/25/2608425.html

qchart 设置线颜色_实战PyQt5: 137-QChart图表之散点图

散点图(scatter chart)将序列显示为一组点。值由点在图表中的位置表示。类别由图表中的不同标记表示。散点图通常用于比较跨类别的聚合数据。在QChart中&#xff0c;使用类QScatterSeries创建散点图。QScatterSeriesQScatterSeries类在散点图中显示数据。散点数据在图表上显示为…

oracle19c xp安装 客户端_windows下安装oracle19c

目录&#xff1a;一. 官网下载oracle19c 以及客户端二.安装oracle19c1.解压安装压缩包在D盘新建文件夹oracle19c(注意&#xff1a;解压后的安装包不能为中文路径&#xff0c;且不要有空格这台特殊的&#xff0c;且数据库安装完成后安装包也不能删除。)。将WINDOWS.X64_193000_d…

调整latex表格_选择LaTeX还是Word的建议

如果对公式细节有很大的要求&#xff0c;比如公式字体、公式特殊格式&#xff08;透明&#xff0c;特殊文字&#xff09;有要求&#xff0c;只能用LaTeX&#xff0c;Word并不支持。还有一些及其专业的地方可能只有LaTeX能完成。有些大型期刊要求使用LaTeX模板那就只能服从要求了…

C#下如何实现服务器 + 客户端的聊天程序

最近也在接触SOCKET编程&#xff0c;在当今这样一个网络时代&#xff0c;很多技术都以网络为中心在诞生&#xff0c;至少我认为是这样的&#xff0c;而SOCKET套接字接口&#xff0c;在实现网络通讯上处于关键地位&#xff0c;所以不会SOCKET是不行的。首先&#xff0c;本文主要…

部署gogs_可以更快地查阅 Gogs 文档了!

# 可以更快地查阅 Gogs 文档了&#xff01;作为程序员&#xff0c;如何高效、准确地查阅文档是日常开发工作中的必备技能。长期以来&#xff0c;优秀开源项目的官方文档都是部署在国外服务器上&#xff0c;从国内访问非常慢&#xff0c;而由于众所周知的限制&#xff0c;部分文…

VC中使用ADO的方法

ADO中打开一个连接&#xff1a; pConnection->ConnectionString "这里的字符串有下面四种写法";      //对连接字符串赋值 pConnection->Open(ConnectionString,"","",adModeUnknown);       //连接数据库 第二三个参数分别为…

c++ mmap写入速度_Linux系统编程_用mmap+数组的方式修改数据文件

正文开始前&#xff0c;先聊点非技术的东西&#xff0c;推荐2本生动有趣的书&#xff1a;《经济学原理 宏观经济学》&#xff0c;曼昆&#xff0c;豆瓣评分9.3&#xff0c;4945人评价《经济学原理 微观经济学》&#xff0c;曼昆&#xff0c;豆瓣评分9.6&#xff0c;1879人评价我…

Java中类型转换

编辑器加载中... int -> String int i12345; String s""; 第一种方法&#xff1a;si""; 第二种方法&#xff1a;sString.valueOf(i); 这两种方法有什么区别呢&#xff1f;作用是不是一样的呢&#xff1f;是不是在任何下都能互换呢&#xff1f; String -…