本部分总结了一下界面绘制和OpenGL绘制视频,由于使用的是Qt的openGL,功能上没有那么复杂,实现起来也比较简单,毕竟人家已经给封好的,完整的代码中使用OpenGL绘制视频,对数据的顶点shader、片元shader着色,对yuv材质的绑定,分配材质内存空间、创建材质显卡空间、纹理以及显卡绘制每帧视频时如何对齐等等一些内容,这部分内容是OpenGL中的,较为复杂,待继续学习后有一定收获再来总结,现在我们继续看这里。
一、基于QT的播放器界面绘制
在做opengl绘制视频前,我们先需要设计一个界面,打开vs2013中该项目中的ui,进入Qt设计界面,设置好界面的属性后,在我们绘制视频时,可以选择3D引擎UX,或者OpenGL,但在这里我们用Qt自带的OpenGL。选择Qt的控件Open GL Widget,在界面中绘制一片区域,设置大小以及属性,之后加入两个按钮控件为打开文件和播放视频,加入相对应的图标,如何加入,网上有很多方法,这里就不啰嗦了,主要得知道这里两个按钮的变量名为openButton和playButton,后面需要用到的。
二、通过QT显示转码后的RGB数据
现在我们需要将FFMpeg解码后的视频播放出来,如何播放?在上面中我们创建了窗口openGLWidget,这里我们重载这个类(是对象openGLWidget的类QOpenGLWidget,重载的是这个类),然后使用我们自己的方法来控制这个窗口。这里我将QOpenGLWidget类提升为VideoWidget类。
然后我们在VS2013中用类向导创建该类进行实现(要继承自QOpenGLWidget)。首先在VideoWidget.h中申明定时器和窗口的重新绘制的函数。
#pragma once
#include <QtWidgets/qwidget.h>
#include
class VideoWidget:public QOpenGLWidget
{
public:
VideoWidget(QWidget *parent = NULL);
void paintEvent(QPaintEvent *event);//窗口的重新绘制
void timerEvent(QTimerEvent *event);//定时器
virtual ~VideoWidget();
};
对于paintEvent的定义,我们知道绘制时需要FFMpeg解码出来的视频帧,而对于解封装、解码我们都在XFFMpeg类中完成,这里我们需要使用它。而在VideoWidget的构造函数里需要打开视频,同时设置定制器来显示播放,目前这是测试阶段,我们就先考虑单线程,播放时有些卡顿,当然后面我们会使用多线程解决这一问题,现在我们看下paintEvent的定义。
void VideoWidget::paintEvent(QPaintEvent *e)
{//绘制
static QImage *image = NULL;
if (image == NULL)
{
uchar *buf = new uchar[width()*height() * 4];//存放解码后的视频空间
image = new QImage(buf, width(), height(), QImage::Format_ARGB32);
}
AVPacket pkt = XFFmpeg::Get()->Read();//读取视频帧
if (pkt.stream_index != XFFmpeg::Get()->videoStream)
{//不为视频帧,释放pkt的空间
av_packet_unref(&pkt);
return;
}
if (pkt.size == 0) return;
AVFrame *yuv = XFFmpeg::Get()->Decode(&pkt);//解码读取到的视频帧
av_packet_unref(&pkt);//解码成后也需要释放空间
if (yuv == NULL) return;
//将解码后的视频帧转化为RGB
XFFmpeg::Get()->ToRGB(yuv, (char *)image->bits(),width(),height());
QPainter painter;//hua
painter.begin(this);
painter.drawImage(QPoint(0, 0), *image);//绘制FFMpeg解码后的视频
painter.end();//
}
XFFMpeg的读取、解码、转换为RGB在之前我们也都说明过。这里要说下的可能就是
if (image == NULL)
{
uchar *buf = new uchar[width()*height() * 4];//存放解码后的视频空间
image = new QImage(buf, width(), height(), QImage::Format_ARGB32);
}
这里的buf用来后面对于解码后的视频帧绘制时用到的,开辟的空间后*4是RGB有三个色彩同时这里还有一个通道数,共占用了四个字节,后面的image 的格式 QImage::Format_ARGB32也选择了32位的设置,都对应了在XFFMPeg中解码以及转化RGB格式时所设置的一些参数。
后面就是它的构造函数以及定时器函数,里面也都比较简单。
VideoWidget::VideoWidget(QWidget *parent) :QOpenGLWidget(parent)
{
XFFmpeg::Get()->Open(“1080.mp4”);//打开视频
startTimer(10);//设置定时器
}
void VideoWidget::timerEvent(QTimerEvent *event)
{
this->update();//定时器更新
}
对于这部分内容大概就这么多,绘制基本如此,下一篇中我们进行视频播放进度控制,处理之前的卡顿现象。