1背景
上面这几篇,是使用qt的gl渲染的。ffmpeg播放器16上里面,新建了三个文件,这一篇继续后续的。
源码存放位置 github.com/xcyxiner/xp…
2步骤
2.1 HVideoWnd 补充成员函数
双击 hvideownd.h 的,添加如下代码
#include "hframe.h"
public:
virtual void setGeometry(const QRect& rc) = 0;
virtual void update() = 0;
public:
HFrame last_frame;
};
2.2 GLWnd 继承 HVideoWnd 的方法
双击glwnd.h,选中HVideoWnd,重构,插入虚方法
效果如下
再添加定义,选中,右键
最终效果如下
补充完善代码
void GLWnd::setGeometry(const QRect &rc)
{
HGLWidget::setGeometry(rc);
}
void GLWnd::update()
{
HGLWidget::update();
}
2.3 hvideowidget.h 中声明HVideoWnd
双击 hvideowidget.h,添加如下代码
private:
HVideoWnd *videownd;
然后在cpp中初始化
#include "glwnd.h"
HVideoWidget::HVideoWidget(QWidget *parent)
: QFrame(parent)
, ui(new Ui::HVideoWidget)
{
ui->setupUi(this);
this->videownd=new GLWnd(this);
}
运行效果如下
2.4 setGeometry
上面2.1里两个方法,其中一个是setGeometry,这个是调整界面大小的。之前播放器12 一直是start里执行线程的。 线程没执行出问题,会触发成功事件。 在hvideowidget.h中添加如下,然后右键,重构,添加定义
public slots:
void onOpenSucceed();
在hvideowidget.cpp中的start中,添加如下代码
void HVideoWidget::start()
{
this->pImpl_player=new HFFPlayer();
this->pImpl_player->set_media(this->media);
int ret= this->pImpl_player->start();
if(ret!=0){
}else{
//
onOpenSucceed();
}
}
void HVideoWidget::onOpenSucceed()
{
}
然后追加onOpenSucceed的实现
这里avdef.h先添加一个枚举类型
typedef enum{
ASPECT_FULL,//100%
ASPECT_PERCENT, // 50%
ASPECT_ORIGINAL_RATIO, // w:h
ASPECT_ORIGINAL_SIZE, // wxh
ASPECT_CUSTOM_RATIO, // 4:3 16:9 ...
ASPECT_CUSTOM_SIZE, // 1280x720 640*480 ..
}aspect_ratio_e;
typedef struct aspect_ratio_s {
aspect_ratio_e type;
int w, h;
} aspect_ratio_t;
然后在hvideowidget.h中添加声明
public:
aspect_ratio_t aspect_ratio;
在构造器函数中进行赋值
HVideoWidget::HVideoWidget(QWidget *parent)
: QFrame(parent)
, ui(new Ui::HVideoWidget)
{
ui->setupUi(this);
this->videownd=new GLWnd(this);
this->aspect_ratio.type=ASPECT_FULL;
}
在hvideowidget.h中添加setAspectRatio
public slots:
void open(HMedia& media);
void start();
void onOpenSucceed();
void setAspectRatio(aspect_ratio_t aspect_ratio);
选中setAspectRatio,右键,重构,添加定义
然后在onOpenSucceed中调用
void HVideoWidget::onOpenSucceed()
{
setAspectRatio(aspect_ratio);
}
接下来,要去设置hvideoplayer的宽度和高度 双击 HVideoPlayer.h,添加如下代码
public:
HMedia media;
int32_t width;
int32_t height;
int64_t duration;
int64_t start_time;
int eof;
int error;
并在构造器中初始化
HVideoPlayer::HVideoPlayer() {
width = 0;
height = 0;
duration = 0;
start_time = 0;
eof = 0;
error = 0;
}
再返回hvideowidget.cpp中添加setAspectRatio的后续代码如下所示
void HVideoWidget::setAspectRatio(aspect_ratio_t aspect_ratio)
{
this->aspect_ratio = aspect_ratio;
int border = 1;
int scr_w = width() - border * 2;
int scr_h = height() - border * 2;
if (scr_w <= 0 || scr_h <= 0) return;
int pic_w = 0;
int pic_h = 0;
if (pImpl_player) {
pic_w = pImpl_player->width;
pic_h = pImpl_player->height;
}
if (pic_w == 0) pic_w = scr_w;
if (pic_h == 0) pic_h = scr_h;
// calc videownd rect
int dst_w, dst_h;
switch (aspect_ratio.type) {
case ASPECT_FULL:
dst_w = scr_w;
dst_h = scr_h;
break;
case ASPECT_PERCENT:
case ASPECT_ORIGINAL_SIZE:
case ASPECT_CUSTOM_SIZE:
case ASPECT_ORIGINAL_RATIO:
case ASPECT_CUSTOM_RATIO:
break;
}
dst_w = std::min(dst_w, scr_w);
dst_h = std::min(dst_h, scr_h);
// align 4
dst_w = dst_w >> 2 << 2;
dst_h = dst_h >> 2 << 2;
int x = border + (scr_w - dst_w) / 2;
int y = border + (scr_h - dst_h) / 2;
videownd->setGeometry(QRect(x, y, dst_w, dst_h));
}
运行后的效果
因为这里的HVideoWidget实例化的时候就是这么大,所以填充满也就上面的效果
2.5 timer
在hvideowidget.h头文件中添加声明
private:
HMedia media;
HVideoPlayer* pImpl_player;
QTimer* timer;
};
然后再添加一个onTimerUpdate,关联timer的timeout信号
public slots:
void open(HMedia& media);
void start();
void onOpenSucceed();
void setAspectRatio(aspect_ratio_t aspect_ratio);
void onTimerUpdate();
选中onTimerUpdate,右键,重构,添加定义
再在构造函数中初始化timer并触发事件
#include <QTimer>
HVideoWidget::HVideoWidget(QWidget *parent)
: QFrame(parent)
, ui(new Ui::HVideoWidget)
{
ui->setupUi(this);
this->videownd=new GLWnd(this);
this->aspect_ratio.type=ASPECT_FULL;
this->timer=new QTimer(this);
timer->setTimerType(Qt::PreciseTimer);
connect(timer,SIGNAL(timeout()),this,SLOT(onTimerUpdate()));
}
然后追加如下代码
void HVideoWidget::onTimerUpdate()
{
if(this->pImpl_player==NULL)return;
//提取一帧
// update video frame
videownd->update();
}
2.6 HVideoPlayer的视频帧
前面2.5这里要读取一帧视频,前面的代码只涉及了start开启线程后的doPrepare,还有后续的run没处理,这里继续补上。
2.6.1 HRingBuf
HBuf中补充一个构造函数
HBuf(size_t cap){
resize(cap);
}
新增HRingBuf,继承HBuf
结果如下所示
添加如下代码
class HRingBuf : public HBuf
{
public:
HRingBuf();
HRingBuf(size_t cap);
virtual ~HRingBuf(){
}
char* alloc(size_t len);
void free(size_t len);
void clear();
size_t size() const;
private:
size_t _head;
size_t _tail;
size_t _size;
};
修改构造函数,使用基类初始化
HRingBuf::HRingBuf():HBuf() {
}
HRingBuf::HRingBuf(size_t cap):HBuf(cap)
{
}
选中_size,右键,生成get方法 选中alloc,free,clear,右键,添加定义
最终的cpp代码如下
#include "hringbuf.h"
HRingBuf::HRingBuf():HBuf() {
}
HRingBuf::HRingBuf(size_t cap):HBuf(cap)
{
}
char *HRingBuf::alloc(size_t len)
{
}
void HRingBuf::free(size_t len)
{
}
void HRingBuf::clear()
{
}
size_t HRingBuf::size() const
{
return _size;
}
补充代码实现
#include "hringbuf.h"
HRingBuf::HRingBuf():HBuf() {
_head=_tail=_size=0;
}
HRingBuf::HRingBuf(size_t cap):HBuf(cap)
{
_head=_tail=_size=0;
}
char *HRingBuf::alloc(size_t len)
{
char* ret=NULL;
if(_head<_tail || _size==0){
// [_tail, this->len) && [0, _head)
if(this->len -_tail>=len){
ret = base + _tail;
_tail += len;
if (_tail == this->len) _tail = 0;
}
else if(_head>=len){
ret=base;
_tail=len;
}
}else{
// [_tail, _head)
if(_head-_tail>=len){
ret=base+_tail;
_tail+=len;
}
}
_size+=ret?len:0;
return ret;
}
void HRingBuf::free(size_t len)
{
_size-=len;
if(len <= this->len -_head){
_head+=len;
if(_head==this->len)_head=0;
}else{
_head=len;
}
}
void HRingBuf::clear()
{
_head=_tail=_size=0;
}
size_t HRingBuf::size() const
{
return _size;
}
后面再分析代码的