自适应网站 响应式网站,个人网站包括哪些内容,心理咨询在线免费咨询,长沙建设教育网站上篇文章#xff1a;嵌入式 Qt开发一个音乐播放器#xff0c;使用Qt制作了一个音乐播放器#xff0c;并在OK3568开发板上进行了运行测试#xff0c;实际测试效果还不错。
本篇继续来实现一个Qt视频播放器软件#xff0c;可以实现视频列表的显示与选择播放等#xff0c;先…上篇文章嵌入式 Qt开发一个音乐播放器使用Qt制作了一个音乐播放器并在OK3568开发板上进行了运行测试实际测试效果还不错。
本篇继续来实现一个Qt视频播放器软件可以实现视频列表的显示与选择播放等先来看下最终的效果 本篇的Qt代码从野火开发板的例程中移植修改而来下面分析下程序的代码结构。
1 视频播放器开发总体结构
整个Qt视频播放器项目的代码结构如下
主代码中是视频播放器相关的代码包括 视频播放器主界面视频名列表界面在视频播放时可以查看视频列表并切换视频Qt视频播放界面实现单纯的视频播放操作按钮界面实现播放、暂停、继续、上一个、下一个、进度调节音量调节播放预览列表界面在进入视频播放之前的视频预览列表界面 Ui代码中使用一些Qt的基本功能包括 一个Qt界面基类滑条功能类图标按钮显示类列表功能类工具类视频帧解析页面列表类 Skin中是一些图片资源和字体/皮肤定义最后是编译的中间文件和编译结果存储的目录 下面分类介绍了程序的主要代码实现。
2 通用界面代码
上篇介绍音乐播放器时介绍过一些自定义控件的代码本篇的视频播放器可以复用这些代码
qtwidgetbase窗口基类该类的一个主要功能是可以向窗口内添加图片形式的按钮qtsliderbar用于实现自定义滑条控件分为水平滑条与竖直滑条qtpixmapbutton图片按钮支持未按下和按下后的两种样式的图片显示qtlistwidget 基础的列表显示
相比于音乐播放器视频播放器还需要其它额外的功能如下
2.1 qttoolbar
工具条的基类通过创建一个QPropertyAnimation属性动画对象主要实现工具条的显示与隐藏的动画效果。
例如在用户无操作一段时间后将上方的标题栏和下方的播放工具栏隐藏。 主要代码如下
QtToolBar::QtToolBar(QWidget *parent) : QtWidgetBase(parent)
{m_animation new QPropertyAnimation(this, pos);m_animation-setDuration(200);m_animation-setEasingCurve(QEasingCurve::Linear);connect(m_animation, SIGNAL(finished()), this, SIGNAL(signalFinihed()));
}void QtToolBar::SetAnimation(const QPoint startPos, const QPoint endPos)
{m_animation-setStartValue(startPos);m_animation-setEndValue(endPos);m_animation-start();
}2.2 qtvideowidgetsurface
视频帧解析类继承自QAbstractVideoSurface类这是一个抽象基类通过实现它的派生类可以获取来自QMediaPlayer或QCamera视频的帧。
supportedPixelFormats 用于向Qt返回帧流的图像类型present 用于获取到每一帧
class QtVideoWidgetSurface : public QAbstractVideoSurface
{Q_OBJECT
public:QtVideoWidgetSurface(QWidget *widget, QObject *parent 0);QListQVideoFrame::PixelFormat supportedPixelFormats(QAbstractVideoBuffer::HandleType handleType QAbstractVideoBuffer::NoHandle) const;bool isFormatSupported(const QVideoSurfaceFormat format) const;bool start(const QVideoSurfaceFormat format);void stop();bool present(const QVideoFrame frame);QRect videoRect() const { return targetRect; }void updateVideoRect();void paint(QPainter *painter);private:QWidget *widget;QImage::Format imageFormat;QRect targetRect;QSize imageSize;QRect sourceRect;QVideoFrame currentFrame;
};2.3 qtpagelistwidget
页面形式的预览排布以及左右页面的滑动切换
2.3.1 QtPageListWidgetItem
该类用于表示列表中的每一个项可以是字符并且可以带有图片(图标)
class QtPageListWidgetItem
{
public:QtPageListWidgetItem(int id, const QStringList args);QtPageListWidgetItem(int id, const QString name);QtPageListWidgetItem(int id, const QString name, const QPixmap icon);QtPageListWidgetItem(int id, const QString path, const QString name, const QPixmap icon);int m_nId;QString m_strText;QPixmap m_pixmapIcon;QString m_strBaseName;QString m_strPath;QRect m_rect;QStringList m_strMultiParameters;
};2…3.2 QtPageListWidget
class QtPageListWidget : public QtWidgetBase
{Q_OBJECT
public:typedef enum{None,LeftDirection,RightDirection} MoveDirection;Q_PROPERTY(int xPos READ Xpos WRITE setXPos)explicit QtPageListWidget(QWidget *parent 0);~QtPageListWidget();void AddItem(int id, QtPageListWidgetItem *item);void SetItems(const QMapint, QtPageListWidgetItem * items);void SetBackground(const QPixmap pixmap);void SetBackground(const QColor color);void SetPageCount(int count);void SetItemLayut(int rows, int columns);void SetItemLayoutSpace(int row, int col);void SetLoopbackChange(bool bOk);signals:void currentItemClicked(QtPageListWidgetItem *item);void currentPageChanged(int index);protected:QMapint, QtPageListWidgetItem * m_listItems;// skinQColor m_backgroundColor;QPixmap m_pixmapWallpaper;int m_nPageCnt;int m_nCurrentPage;int m_nPrevPage;int m_nLayoutRows;int m_nLayoutColumns;qreal m_nItemWidth;qreal m_nItemHeight;int m_nDirection;QTimer *m_timerMove;bool m_bLoopbackChange;QPropertyAnimation *m_animationMove;private:bool m_bPressed;QPoint m_startPos;int m_nStartPos;int m_nMoveEndValue;bool m_bRecovery;private:void setXPos(int nValue);int Xpos() { return m_nStartPos; }void resizeRect();
private slots:protected:int m_nCurrentIndex;int m_nHorSpace;int m_nVSpace;protected:void mousePressEvent(QMouseEvent *e);void mouseReleaseEvent(QMouseEvent *);void mouseMoveEvent(QMouseEvent *e);void paintEvent(QPaintEvent *);void drawListItem(QPainter *painter, int page, int xOffset 0);virtual void drawItemInfo(QPainter *painter, QtPageListWidgetItem *item);
};注意该类和qtlistwidget类的功能比较相似
3 视频播放器代码
首先是整体的主界面部分进行各项功能的初始化显示主要包括
播放列表初始化视频预览列表界面视频播放界面初始化先隐藏播放界面
界面效果如下 主要代码逻辑
{QtWidgetTitleBar *m_widgetTitle new QtWidgetTitleBar(this);m_widgetTitle-SetScalSize(Skin::m_nScreenWidth, 80);m_widgetTitle-SetBackground(Qt::transparent);m_widgetTitle-setFont(QFont(Skin::m_strAppFontNormal));m_widgetTitle-SetTitle(tr(视频播放器), #ffffff, 32);QVBoxLayout *verLayoutCentor new QVBoxLayout(this);verLayoutCentor-setContentsMargins(0, 0, 0, 0);verLayoutCentor-setSpacing(0);verLayoutCentor-addWidget(m_widgetTitle, 1);// 播放列表(视频预览列表界面)m_videosList new VideoListViewer(this);m_videosList-SetBackground(Qt::transparent);connect(m_videosList, SIGNAL(currentItemClicked(QtPageListWidgetItem *)), this, SLOT(SltItemClicked(QtPageListWidgetItem *)));verLayoutCentor-addWidget(m_videosList, 5);// 视频播放界面(先隐藏播放界面)m_videoWidget new QtVideoWidget(this);m_videoWidget-hide();
}初始化各个界面后还要连接对应的槽函数如切换视频播放列表中的视频时的处理等。
3.1 视频播放
视频播放部分主要有两部分功能
视频解码播放使用Qt自带的媒体播放器组件进行音频播放播放时的按钮操作实现播放、暂停、继续、上一个、下一个、进度调节音量调节 3.1.1 QMediaPlayer播放视频
这里使用Qt自带的QMediaPlayer组件进行视频的播放QMediaPlayer播放视频于播放音频的步骤类似。
本项目的视频播放初始化部分
QtVideoWidget::QtVideoWidget(QWidget *parent) : QtWidgetBase(parent)
{m_urlMedia QUrl();m_bToolBarShow false;m_nDuration 0;m_nPostion 0;m_player new QMediaPlayer(this);surface new QtVideoWidgetSurface(this);m_player-setVideoOutput(surface);m_playList new MediaPlayListWidget(this);m_playList-setVisible(false);m_player-setPlaylist(m_playList-palyList());connect(m_player, SIGNAL(durationChanged(qint64)), this, SLOT(SltDurationChanged(qint64)));connect(m_player, SIGNAL(positionChanged(qint64)), this, SLOT(SltPostionChanged(qint64)));m_titleBar new PlayTitleBarWidget(this);connect(m_playList, SIGNAL(signalMediaChanged(QString)), m_titleBar, SLOT(SetText(QString)));connect(m_titleBar, SIGNAL(signalBack()), this, SLOT(SltBackClicked()));m_playBar new PlayerBarWidget(this);connect(m_playBar, SIGNAL(signalPlay(bool)), this, SLOT(SltBtnPlayClicked(bool)));connect(m_playBar, SIGNAL(currentPostionChanged(int)), this, SLOT(SltChangePostion(int)));connect(m_playBar, SIGNAL(signalPrev()), m_playList-palyList(), SLOT(previous()));connect(m_playBar, SIGNAL(signalNext()), m_playList-palyList(), SLOT(next()));connect(m_playBar, SIGNAL(signalMuenList()), this, SLOT(SltShowMenuList()));connect(m_playBar, SIGNAL(signalVolume()), this, SLOT(SltChangeVolume()));m_timerShow new QTimer(this);m_timerShow-setSingleShot(true);m_timerShow-setInterval(5000);connect(m_timerShow, SIGNAL(timeout()), this, SLOT(SltAutoCloseToolBar()));m_volumeSlider new QtSliderBar(this);m_volumeSlider-SetHorizontal(false);m_volumeSlider-SetValue(100);m_volumeSlider-hide();connect(m_volumeSlider, SIGNAL(currentValueChanged(int)), m_player, SLOT(setVolume(int)));
}3.1.2 播放操作按钮
视频播放时需要用到播放、暂停、继续、上一个、下一个、进度调节、音量调节等操作按钮这里的对应按钮使用图标显示为对应的按钮通过加载QPixmap来实现
void PlayerBarWidget::InitWidget()
{m_btns.insert(0, new QtPixmapButton(0, QRect(295, 40, 60, 60), QPixmap(:/images/video/ic_prev.png), QPixmap(:/images/video/ic_prev_pre.png)));m_btns.insert(1, new QtPixmapButton(1, QRect(375, 40, 60, 60), QPixmap(:/images/video/ic_play.png), QPixmap(:/images/video/ic_pause.png)));m_btns.insert(2, new QtPixmapButton(2, QRect(465, 40, 60, 60), QPixmap(:/images/video/ic_next.png), QPixmap(:/images/video/ic_next_pre.png)));m_btns.insert(3, new QtPixmapButton(3, QRect(655, 40, 60, 60), QPixmap(:/images/video/ic_volume.png), QPixmap(:/images/video/ic_volume_pre.png)));m_btns.insert(4, new QtPixmapButton(4, QRect(728, 40, 60, 60), QPixmap(:/images/video/ic_list.png), QPixmap(:/images/video/ic_list_pre.png)));m_btns.value(1)-setCheckAble(true);// 进度条m_progressBar new QtSliderBar(this);m_progressBar-SetHorizontal(true);m_progressBar-SetSliderSize(2, 40);connect(m_progressBar, SIGNAL(currentValueChanged(int)), this, SIGNAL(currentPostionChanged(int)));
}3.2 播放列表
播放列表功能用来实现视频文件的显示以及手动指定切换要播放的视频。 3.2.1 读取视频文件
通过读取指定目录下的文件查找类型为mp4的视频文件构造视频播放列表。
void MediaPlayListWidget::ScanDirMedias(const QString path)
{QDir dir(path);if (!dir.exists())return;dir.setFilter(QDir::Dirs | QDir::Files);dir.setSorting(QDir::DirsFirst);QFileInfoList list dir.entryInfoList();int index m_mapItems.size();for (int i 0; i list.size(); i){QFileInfo fileInfo list.at(i);if (fileInfo.fileName() . || fileInfo.fileName() ..){continue;}if (fileInfo.isDir()){ScanDirMedias(fileInfo.filePath());}else if (fileInfo.suffix() mp4){QString strName fileInfo.baseName().toLocal8Bit().constData();QString strPath fileInfo.absoluteFilePath().toLocal8Bit().constData();m_playList-addMedia(QUrl::fromLocalFile(strPath));m_mapItems.insert(index, new QtListWidgetItem(index, strPath, strName, QPixmap(:/images/video/ic_video_preview.png)));index;}}
}3.2.2 视频列表界面
视频列表的具体界面实现主要是在对应的矩形位置显示各个视频文件的名称
void VideoListViewer::drawItemInfo(QPainter *painter, QtPageListWidgetItem *item)
{painter-save();QFont font(Skin::m_strAppFontBold);font.setPixelSize(18);painter-setFont(font);QPixmap pixmap item-m_pixmapIcon;int nXoffset (item-m_rect.width() - pixmap.width()) / 2;int nYoffset (item-m_rect.height() - pixmap.height() - painter-fontMetrics().height() - 10) / 2;QRect rectPixmap(nXoffset item-m_rect.left(), item-m_rect.top() nYoffset, pixmap.width(), pixmap.height());if (pixmap.isNull()){painter-setPen(QColor(#7effffff));painter-drawRect(item-m_rect);}else{painter-drawPixmap(rectPixmap.topLeft(), pixmap);}painter-setPen(Qt::white);painter-drawText(item-m_rect.left(), rectPixmap.bottom() 10, item-m_rect.width(), 30, Qt::AlignCenter, item-m_strBaseName);painter-restore();
}3.3 视频预览列表
在进入正式的视频播放前会先有一个视频预览列表界面在这个界面会列出指定搜索目录下的所有视频点击任意视频图标即可进入播放界面。 此部分的列表绘制代码逻辑如下
void QtPageListWidget::drawItemInfo(QPainter *painter, QtPageListWidgetItem *item)
{painter-save();QRect rect item-m_rect;int nXoffset (rect.width() ICON_SIZE) ? (rect.width() - ICON_SIZE) / 2 : 0;QRect rectPixmap(rect.left() nXoffset ICON_SIZE / 2, rect.top() ICON_SIZE / 2, ICON_SIZE, ICON_SIZE);if (item-m_pixmapIcon.isNull()){painter-setPen(Qt::NoPen);painter-setBrush(QColor(#02a7f0));painter-drawEllipse(rectPixmap.topLeft(), ICON_SIZE / 2, ICON_SIZE / 2);}else{painter-drawPixmap(rect.left() nXoffset, rect.top(), item-m_pixmapIcon);}if (m_nCurrentIndex item-m_nId){painter-setPen(Qt::NoPen);painter-setBrush(QColor(#32000000));painter-drawEllipse(rectPixmap.topLeft(), ICON_SIZE / 2, ICON_SIZE / 2);}QFont font painter-font();font.setPixelSize(16);painter-setFont(font);painter-setPen(#ffffff);int nTextHeight painter-fontMetrics().height();QRect rectText(rect.left(), rect.bottom() - nTextHeight, rect.width(), nTextHeight);painter-drawText(rectText, Qt::AlignCenter, item-m_strText);painter-restore();
}4 编译与测试
4.1 在Windows平台编译
Qt程序编写好后可以先在Windows电脑上编译查看效果在运行时可能会遇到如下问题
DirectShowPlayerService::doRender: Unresolved error code 0x80040266 (IDispatch error #102)编译的时候没问题但运行的时候报错 这是因为Qt 中的多媒体播放底层是使用DirectShowPlayerService所以Windows电脑上需要先安装一个DirectShow解码器例如LAV Filters。可以到这里https://github.com/Nevcairiel/LAVFilters/releases下载并安装 LAVFilters 下载exe安装包安装即可安装后再运行就不会报错了在Windows系统上运行视频播放器的效果如下 4.2 交叉编译并在板子上运行
通过交叉编译来测试视频播放器在OK3568-C板子上的播放效果。
使用编译音乐播放器时编写my3568build.sh的编译脚本编译即可无需修改
#! /bin/bashmkdir -p build
cd buildexport PATH/home/xxpcb/myTest/OK3568/sourcecode/OK3568-linux-source/buildroot/output/OK3568/host/bin:$PATHqmake .. make执行该脚本即可编译:
./my3568build.sh 将编译成功的可执行文件VIdeoPlayer复制到OK3568-C板子中然后在其同目录下创建一个video文件夹里面放入若干个mp4视频文件然后就可以测试了此外代码中还指定了/userdata/media这个搜索目录这里有板子自带的一些视频 文件复制到板子我这里仍然使用的ADB无线传输的方式比较方便具体ADB操作演示可参考之前这篇文章: RK3568源码编译与交叉编译环境搭建最后的Qt交叉编译与测试部分
需注意的是板子里的这个Linux系统不支持中文的显示视频名不要有中文。
实测效果见文末视频整体体验播放流畅视频切换流程进度条调整播放进度没有音乐播放器调整的顺畅另外不知道怎么原因视频播放的声音外放声音特别小用耳机插孔听是正常的。
5 总结
本篇介绍了使用Qt开发一个视频播放器一些功能代码是复用上篇的音乐播放器的代码使用Qt Creator编写视频播放器的代码首先在Windows电脑上编译运行测试然后交叉编译在OK3568-C开发板上进行实际测试。
该视频播放器实现的功能包括基础的播放功能、暂停与继续音量调节视频列表显示下一个、下一个切换进度条调节播放进度等。