获取本地 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<< "网…

谁在窥屏_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…

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

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

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

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

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

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

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

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

太极软件qn的代码_多版本QQ内置qn、qx模块

软件名称&#xff1a;QQ版本号&#xff1a;1362、1392、1558版本&#xff1a;8.3.0、8.3.5、8.4.18安装包大小&#xff1a;81.93m、88.64m、100.93m简介&#xff1a;分别是830、835、8418这三个版本的QQ&#xff0c;只内置qn、qx模块&#xff0c;可以实现无需root&#xff0c;无…

asp.net 导入excel显示进度

这几天在做个导入excel的上传页面&#xff0c;由于数据量太大&#xff0c;要显示个进度条&#xff0c;本人不懂jquery&#xff0c;所以百度完再经过调整之后完成了&#xff0c;如果告诉别人只是为了显示个进度条而弄个多线程&#xff0c;还要根据session的机制模拟一个具有sess…

element form自定义校验_SpringBoot分组校验及自定义校验注解

前言在日常的开发中&#xff0c;参数校验是非常重要的一个环节&#xff0c;严格参数校验会减少很多出bug的概率&#xff0c;增加接口的安全性。在此之前写过一篇SpringBoot统一参数校验主要介绍了一些简单的校验方法。而这篇则是介绍一些进阶的校验方式。比如说&#xff1a;在某…

前端学习(526):等分布局

<!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>等分布局</title><style>.col1{backgro…

前端学习(527):等分布局第二种方案

<!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>等分布局</title><style>.parent{width…

c语言 feof_C语言 技能提升 系列文章(六)文件操作

C语言除了提供open()/ read()/ write()/ close() 这些基本的操作以外&#xff0c;还提供了下面几个非常有用的API。// 删除指定的文件int remove ( const char * filename ); // 重命名指定的文件int rename ( const char * oldname, const char * newname );// 以“wb”模式打…