赞
踩
车载终端是一个非常复杂且常用的装置,随着电车与自动驾驶技术的不断升级迭代,需求也与日俱增!我们往往需要在终端上附加许许多多其他的功能,比如:智能家居联动、车内环境监测、天气预报与网上浏览等!
作者强调:考虑到篇幅有限,作者本篇博客仅进行部分功能实现教学,并侧重应用层的实现!基础薄弱的朋友,可以直接使用正点原子出厂的镜像程序进行项目复现!
音频 CODEC 支持 I2S 协议,那么主控制器也必须支持 I2S 协议,I.MX6ULL 也提供了一个叫做 SAI 的外设,全称为 SynchronousAudio Interface,翻译过来就是同步音频接口。
I.MX6ULL 的 SAI 是一个全双工、支持帧同步的串行接口,支持I2S、AC97、TDM和音频DSP。
正点原子 ALPHA 开发板音频原理图如图所示:
NXP 官方已经写好了 WM8960 驱动,因此我们直接配置内核使能 WM8960 驱动即可,按照如下所示步骤使能 WM8960 驱动。
1、根据IMX6ULL的引脚原理图修改设备树;
2、使能内核的 WM8960 驱动;
2.1、取消 ALSA 模拟 OSS API
2.2、使能 I.MX6ULL 的 WM8960 驱动
完整可见:《【正点原子】I.MX6U嵌入式Linux驱动开发指南V1.6》 第 1544 页
正点原子的 IMX6ULL 与 NXP 官方的 “蓝版”相似度极高,就是仿照着进行制作的(一般情况下,大都公司产品的项目板也是如此)
6ULL 的 eLCDIF 接口驱动程序 NXP 已经编写好了,因此 LCD 驱动部分我们不需要去修改。我们需要做的就是按照所使用的 LCD 来修改设备树。重点要注意三个地方:
①、LCD 所使用的 IO 配置。
②、LCD 屏幕节点修改,修改相应的属性值,换成我们所使用的 LCD 屏幕参数。
③、LCD 背光节点信息修改,要根据实际所使用的背光 IO 来修改相应的设备节点信息。
1、修改 LCD 所使用的 IO 配置;
检查一下设备树中 LCD 所使用的 IO 配置,这个其实 NXP 都已经给我们写好了,不需要修改!
2、LCD 屏幕参数节点信息修改
在 imx6ull-alientek-emmc.dts 文件中找到 lcdif 节点,节点内容如下所示:
&lcdif { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_lcdif_dat &pinctrl_lcdif_ctrl>; display = <&display0>; status = "okay"; /* 7寸1024*600 */ display0: display { bits-per-pixel = <24>; /* */ bus-width = <24>; /* LCD屏幕数据线有多少 */ display-timings { native-mode = <&timing0>; timing0: timing0 { clock-frequency = <51200000>; /* 时钟频率51.2MHZ */ hactive = <1024>; /* 水平像素点 */ vactive = <600>; /* 垂直像素点 */ hfront-porch = <160>; hback-porch = <140>; hsync-len = <20>; vback-porch = <20>; vfront-porch = <12>; vsync-len = <3>; /* 像素点有效电平值 */ hsync-active = <0>; vsync-active = <0>; de-active = <1>; pixelclk-active = <0>; }; }; }; /* 4.3寸480*272 */ /* display0: display { bits-per-pixel = <24>; bus-width = <24>; display-timings { native-mode = <&timing0>; timing0: timing0 { clock-frequency = <9000000>; hactive = <480>; vactive = <272>; hfront-porch = <5>; hback-porch = <40>; hsync-len = <1>; vback-porch = <8>; vfront-porch = <8>; vsync-len = <1>; hsync-active = <0>; vsync-active = <0>; de-active = <1>; pixelclk-active = <0>; }; }; };*/ /* 4.3寸800*480 */ /* display0: display { bits-per-pixel = <24>; bus-width = <24>; display-timings { native-mode = <&timing0>; timing0: timing0 { clock-frequency = <31000000>; hactive = <800>; vactive = <480>; hfront-porch = <40>; hback-porch = <88>; hsync-len = <48>; vback-porch = <32>; vfront-porch = <13>; vsync-len = <3>; hsync-active = <0>; vsync-active = <0>; de-active = <1>; pixelclk-active = <0>; }; }; };*/ };
根据自己使用 LCD 的实际参数修改红色框中的各个参数信息!
3、LCD 屏幕背光节点信息
正点原子的 LCD 接口背光控制 IO 连接到了 I.MX6U 的 GPIO1_IO08 引脚上,GPIO1_IO08复用为 PWM1_OUT,通过 PWM 信号来控制 LCD 屏幕背光的亮度。正点原子 I.MX6U-ALPHA 开发板的 LCD 背光引脚和 NXP 官方 EVK 开发板的背光引脚一样,因此背光的设备树节点是不需要修改的。
设置 backlight 节点,这个 NXP 已经给我们设置好了,大家在 imx6ull-alientek-emmc.dts 文件中找到如下内容:
backlight {
compatible = "pwm-backlight";
pwms = <&pwm1 0 5000000>;
brightness-levels = <0 4 8 16 32 64 128 255>;
default-brightness-level = <7>;
status = "okay";
};
第 3 行,设置背光使用 pwm1,PWM 频率为 200Hz。
第 4 行,设置背 8 级背光(0~7),分别为 0、4、8、16、32、64、128、255,对应占空比为0%、1.57%、3.13%、6.27%、12.55%、25.1%、50.19%、100%,如果嫌少的话可以自行添加一些其他的背光等级值。
第 5 行,设置默认背光等级为 6,也就是 **50.19%**的亮度。
完整可见:《【正点原子】I.MX6U嵌入式Linux驱动开发指南V1.6》 第 1386 页
本项目作者替换的智能家居 APP 的功能页为 AP3216C 的车载内室监测功能!
篇幅有限,AP3216的使用和 QT 功能页设计博客:http://t.csdn.cn/cN6p1
音乐播放器是各家嵌入式机构 QT 练习的常规项目,QMediaPlayer 类是一个高级媒体播放类。它可以用来播放歌曲、电影和网络广播等内容。一般用于播放 mp3 和 mp4 等等媒体文件。QMediaPlayer 类常常与 QMediaPlaylist 类一起使用。可以很轻松的设计一个自己喜欢的音乐播放器与视频播放器。
QMediaPlayer 提供了很多信号,我们可以使用这些信号来完成音乐播放器的一系列操作,比如媒体状态改变的信号 stateChanged(QMediaPlayer::State state),判断这个 state 的状态就可以知道什么时候媒体暂停、播放、停止了。
★在项目文件 14_musicplayer.pro 文件第一行添加的代码:multimedia
在头文件 “mainwindow.h” 具体代码如下:
/****************************************************************** * @projectName musicplayer * @brief mainwindow.h * @author 混分巨兽龙某某 * @email 1178305328@qq.com *******************************************************************/ #ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QMainWindow> #include <QMediaPlayer> #include <QMediaPlaylist> #include <QPushButton> #include <QSlider> #include <QVBoxLayout> #include <QHBoxLayout> #include <QListWidget> #include <QLabel> #include <QSpacerItem> #include <QDebug> /* 媒体信息结构体 */ struct MediaObjectInfo { /* 用于保存歌曲文件名 */ QString fileName; /* 用于保存歌曲文件路径 */ QString filePath; }; class MainWindow : public QMainWindow { Q_OBJECT public: MainWindow(QWidget *parent = nullptr); ~MainWindow(); private: /* 媒体播放器,用于播放音乐 */ QMediaPlayer *musicPlayer; /* 媒体列表 */ QMediaPlaylist *mediaPlaylist; /* 音乐列表 */ QListWidget *listWidget; /* 播放进度条 */ QSlider *durationSlider; /* 音乐播放器按钮 */ QPushButton *pushButton[7]; QPushButton *exit_button; /* 垂直布局 */ QVBoxLayout *vBoxLayout[3]; /* 水平布局 */ QHBoxLayout *hBoxLayout[4]; /* 垂直容器 */ QWidget *vWidget[3]; /* 水平容器 */ QWidget *hWidget[4]; /* 标签文本 */ QLabel *label[4]; /* 用于遮罩 */ QWidget *listMask; /* 音乐布局函数 */ void musicLayout(); /* 主窗体大小重设大小函数重写 */ void resizeEvent(QResizeEvent *event); /* 媒体信息存储 */ QVector<MediaObjectInfo> mediaObjectInfo; /* 扫描歌曲 */ void scanSongs(); /* 媒体播放器类初始化 */ void mediaPlayerInit(); private slots: /* 播放按钮点击 */ void btn_play_clicked(); /* 下一曲按钮点击*/ void btn_next_clicked(); /* 上一曲按钮点击 */ void btn_previous_clicked(); /* 媒体状态改变 */ void mediaPlayerStateChanged(QMediaPlayer::State); /* 列表单击 */ void listWidgetCliked(QListWidgetItem*); /* 媒体列表项改变 */ void mediaPlaylistCurrentIndexChanged(int); /* 媒体总长度改变 */ void musicPlayerDurationChanged(qint64); /* 媒体播放位置改变 */ void mediaPlayerPositionChanged(qint64); /* 播放进度条松开 */ void durationSliderReleased(); }; #endif // MAINWINDOW_H
在源文件 “mainwindow.cpp” 具体代码如下:
#include "mainwindow.h" #include <QCoreApplication> #include <QFileInfoList> #include <QDir> #include <QProcess> QProcess * mypro; MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) { /* 布局初始化 */ musicLayout(); /* 媒体播放器初始化 */ mediaPlayerInit(); /* 扫描歌曲 */ scanSongs(); /* 按钮信号槽连接 */ connect(pushButton[0], SIGNAL(clicked()), this, SLOT(btn_previous_clicked())); connect(pushButton[1], SIGNAL(clicked()), this, SLOT(btn_play_clicked())); connect(pushButton[2], SIGNAL(clicked()), this, SLOT(btn_next_clicked())); /* 媒体信号槽连接 */ connect(musicPlayer, SIGNAL(stateChanged(QMediaPlayer::State)), this, SLOT(mediaPlayerStateChanged(QMediaPlayer::State))); connect(mediaPlaylist, SIGNAL(currentIndexChanged(int)), this, SLOT(mediaPlaylistCurrentIndexChanged(int))); connect(musicPlayer, SIGNAL(durationChanged(qint64)), this, SLOT(musicPlayerDurationChanged(qint64))); connect(musicPlayer, SIGNAL(positionChanged(qint64)), this, SLOT(mediaPlayerPositionChanged(qint64))); /* 列表信号槽连接 */ connect(listWidget, SIGNAL(itemClicked(QListWidgetItem*)), this, SLOT(listWidgetCliked(QListWidgetItem*))); /* slider信号槽连接 */ connect(durationSlider, SIGNAL(sliderReleased()), this, SLOT(durationSliderReleased())); /* 失去焦点 */ this->setFocus(); exit_button = new QPushButton(this); exit_button->setMinimumSize(50, 50); exit_button->setMaximumSize(50, 50); exit_button->move(760,440); exit_button->setStyleSheet("QPushButton{background:yellow}"); connect(exit_button,&QPushButton::clicked,[=](){ mypro->close(); exit(1);//退出程序 }); } void MainWindow::musicLayout() { /* 设置位置与大小,这里固定为800, 480 */ this->setGeometry(0, 0, 800, 480); QPalette pal; /* 按钮 */ for (int i = 0; i < 7; i++) pushButton[i] = new QPushButton(); /* 标签 */ for (int i = 0; i < 4; i++) label[i] = new QLabel(); for (int i = 0; i < 3; i++) { /* 垂直容器 */ vWidget[i] = new QWidget(); vWidget[i]->setAutoFillBackground(true); /* 垂直布局 */ vBoxLayout[i] = new QVBoxLayout(); } for (int i = 0; i < 4; i++) { /* 水平容器 */ hWidget[i] = new QWidget(); hWidget[i]->setAutoFillBackground(true); /* 水平布局 */ hBoxLayout[i] = new QHBoxLayout(); } /* 播放进度条 */ durationSlider = new QSlider(Qt::Horizontal); durationSlider->setMinimumSize(300, 15); durationSlider->setMaximumHeight(15); durationSlider->setObjectName("durationSlider"); /* 音乐列表 */ listWidget = new QListWidget(); listWidget->setObjectName("listWidget"); listWidget->resize(310, 265); listWidget->setVerticalScrollBarPolicy( Qt::ScrollBarAlwaysOff); listWidget->setHorizontalScrollBarPolicy( Qt::ScrollBarAlwaysOff); /* 列表遮罩 */ listMask = new QWidget(listWidget); listMask->setMinimumSize(310, 50); listMask->setMinimumHeight(50); listMask->setObjectName("listMask"); listMask->setGeometry(0, listWidget->height() - 50, 310, 50); /* 设置对象名称 */ pushButton[0]->setObjectName("btn_previous"); pushButton[1]->setObjectName("btn_play"); pushButton[2]->setObjectName("btn_next"); pushButton[3]->setObjectName("btn_favorite"); pushButton[4]->setObjectName("btn_mode"); pushButton[5]->setObjectName("btn_menu"); pushButton[6]->setObjectName("btn_volume"); /* 设置按钮属性 */ pushButton[1]->setCheckable(true); pushButton[3]->setCheckable(true); /* H0布局 */ vWidget[0]->setMinimumSize(310, 480); vWidget[0]->setMaximumWidth(310); vWidget[1]->setMinimumSize(320, 480); QSpacerItem *hSpacer0 = new QSpacerItem(70, 480, QSizePolicy::Minimum, QSizePolicy::Maximum); QSpacerItem *hSpacer1 = new QSpacerItem(65, 480, QSizePolicy::Minimum, QSizePolicy::Maximum); QSpacerItem *hSpacer2 = new QSpacerItem(60, 480, QSizePolicy::Minimum, QSizePolicy::Maximum); hBoxLayout[0]->addSpacerItem(hSpacer0); hBoxLayout[0]->addWidget(vWidget[0]); hBoxLayout[0]->addSpacerItem(hSpacer1); hBoxLayout[0]->addWidget(vWidget[1]); hBoxLayout[0]->addSpacerItem(hSpacer2); hBoxLayout[0]->setContentsMargins(0, 0, 0, 0); hWidget[0]->setLayout(hBoxLayout[0]); setCentralWidget(hWidget[0]); /* V0布局 */ listWidget->setMinimumSize(310, 265); hWidget[1]->setMinimumSize(310, 80); hWidget[1]->setMaximumHeight(80); label[0]->setMinimumSize(310, 95); label[0]->setMaximumHeight(95); QSpacerItem *vSpacer0 = new QSpacerItem(310, 10, QSizePolicy::Minimum, QSizePolicy::Maximum); QSpacerItem *vSpacer1 = new QSpacerItem(310, 30, QSizePolicy::Minimum, QSizePolicy::Minimum); vBoxLayout[0]->addWidget(label[0]); vBoxLayout[0]->addWidget(listWidget); vBoxLayout[0]->addSpacerItem(vSpacer0); vBoxLayout[0]->addWidget(hWidget[1]); vBoxLayout[0]->addSpacerItem(vSpacer1); vBoxLayout[0]->setContentsMargins(0, 0, 0, 0); vWidget[0]->setLayout(vBoxLayout[0]); /* H1布局 */ for (int i = 0; i < 3; i++) { pushButton[i]->setMinimumSize(80, 80); } QSpacerItem *hSpacer3 = new QSpacerItem(40, 80, QSizePolicy::Expanding, QSizePolicy::Expanding); QSpacerItem *hSpacer4 = new QSpacerItem(40, 80, QSizePolicy::Expanding, QSizePolicy::Expanding); hBoxLayout[1]->addWidget(pushButton[0]); hBoxLayout[1]->addSpacerItem(hSpacer3); hBoxLayout[1]->addWidget(pushButton[1]); hBoxLayout[1]->addSpacerItem(hSpacer4); hBoxLayout[1]->addWidget(pushButton[2]); hBoxLayout[1]->setContentsMargins(0, 0, 0, 0); hWidget[1]->setLayout(hBoxLayout[1]); /* V1布局 */ QSpacerItem *vSpacer2 = new QSpacerItem(320, 40, QSizePolicy::Minimum, QSizePolicy::Maximum); QSpacerItem *vSpacer3 = new QSpacerItem(320, 20, QSizePolicy::Minimum, QSizePolicy::Maximum); QSpacerItem *vSpacer4 = new QSpacerItem(320, 30, QSizePolicy::Minimum, QSizePolicy::Minimum); label[1]->setMinimumSize(320, 320); QImage Image; Image.load(":/images/cd.png"); QPixmap pixmap = QPixmap::fromImage(Image); int with = 320; int height = 320; QPixmap fitpixmap = pixmap.scaled(with, height, Qt::IgnoreAspectRatio, Qt::SmoothTransformation); label[1]->setPixmap(fitpixmap); label[1]->setAlignment(Qt::AlignCenter); vWidget[2]->setMinimumSize(300, 80); vWidget[2]->setMaximumHeight(80); vBoxLayout[1]->addSpacerItem(vSpacer2); vBoxLayout[1]->addWidget(label[1]); vBoxLayout[1]->addSpacerItem(vSpacer3); vBoxLayout[1]->addWidget(durationSlider); vBoxLayout[1]->addWidget(vWidget[2]); vBoxLayout[1]->addSpacerItem(vSpacer4); vBoxLayout[1]->setContentsMargins(0, 0, 0, 0); vWidget[1]->setLayout(vBoxLayout[1]); /* V2布局 */ QSpacerItem *vSpacer5 = new QSpacerItem(300, 10, QSizePolicy::Minimum, QSizePolicy::Maximum); hWidget[2]->setMinimumSize(320, 20); hWidget[3]->setMinimumSize(320, 60); vBoxLayout[2]->addWidget(hWidget[2]); vBoxLayout[2]->addSpacerItem(vSpacer5); vBoxLayout[2]->addWidget(hWidget[3]); vBoxLayout[2]->setContentsMargins(0, 0, 0, 0); vWidget[2]->setLayout(vBoxLayout[2]); /* H2布局 */ QFont font; font.setPixelSize(10); /* 设置标签文本 */ label[0]->setText("Q Music,Enjoy it!"); label[2]->setText("00:00"); label[3]->setText("00:00"); label[2]->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); label[3]->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); label[3]->setAlignment(Qt::AlignRight); label[2]->setAlignment(Qt::AlignLeft); label[2]->setFont(font); label[3]->setFont(font); pal.setColor(QPalette::WindowText, Qt::white); label[0]->setPalette(pal); label[2]->setPalette(pal); label[3]->setPalette(pal); hBoxLayout[2]->addWidget(label[2]); hBoxLayout[2]->addWidget(label[3]); hBoxLayout[2]->setContentsMargins(0, 0, 0, 0); hWidget[2]->setLayout(hBoxLayout[2]); /* H3布局 */ QSpacerItem *hSpacer5 = new QSpacerItem(0, 60, QSizePolicy::Minimum, QSizePolicy::Maximum); QSpacerItem *hSpacer6 = new QSpacerItem(80, 60, QSizePolicy::Maximum, QSizePolicy::Maximum); QSpacerItem *hSpacer7 = new QSpacerItem(80, 60, QSizePolicy::Maximum, QSizePolicy::Maximum); QSpacerItem *hSpacer8 = new QSpacerItem(80, 60, QSizePolicy::Maximum, QSizePolicy::Maximum); QSpacerItem *hSpacer9 = new QSpacerItem(0, 60, QSizePolicy::Minimum, QSizePolicy::Maximum); for (int i = 3; i < 7; i++) { pushButton[i]->setMinimumSize(25, 25); pushButton[i]->setMaximumSize(25, 25); } hBoxLayout[3]->addSpacerItem(hSpacer5); hBoxLayout[3]->addWidget(pushButton[3]); hBoxLayout[3]->addSpacerItem(hSpacer6); hBoxLayout[3]->addWidget(pushButton[4]); hBoxLayout[3]->addSpacerItem(hSpacer7); hBoxLayout[3]->addWidget(pushButton[5]); hBoxLayout[3]->addSpacerItem(hSpacer8); hBoxLayout[3]->addWidget(pushButton[6]); hBoxLayout[3]->addSpacerItem(hSpacer9); hBoxLayout[3]->setContentsMargins(0, 0, 0, 0); hBoxLayout[3]->setAlignment(Qt::AlignHCenter); hWidget[3]->setLayout(hBoxLayout[3]); //hWidget[0]->setStyleSheet("background-color:red"); //hWidget[1]->setStyleSheet("background-color:#ff5599"); //hWidget[2]->setStyleSheet("background-color:#ff55ff"); //hWidget[3]->setStyleSheet("background-color:black"); //vWidget[0]->setStyleSheet("background-color:#555555"); //vWidget[1]->setStyleSheet("background-color:green"); //vWidget[2]->setStyleSheet("background-color:gray"); } MainWindow::~MainWindow() { } void MainWindow::btn_play_clicked() { int state = musicPlayer->state(); switch (state) { case QMediaPlayer::StoppedState: /* 媒体播放 */ musicPlayer->play(); break; case QMediaPlayer::PlayingState: /* 媒体暂停 */ musicPlayer->pause(); break; case QMediaPlayer::PausedState: musicPlayer->play(); break; } } void MainWindow::btn_next_clicked() { musicPlayer->stop(); int count = mediaPlaylist->mediaCount(); if (0 == count) return; /* 列表下一个 */ mediaPlaylist->next(); musicPlayer->play(); } void MainWindow::btn_previous_clicked() { musicPlayer->stop(); int count = mediaPlaylist->mediaCount(); if (0 == count) return; /* 列表上一个 */ mediaPlaylist->previous(); musicPlayer->play(); } void MainWindow::mediaPlayerStateChanged( QMediaPlayer::State state) { switch (state) { case QMediaPlayer::StoppedState: pushButton[1]->setChecked(false); break; case QMediaPlayer::PlayingState: pushButton[1]->setChecked(true); break; case QMediaPlayer::PausedState: pushButton[1]->setChecked(false); break; } } void MainWindow::listWidgetCliked(QListWidgetItem *item) { musicPlayer->stop(); mediaPlaylist->setCurrentIndex(listWidget->row(item)); musicPlayer->play(); } void MainWindow::mediaPlaylistCurrentIndexChanged( int index) { if (-1 == index) return; /* 设置列表正在播放的项 */ listWidget->setCurrentRow(index); } void MainWindow::musicPlayerDurationChanged( qint64 duration) { durationSlider->setRange(0, duration / 1000); int second = duration / 1000; int minute = second / 60; second %= 60; QString mediaDuration; mediaDuration.clear(); if (minute >= 10) mediaDuration = QString::number(minute, 10); else mediaDuration = "0" + QString::number(minute, 10); if (second >= 10) mediaDuration = mediaDuration + ":" + QString::number(second, 10); else mediaDuration = mediaDuration + ":0" + QString::number(second, 10); /* 显示媒体总长度时间 */ label[3]->setText(mediaDuration); } void MainWindow::mediaPlayerPositionChanged( qint64 position) { if (!durationSlider->isSliderDown()) durationSlider->setValue(position/1000); int second = position / 1000; int minute = second / 60; second %= 60; QString mediaPosition; mediaPosition.clear(); if (minute >= 10) mediaPosition = QString::number(minute, 10); else mediaPosition = "0" + QString::number(minute, 10); if (second >= 10) mediaPosition = mediaPosition + ":" + QString::number(second, 10); else mediaPosition = mediaPosition + ":0" + QString::number(second, 10); /* 显示现在播放的时间 */ label[2]->setText(mediaPosition); } void MainWindow::resizeEvent(QResizeEvent *event) { Q_UNUSED(event); listMask->setGeometry(0, listWidget->height() - 50, 310, 50); } void MainWindow::durationSliderReleased() { /* 设置媒体播放的位置 */ musicPlayer->setPosition(durationSlider->value() * 1000); } void MainWindow::scanSongs() { QDir dir(QCoreApplication::applicationDirPath() + "/myMusic"); QDir dirbsolutePath(dir.absolutePath()); /* 如果目录存在 */ if (dirbsolutePath.exists()) { /* 定义过滤器 */ QStringList filter; /* 包含所有.mp3后缀的文件 */ filter << "*.mp3"; /* 获取该目录下的所有文件 */ QFileInfoList files = dirbsolutePath.entryInfoList(filter, QDir::Files); /* 遍历 */ for (int i = 0; i < files.count(); i++) { MediaObjectInfo info; /* 使用utf-8编码 */ QString fileName = QString::fromUtf8(files.at(i) .fileName() .replace(".mp3", "") .toUtf8() .data()); info.fileName = fileName + "\n" + fileName.split("-").at(1); info.filePath = QString::fromUtf8(files.at(i) .filePath() .toUtf8() .data()); /* 媒体列表添加歌曲 */ if (mediaPlaylist->addMedia( QUrl::fromLocalFile(info.filePath))) { /* 添加到容器数组里储存 */ mediaObjectInfo.append(info); /* 添加歌曲名字至列表 */ listWidget->addItem(info.fileName); } else { qDebug()<< mediaPlaylist->errorString() .toUtf8().data() << endl; qDebug()<< " Error number:" << mediaPlaylist->error() << endl; } } } } void MainWindow::mediaPlayerInit() { musicPlayer = new QMediaPlayer(this); mediaPlaylist = new QMediaPlaylist(this); /* 确保列表是空的 */ mediaPlaylist->clear(); /* 设置音乐播放器的列表为mediaPlaylist */ musicPlayer->setPlaylist(mediaPlaylist); /* 设置播放模式,Loop是列循环 */ mediaPlaylist->setPlaybackMode(QMediaPlaylist::Loop); }
上述代码就是常规的 QT 页面布局以及操作函数和信号,代码参考了正点原子的教程。特别需要注意的地方是需要在 QMusic 的功能页中加入退出按钮,即切换至其父进程!具体如下图:
运行结果:
视频播放器依旧是各家嵌入式机构QT练习的常规项目,与音乐播放器一样使用 QMediaPlayer 类,不同的是需要使用 setVideoOutput(QVideoWidget*) 设置一个视频输出窗口,好让视频在此窗口显示,其他步骤基本都一样。
★在项目文件 15_videoplayer.pro 文件第一行添加的代码:multimedia multimediawidgets
在头文件 “mainwindow.h” 具体代码如下
#ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QMainWindow> #include <QMediaPlayer> #include <QMediaPlaylist> #include <QPushButton> #include <QSlider> #include <QVBoxLayout> #include <QHBoxLayout> #include <QListWidget> #include <QLabel> #include <QSpacerItem> #include <QVideoWidget> #include <QDebug> /* 媒体信息结构体 */ struct MediaObjectInfo { /* 用于保存视频文件名 */ QString fileName; /* 用于保存视频文件路径 */ QString filePath; }; class MainWindow : public QMainWindow { Q_OBJECT public: MainWindow(QWidget *parent = nullptr); ~MainWindow(); private: /* 媒体播放器,用于播放视频 */ QMediaPlayer *videoPlayer; /* 媒体列表 */ QMediaPlaylist *mediaPlaylist; /* 视频显示窗口 */ QVideoWidget *videoWidget; /* 视频列表 */ QListWidget *listWidget; /* 播放进度条 */ QSlider *durationSlider; /* 音量条 */ QSlider *volumeSlider; /* 视频播放器按钮 */ QPushButton *pushButton[5]; QPushButton *exit_button; /* 水平布局 */ QHBoxLayout *hBoxLayout[3]; /* 水平容器 */ QWidget *hWidget[3]; /* 标签文本 */ QLabel *label[2]; /* 垂直容器 */ QWidget *vWidget[2]; /* 垂直界面 */ QVBoxLayout *vBoxLayout[2]; /* 视频布局函数 */ void videoLayout(); /* 主窗体大小重设大小函数重写 */ void resizeEvent(QResizeEvent *event); /* 媒体信息存储 */ QVector<MediaObjectInfo> mediaObjectInfo; /* 扫描本地视频文件 */ void scanVideoFiles(); /* 媒体初始化 */ void mediaPlayerInit(); private slots: /* 播放按钮点击 */ void btn_play_clicked(); /* 下一个视频按钮点击 */ void btn_next_clicked(); /* 音量加 */ void btn_volmeup_clicked(); /* 音量减 */ void btn_volmedown_clicked(); /* 全屏 */ void btn_fullscreen_clicked(); /* 媒体状态改变 */ void mediaPlayerStateChanged(QMediaPlayer::State); /* 列表单击 */ void listWidgetCliked(QListWidgetItem*); /* 媒体列表项改变 */ void mediaPlaylistCurrentIndexChanged(int); /* 媒体总长度改变 */ void musicPlayerDurationChanged(qint64); /* 媒体播放位置改变 */ void mediaPlayerPositionChanged(qint64); /* 播放进度条松开 */ void durationSliderReleased(); /* 音量条松开 */ void volumeSliderReleased(); }; #endif // MAINWINDOW_H
在源文件**“mainwindow.cpp”**具体代码如下:
#include "mainwindow.h" #include <QCoreApplication> #include <QFileInfoList> #include <QDir> #include <QProcess> QProcess * mypro; MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) { /* 视频播放器布局初始化 */ videoLayout(); /* 媒体初始化 */ mediaPlayerInit(); /* 扫描本地视频 */ scanVideoFiles(); /* 设置按钮的属性 */ pushButton[0]->setCheckable(true); pushButton[4]->setCheckable(true); /* 按钮连接信号槽 */ connect(pushButton[0], SIGNAL(clicked()), this, SLOT(btn_play_clicked())); connect(pushButton[1], SIGNAL(clicked()), this, SLOT(btn_next_clicked())); connect(pushButton[2], SIGNAL(clicked()), this, SLOT(btn_volmedown_clicked())); connect(pushButton[3], SIGNAL(clicked()), this, SLOT(btn_volmeup_clicked())); connect(pushButton[4], SIGNAL(clicked()), this, SLOT(btn_fullscreen_clicked())); /* 列表连接信号槽 */ connect(listWidget, SIGNAL(itemClicked(QListWidgetItem*)), this, SLOT(listWidgetCliked(QListWidgetItem*))); /* 媒体连接信号槽 */ connect(videoPlayer, SIGNAL(stateChanged(QMediaPlayer::State)), this, SLOT(mediaPlayerStateChanged(QMediaPlayer::State))); connect(mediaPlaylist, SIGNAL(currentIndexChanged(int)), this, SLOT(mediaPlaylistCurrentIndexChanged(int))); connect(videoPlayer, SIGNAL(durationChanged(qint64)), this, SLOT(musicPlayerDurationChanged(qint64))); connect(videoPlayer, SIGNAL(positionChanged(qint64)), this, SLOT(mediaPlayerPositionChanged(qint64))); /* slider信号槽连接 */ connect(durationSlider, SIGNAL(sliderReleased()), this, SLOT(durationSliderReleased())); connect(volumeSlider, SIGNAL(sliderReleased()), this, SLOT(volumeSliderReleased())); /* 退出按钮 */ exit_button = new QPushButton(this); exit_button->setMinimumSize(60, 50); exit_button->setMaximumSize(60, 50); exit_button->move(740,10); exit_button->setStyleSheet("QPushButton{background: black}"); connect(exit_button,&QPushButton::clicked,[=](){ mypro->close(); exit(1);//退出程序 }); } MainWindow::~MainWindow() { } void MainWindow::videoLayout() { /* 设置位置与大小,这里固定为800, 480 */ this->setGeometry(0, 0, 800, 480); // this->setMinimumSize(800, 480); // this->setMaximumSize(800, 480); QPalette pal; pal.setColor(QPalette::WindowText, Qt::white); for (int i = 0; i < 3; i++) { /* 水平容器 */ hWidget[i] = new QWidget(); hWidget[i]->setAutoFillBackground(true); /* 水平布局 */ hBoxLayout[i] = new QHBoxLayout(); } for (int i = 0; i < 2; i++) { /* 垂直容器 */ vWidget[i] = new QWidget(); vWidget[i]->setAutoFillBackground(true); /* 垂直布局 */ vBoxLayout[i] = new QVBoxLayout(); } for (int i = 0; i < 2; i++) { label[i] = new QLabel(); } for (int i = 0; i < 5; i++) { pushButton[i] = new QPushButton(); pushButton[i]->setMaximumSize(44, 44); pushButton[i]->setMinimumSize(44, 44); } /* 设置 */ vWidget[0]->setObjectName("vWidget0"); vWidget[1]->setObjectName("vWidget1"); hWidget[1]->setObjectName("hWidget1"); hWidget[2]->setObjectName("hWidget2"); pushButton[0]->setObjectName("btn_play"); pushButton[1]->setObjectName("btn_next"); pushButton[2]->setObjectName("btn_volumedown"); pushButton[3]->setObjectName("btn_volumeup"); pushButton[4]->setObjectName("btn_screen"); QFont font; font.setPixelSize(18); label[0]->setFont(font); label[1]->setFont(font); pal.setColor(QPalette::WindowText, Qt::white); label[0]->setPalette(pal); label[1]->setPalette(pal); label[0]->setText("00:00"); label[1]->setText("/00:00"); durationSlider = new QSlider(Qt::Horizontal); durationSlider->setMaximumHeight(15); durationSlider->setObjectName("durationSlider"); volumeSlider = new QSlider(Qt::Horizontal); volumeSlider->setRange(0, 100); volumeSlider->setMaximumWidth(80); volumeSlider->setObjectName("volumeSlider"); volumeSlider->setValue(50); listWidget = new QListWidget(); listWidget->setObjectName("listWidget"); listWidget->setVerticalScrollBarPolicy( Qt::ScrollBarAlwaysOff); listWidget->setHorizontalScrollBarPolicy( Qt::ScrollBarAlwaysOff); //listWidget->setFocusPolicy(Qt::NoFocus); videoWidget = new QVideoWidget(); videoWidget->setStyleSheet("border-image: none;" "background: transparent;" "border:none"); /* H0布局 */ vWidget[0]->setMinimumSize(300, 480); vWidget[0]->setMaximumWidth(300); videoWidget->setMinimumSize(500, 480); hBoxLayout[0]->addWidget(videoWidget); hBoxLayout[0]->addWidget(vWidget[0]); hWidget[0]->setLayout(hBoxLayout[0]); hBoxLayout[0]->setContentsMargins(0, 0, 0, 0); setCentralWidget(hWidget[0]); /* V0布局 */ QSpacerItem *vSpacer0 = new QSpacerItem(0, 80, QSizePolicy::Minimum, QSizePolicy::Maximum); vBoxLayout[0]->addWidget(listWidget); vBoxLayout[0]->addSpacerItem(vSpacer0); vBoxLayout[0]->setContentsMargins(0, 0, 0, 0); vWidget[0]->setLayout(vBoxLayout[0]); /* V1布局 */ /* 底板部件布局 */ hWidget[1]->setMaximumHeight(15); hWidget[2]->setMinimumHeight(65); vBoxLayout[1]->addWidget(hWidget[1]); vBoxLayout[1]->addWidget(hWidget[2]); vBoxLayout[1]->setAlignment(Qt::AlignCenter); vWidget[1]->setLayout(vBoxLayout[1]); vWidget[1]->setParent(this); vWidget[1]->setGeometry(0, this->height() - 80, this->width(), 80); vBoxLayout[1]->setContentsMargins(0, 0, 0, 0); /* 位于最上层 */ vWidget[1]->raise(); /* H1布局 */ hBoxLayout[1]->addWidget(durationSlider); hBoxLayout[1]->setContentsMargins(0, 0, 0, 0); hWidget[1]->setLayout(hBoxLayout[1]); /* H2布局 */ QSpacerItem *hSpacer0 = new QSpacerItem(300, 80, QSizePolicy::Expanding, QSizePolicy::Maximum); hBoxLayout[2]->addSpacing(20); hBoxLayout[2]->addWidget(pushButton[0]); hBoxLayout[2]->addSpacing(10); hBoxLayout[2]->addWidget(pushButton[1]); hBoxLayout[2]->addSpacing(10); hBoxLayout[2]->addWidget(pushButton[2]); hBoxLayout[2]->addWidget(volumeSlider); hBoxLayout[2]->addWidget(pushButton[3]); hBoxLayout[2]->addWidget(label[0]); hBoxLayout[2]->addWidget(label[1]); hBoxLayout[2]->addSpacerItem(hSpacer0); hBoxLayout[2]->addWidget(pushButton[4]); hBoxLayout[2]->addSpacing(20); hBoxLayout[2]->setContentsMargins(0, 0, 0, 0); hBoxLayout[2]->setAlignment(Qt::AlignLeft | Qt::AlignTop); hWidget[2]->setLayout(hBoxLayout[2]); } void MainWindow::mediaPlayerInit() { videoPlayer = new QMediaPlayer(this); mediaPlaylist = new QMediaPlaylist(this); /* 确保列表是空的 */ mediaPlaylist->clear(); /* 设置视频播放器的列表为mediaPlaylist */ videoPlayer->setPlaylist(mediaPlaylist); /* 设置视频输出窗口 */ videoPlayer->setVideoOutput(videoWidget); /* 设置播放模式,Loop是列循环 */ mediaPlaylist->setPlaybackMode(QMediaPlaylist::Loop); /* 设置默认软件音量为50% */ videoPlayer->setVolume(50); } void MainWindow::resizeEvent(QResizeEvent *event) { Q_UNUSED(event); vWidget[1]->setGeometry(0, this->height() - 80, this->width(), 80); } void MainWindow::btn_play_clicked() { int state = videoPlayer->state(); switch (state) { case QMediaPlayer::StoppedState: /* 媒体播放 */ videoPlayer->play(); break; case QMediaPlayer::PlayingState: /* 媒体暂停 */ videoPlayer->pause(); break; case QMediaPlayer::PausedState: /* 设置视频输出窗口 */ videoPlayer->play(); break; } } void MainWindow::btn_next_clicked() { videoPlayer->stop(); int count = mediaPlaylist->mediaCount(); if (0 == count) return; /* 列表下一个 */ mediaPlaylist->next(); videoPlayer->play(); } void MainWindow::btn_volmeup_clicked() { /* 点击每次音量+5 */ volumeSlider->setValue(volumeSlider->value() + 5); videoPlayer->setVolume(volumeSlider->value()); } void MainWindow::btn_fullscreen_clicked() { /* 全屏/非全屏操作 */ vWidget[0]->setVisible(!pushButton[4]->isChecked()); } void MainWindow::btn_volmedown_clicked() { /* 点击每次音量-5 */ volumeSlider->setValue(volumeSlider->value() - 5); videoPlayer->setVolume(volumeSlider->value()); } void MainWindow::mediaPlayerStateChanged( QMediaPlayer::State state) { switch (state) { case QMediaPlayer::StoppedState: pushButton[0]->setChecked(false); break; case QMediaPlayer::PlayingState: pushButton[0]->setChecked(true); break; case QMediaPlayer::PausedState: pushButton[0]->setChecked(false); break; } } void MainWindow::listWidgetCliked(QListWidgetItem *item) { videoPlayer->stop(); mediaPlaylist->setCurrentIndex(listWidget->row(item)); videoPlayer->play(); } void MainWindow::mediaPlaylistCurrentIndexChanged( int index) { if (-1 == index) return; /* 设置列表正在播放的项 */ listWidget->setCurrentRow(index); } void MainWindow::musicPlayerDurationChanged( qint64 duration) { durationSlider->setRange(0, duration / 1000); int second = duration / 1000; int minute = second / 60; second %= 60; QString mediaDuration; mediaDuration.clear(); if (minute >= 10) mediaDuration = QString::number(minute, 10); else mediaDuration = "0" + QString::number(minute, 10); if (second >= 10) mediaDuration = mediaDuration + ":" + QString::number(second, 10); else mediaDuration = mediaDuration + ":0" + QString::number(second, 10); /* 显示媒体总长度时间 */ label[1]->setText("/" + mediaDuration); } void MainWindow::mediaPlayerPositionChanged( qint64 position) { if (!durationSlider->isSliderDown()) durationSlider->setValue(position / 1000); int second = position / 1000; int minute = second / 60; second %= 60; QString mediaPosition; mediaPosition.clear(); if (minute >= 10) mediaPosition = QString::number(minute, 10); else mediaPosition = "0" + QString::number(minute, 10); if (second >= 10) mediaPosition = mediaPosition + ":" + QString::number(second, 10); **自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。** **深知大多数嵌入式工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!** **因此收集整理了一份《2024年嵌入式&物联网开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。** ![img](https://img-blog.csdnimg.cn/img_convert/7fbe485d8d4baf081563f6c6a3a54f96.png) ![img](https://img-blog.csdnimg.cn/img_convert/57f96529bf1b7657b9846431769aa798.jpeg) ![img](https://img-blog.csdnimg.cn/img_convert/56bccad9ddc61e6d0ba8dc2cbd8469c3.png) **既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上嵌入式&物联网开发知识点,真正体系化!** ![img](https://img-blog.csdnimg.cn/img_convert/f4b3a8b286b9286f478cee96e674a3dc.png) ![img](https://img-blog.csdnimg.cn/img_convert/a9dc63d0350e5c25562e8ca7f9ff81b8.png) **由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新** **如果你觉得这些内容对你有帮助,可以+V:Vip1104z获取!!! (备注:嵌入式)** <img src="https://img-community.csdnimg.cn/images/73bb5de17851459088c6af944156ee24.jpg" alt="img" style="zoom: 67%;" /> # 最后 **资料整理不易,觉得有帮助的朋友可以帮忙点赞分享支持一下小编~** **你的支持,我的动力;祝各位前程似锦,offer不断,步步高升!!!** /* 显示媒体总长度时间 */ label[1]->setText("/" + mediaDuration); } void MainWindow::mediaPlayerPositionChanged( qint64 position) { if (!durationSlider->isSliderDown()) durationSlider->setValue(position / 1000); int second = position / 1000; int minute = second / 60; second %= 60; QString mediaPosition; mediaPosition.clear(); if (minute >= 10) mediaPosition = QString::number(minute, 10); else mediaPosition = "0" + QString::number(minute, 10); if (second >= 10) mediaPosition = mediaPosition + ":" + QString::number(second, 10); **自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。** **深知大多数嵌入式工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!** **因此收集整理了一份《2024年嵌入式&物联网开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。** [外链图片转存中...(img-OqHqMWfJ-1712382462148)] [外链图片转存中...(img-PmH8rlSC-1712382462149)] [外链图片转存中...(img-75sdQibn-1712382462150)] **既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上嵌入式&物联网开发知识点,真正体系化!** [外链图片转存中...(img-wRgIHtu7-1712382462151)] [外链图片转存中...(img-znu7l7JS-1712382462152)] **由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新** **如果你觉得这些内容对你有帮助,可以+V:Vip1104z获取!!! (备注:嵌入式)** <img src="https://img-community.csdnimg.cn/images/73bb5de17851459088c6af944156ee24.jpg" alt="img" style="zoom: 67%;" /> # 最后 **资料整理不易,觉得有帮助的朋友可以帮忙点赞分享支持一下小编~** **你的支持,我的动力;祝各位前程似锦,offer不断,步步高升!!!** **[更多资料点击此处获qu!!](https://bbs.csdn.net/topics/618376385)**
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。