使用QT编写视频播放器总结

本文是关于基于QMediaPlayer的播放器的总结,一开始我的想法就是想用opencv做一个视频播放器,因为opencv平时用的也比较顺手,但是花了半天的时间实际一做才知道事情没那么简单,首先使用opencv加载本地视频文件到界面上就花了不少时间,在使用qt播放opencv传过来的视频的时候播放的基本原理还是没变,仍然是一帧一帧的连续输出就形成了视频。但是这个地方有好几个要注意的地方,首先,opencv自带的waikey函数在qt里面不能用,因为本身waikey函数在opencv播放视频时是用来设置帧间的时间间距的,此时必须要根据视频的帧率来设置帧数之间的时间间隔;其次,waikey函数在opencv中使用习惯了没注意到,这个函数本身是和其他函数配合起到持续输出帧数的作用,在输出的过程中必须有。。。(这个地方忘了,先搁置一下);因此如果直接在qt中使用这个函数的话会出现没有画面的情况,为此,我们需要选用qt里面的Qtimer控件,进行输出间隔的控制,然后还是根据视频的帧数设置输出间隔。以上工作都搞得差不多了之后,我发现了一个最操蛋的事,这样使用opencv输出来的视频是没有声音的!前前后后搞了一个下午,浪费了不少时间,但是也算是加深了对opencv进一步的了解了吧。
使用QT编写视频播放器总结_第1张图片
通过网上的查阅和与师兄的沟通发现,原来做视频播放器的库有很多,包括qt自带的QMediaPlayer、ffmpeg等等,本来听说ffmpeg还不错,但是一到官网一看没有直接的安装包,心想还是用qt自带的库吧。下面是我在使用QMediaPlayer过程中遇到的一些困难和解决问题的办法。
由于我是qt初学者,对qt中的很多机制还不是特别的了解,但是通过做了这么一个小例子,我把基本的一些问题都搞的比较清楚了,最起码后面再碰到大部分问题时心里有个方向了。
首先是Qtimer这个控件的使用上,之前对槽与信号了解的也不是很深,以为大部分槽都可以在界面上找到,但是我这个项目做的越深越发现原来很多界面的设置可以用代码实现,一旦用了代码就不能简单的使用界面一点直接跳转的方式来写槽与信号了。我对信号的理解就是,信号本身就是一个函数,但是不能被定义,并且要在头文件里用signals关键字指出,信号不能有返回值,它仅代表在某个控件或窗体上出发了某个东西,然后由信号就会产生对应的槽函数,槽函数是和普通函数没太大差别的函数,它本身要以关键字slots在头文件中指出,在定义的时候可以写入任意的操作。并且信号与槽机制在子窗体和父窗体的值的传递中起着重要作用,可以使用槽与信号实现父窗体传值到子窗体,也可以实现子窗体传值到父窗体,也就是说,有了槽与信号,可以很灵活的控制子父窗体数据之间的联系。Qtimer这个控件的大部分使用都是和信号与槽结合在一起的,connect(timer,SIGNAL(timeOut()),this,SLOT(on_timeout()));通过初始化一个timer并且设置其时间间隔,以毫秒为单位,之后每过一个时间间隔,就会发出一个信号使槽函数开始运行,知道设置timer.stop(),信号停止发送。因此利用QTimer这个控件可以实现很多定时操作。在这个项目里面主要是用来设置当播放视频全屏时鼠标悬浮一段时间之后自动隐藏,然后在鼠标移动之后重新出现鼠标指针,但是这个地方有个问题,鼠标移动必须按住任意一个按键才能使指针显示出来,并且我使用的就是MouseMoveEvent(),这个问题目前还没解决。
然后就是界面的布局上,之前对qt的界面布局很迷,因为一开始学习编程时接触了一段时间的C#,C#的界面布局感觉要简单很多,但是这么几天我发现其实qt的布局也很方便,一旦理解了就很容易做出来比较好看的布局。关于布局第一点是五种布局方式,垂直、水平、栅格、群组等,在布局的时候我发现视频和控制按钮得分割开,我一开始是不知道用什么方式的,后来在网上一查,可以使用QSplitter进行分割,QSplitter也是控件,并且是由分割线和本体组成的,分割线的粗细和颜色都可以自定义设置,但是粗细只能是整数,因此无法设置小于一的线宽,一般默认情况下Qsplitter的分割线是可以被移动的,但是也可以通过设置分割线的属性值setEnabled来设置其不可调整比例,主要用法如下
QSplitterHandle *pHandle = splitter->handle(1); pHandle->setEnabled(false); pHandle->setStyleSheet("background-color:rgba(0,48,77,0.7)"); QSplitterHandle *cHandle = splitter_video->handle(1); cHandle->setEnabled(false); cHandle->setStyleSheet("background-color:rgba(0,48,77,0.7)");
主要就是通过获取splitter的handle值来单独设置,网上很多说可以利用setOpaque函数的值来设置的,我始终没设置成功,最终就是用的上述方法来设置的。此外关于splitter的一点就是初始比例如果不设置的话就是默认的1:1,在某些情况下自己设置的比例如果不生效就会自动采用默认比例。我这个项目里主要用到了两个splitter,所以在分割的时候一定注意比例的问题,当时一开始我怎么设置都不生效,后来我发现对于QMainWindow本身要设置一个主窗体,因为中间的窗口很多,会涉及到冲突的问题,我的做法是用一个最大的splitter设置为窗体的主窗体,然后其他所有的布局都在这上面进行,在布局的时候还遇到了一个问题,就是涉及到控件的嵌套布局方式,当对多个控件使用组合布局时一定不要先设置父窗体指针,要在最后一个布局上设置才会生效。
`QHBoxLayout *hbLayoutCtrl = new QHBoxLayout();
hbLayoutCtrl->addWidget(labelTime);
hbLayoutCtrl->addStretch();
hbLayoutCtrl->addStretch();
hbLayoutCtrl->addStretch();
hbLayoutCtrl->addWidget(btn_stop);
hbLayoutCtrl->addWidget(btn_previous);
hbLayoutCtrl->addWidget(btn_play);
hbLayoutCtrl->addWidget(btn_next);
hbLayoutCtrl->addWidget(btn_volume);
hbLayoutCtrl->addWidget(audio_slider);
hbLayoutCtrl->addStretch();
hbLayoutCtrl->addStretch();
hbLayoutCtrl->addWidget(btn_fullScreen);
hbLayoutCtrl->addWidget(btn_hidePlayList);
//进度条的设置 涉及到多个布局混合的方式,一定要在最终的布局里面再设置父窗口指针
slider->setOrientation(Qt::Horizontal);
slider->setVisible(false);
audio_slider->setOrientation(Qt::Horizontal);
QHBoxLayout *hbSliderLayout = new QHBoxLayout();
hbSliderLayout->addWidget(slider);

QVBoxLayout *vbLayout = new QVBoxLayout(widget_control);
vbLayout->addLayout(hbSliderLayout);
vbLayout->addLayout(hbLayoutCtrl);
vbLayout->setMargin(0);`
这个地方是两个水平布局然后两个布局作为子布局在新的竖直布局里实现,一开始我指定了每个布局的父窗口指针的位置,后来发现设置之后根本不生效,后面查了好多资料才发现在多个布局中一定只能在最后的一个布局里面设置父窗口指针,否则就不生效。
在搞这个东西的时候我还发现对qt外观格式的设置,即qss文本设置qt上各种元素的样式,这个后续再展开说。

你可能感兴趣的:(qt,c++,qt)