1背景
上面这几篇,是使用qt的gl渲染的。上一次12最终到了解码,这一篇继续后续的。
源码存放位置 github.com/xcyxiner/xp…
2步骤
2.1 图像缩放以及像素格式转换
从8中可以看到解码后进行了 图像缩放以及像素格式转换.
继续在hffplayer.cpp中添加
先添加dst_pix_fmt的声明
AVPixelFormat src_pix_fmt;
AVPixelFormat dst_pix_fmt;
再在cpp中 HFFPlayer::open 添加如下代码
// 原始视频宽高以及像素格式
int sw,sh,dw,dh;
sw=codec_ctx->width;
sh=codec_ctx->height;
src_pix_fmt=codec_ctx->pix_fmt;
if(sw<=0|| sh <=0 || src_pix_fmt==AV_PIX_FMT_NONE){
if(fmt_ctx){
avformat_close_input(&fmt_ctx);
avformat_free_context(fmt_ctx);
fmt_ctx=NULL;
}
if(codec_ctx){
avcodec_free_context(&codec_ctx);
codec_ctx=NULL;
}
ret=-45;
return ret;
}
//目标视频宽高以及像素格式
dw=sw&(~3);
dh=sh&(~3);
dst_pix_fmt=AV_PIX_FMT_YUV420P;
追加断点并测试
再在头文件中添加声明
SwsContext* sws_ctx;
再在cpp中追加如下代码
//图像缩放以及像素格式转换
sws_ctx=sws_getContext(sw,sh,src_pix_fmt,dw,dh,dst_pix_fmt,SWS_BICUBIC,NULL,NULL,NULL);
if(sws_ctx==NULL){
if(fmt_ctx){
avformat_close_input(&fmt_ctx);
avformat_free_context(fmt_ctx);
fmt_ctx=NULL;
}
if(codec_ctx){
avcodec_free_context(&codec_ctx);
codec_ctx=NULL;
}
ret=-50;
return ret;
}
追加一行输出,打断点
#include <iostream>
std::cout<<ret<<std::endl;
2.2 frame 视频帧
先添加声明
AVPacket* packet;
AVFrame* frame;
然后赋值
packet=av_packet_alloc();
frame=av_frame_alloc();
新建一个HFrame文件(c++文件)
因为这里还使用了HBuf,所以需要再添加一个新文件
添加成员变量
#include <cstdlib>
class HBuf
{
public:
char* base;
size_t len;
HBuf() {
base=NULL;
len=0;
cleanup_ = false;
}
HBuf(void* data, size_t len) {
this->base=(char*)data;
this->len=len;
cleanup_ = false;
}
~HBuf(){
free(base);
base=NULL;
}
char *getBase() const;
size_t getLen() const;
void resize(size_t cap);
private:
bool cleanup_;
};
并在hbuf.cpp中添加如下代码
#include "hbuf.h"
#include <cstring>
size_t HBuf::getLen() const
{
return len;
}
void HBuf::resize(size_t cap)
{
if(cap==len)return;
if(base==NULL){
base=(char*)malloc(cap);
memset(base,0,cap);
}else{
base=(char*)realloc(base,cap);
if(cap>len){
memset(base+len,0,cap-len);
}
}
len=cap;
cleanup_=true;
}
char *HBuf::getBase() const
{
return base;
}
然后再补全上面的成员变量并初始化,如下所示
#include "hbuf.h"
class HFrame
{
public:
HBuf buf;
int w;
int h;
int bpp;
int type;
HFrame(){
w=h=bpp=type=0;
}
};
然后再在hffplayer.h添加申明
#include "hframe.h"
uint8_t* data[4];
int linesize[4];
HFrame hframe;
这里用到PIX_FMT_IYUV,先在avdef.h中添加如下枚举
typedef enum{
PIX_FMT_NONE=0,
PIX_FMT_IYUV//YYYY YYYY UUVV
} pix_fmt_e;
继续cpp中的代码
//视频帧存储
packet=av_packet_alloc();
frame=av_frame_alloc();
hframe.w=dw;
hframe.h=dh;
hframe.buf.resize(dw*dh*4);
if(dst_pix_fmt==AV_PIX_FMT_YUV420P){
hframe.type=PIX_FMT_IYUV;
hframe.bpp=12;
int y_size=dw*dh;
hframe.buf.len=y_size*3/2;
data[0]=(uint8_t*)hframe.buf.base;
data[1]=data[0]+y_size;
data[2]=data[1]+y_size/4;
linesize[0]=dw;
linesize[1]=linesize[2]=dw/2;
}
return ret;
上面的追加调试的结果
2.3 gl渲染--HVideoWnd
前面两节属于上一次没写完的代码,这一次补充完整。 之前的start方法执行线程后,上面的只完成了准备工作,后续的run,之后再写。
在播放器11里,提到了HVideoWnd,这里添加一个c++文件,继承QWidget
播放器11里提到了工厂方法,这里就跳过,直接使用gl的对象渲染 GLWnd ,后面再添加sdl的渲染
2.4 GLWnd 基类 HGLWidget
从播放器13里知道 GLWnd : public HVideoWnd, HGLWidget ,继承了两个父类。第一个,前面已经添加了,这里再添加后面一个HGLWidget
还是c++文件,名称为HGLWidget,继承QWidget
hglwidget.h 修改基类为QOpenGLWidget
#include <QWidget>
#include <QtOpenGLWidgets/qopenglwidget.h>
class HGLWidget : public QOpenGLWidget
{
Q_OBJECT
public:
explicit HGLWidget(QWidget *parent = nullptr);
signals:
};
同样修改hglwidget.cpp中的构造函数的基类
HGLWidget::HGLWidget(QWidget *parent)
: QOpenGLWidget{parent}
{}
切换到hglwidget.h,选中QOpenGLWidget,右键,重构,插入基类的方法
只勾选QOpenGLWidget中的initializeGL,resizeGL,paintGL方法,以及勾选下面的添加virtual
然后选中,右键,重构,添加定义在cpp中
最终效果如下所示
这时编译会报错,需要在pro文件中关联 openglwidgets,如下图所示
重新构建,就没有报错了
2.5 GLWnd
添加c++文件,名称为GLWnd,继承QWidget
修改基类为 HVideoWnd, HGLWidget
#include "hglwidget.h"
#include "hvideownd.h"
class GLWnd : public HVideoWnd, HGLWidget
修改构造器方法
#include "glwnd.h"
GLWnd::GLWnd(QWidget *parent)
: HVideoWnd(parent),HGLWidget(parent)
{}