QT视频播放器的一些笔记

1:首先分配一个QImage的缓冲,然后进行绘制。具体过程如下:

void XVideoWidget::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);
}
XFFmpeg::Get()->ToRGB((char*)image->bits(), width(), height());   //转换成RGB
QPainter painter;
painter.begin(this);
painter.drawImage(QPoint(0, 0), *image);  //绘图方法
painter.end();
}

2:多线程管理读视频桢,解码。
class XVideoWidget : public QOpenGLWidget
{
public:
void paintEvent(QPaintEvent *e);
void timerEvent(QTimerEvent *e);
XVideoWidget(QWidget *p = NULL);
virtual ~XVideoWidget();
};
void XVideoThread::run()
{
while (!isexit)
{
AVPacket pkt = XFFmpeg::Get()->Read();
if (pkt.size <= 0)
{
msleep(10);
continue;
}
if (pkt.stream_index != XFFmpeg::Get()->videoStream)
{
av_packet_unref(&pkt);
continue;
}
XFFmpeg::Get()->Decode(&pkt);
av_packet_unref(&pkt);
if (XFFmpeg::Get()->fps > 0) //fps是帧率
{
//休眠一帧的时间,一帧有多少ms。fps每一秒多少桢
msleep(1000/(XFFmpeg::Get()->fps)); //控制解码时间
}
}
return;
}

3:视频总长度显示
需要用sprintf来拼接缓冲区。
int min = (XFFmpeg::Get()->pts/1000)/60;
int sec = (XFFmpeg::Get()->pts / 1000) % 60;
char buf[1024] = { 0 };
sprintf(buf, "%03d:%02d", min, sec);
ui.playtime->setText(buf);
当前的显示时间要通过yuv的pts来获取,因为yuv是已经解码出来的视频桢,而pkt的pts是还没有解码出来,这是有一个延时的。
pts = (yuv->pts*r2d(ic->streams[pkt->stream_index]->time_base))*1000;

4:关于进度条的问题
当前播放的进度条滑块的位置,可以用当前的pts和总时间的比值,算出一个比率,然后去计算滑块的位置就可以了。具体方法如下:
if (XFFmpeg::Get()->totalMs > 0)
{
float rate = (float)XFFmpeg::Get()->pts / (float)XFFmpeg::Get()->totalMs;
if(!isPressSlider) //当拖动滑动条的时候,不会去更新滑动条的位置
ui.playslider->setValue(rate * 1000);
}

bool XFFmpeg::Seek(float pos)
{
mutex.lock();
if (!ic)
{
mutex.unlock();
return false;
}
int64_t stamp = 0;
stamp = pos*ic->streams[videoStream]->duration;
int re = av_seek_frame(ic, videoStream, stamp, AVSEEK_FLAG_BACKWARD | AVSEEK_FLAG_FRAME);//定位到滑动块地方的关键帧,用比率的方法
avcodec_flush_buffers(ic->streams[videoStream]->codec);//之前解码的缓冲清理
if (re > 0)
return true;
mutex.unlock();
return true;
}
下面两个函数是滑动块的槽函数
void XPlay::sliderPress()
{
isPressSlider = true;
return;
}
void XPlay::sliderRelease()
{
isPressSlider = false;
float pos = 0;
pos = (float)(ui.playslider->value())/(float)(ui.playslider->maximum()+1);
XFFmpeg::Get()->Seek(pos);
return;
}
5:窗口变化视频跟着变化
需要重写resize函数
void XPlay::resizeEvent(QResizeEvent *e)
{
ui.openGLWidget->resize(size());
return;
}
但是这样做以后,还要改变分配的内存空间
void XVideoWidget::paintEvent(QPaintEvent *e)
{
static QImage *image = NULL;
static int w = 0; //记录上一次的宽高
static int h = 0;
if (w != width() || h != height())  //这里说明变化了
{
if(image)//判断是不是第一次进来,如果第一次就不要进来
{
delete image->bits();//这里清空的目的是重新分配
delete image;
image = NULL;
}
}
if (image == NULL)
{
uchar *buf = new uchar[width()*height() * 4];
image = new QImage(buf, width(), height(), QImage::Format_ARGB32);
}
XFFmpeg::Get()->ToRGB((char*)image->bits(), width(), height());
QPainter painter;
painter.begin(this);
painter.drawImage(QPoint(0, 0), *image);
painter.end();
}
窗口的控件的变化位置的调整
ui.playButton->move(this->width() / 2 + 50, this->height() - 50);
ui.openButton->move(this->width() / 2 - 50, this->height() - 50);
ui.playslider->move(50, this->height() - 100);
ui.playslider->resize((this->width() - 50), ui.playslider->height());

6:点击滑动条重定义类问题
#include <QSlider>
#include <QMouseEvent>
class XSlider:public QSlider
{
Q_OBJECT
public:
XSlider(QWidget *p = NULL);
virtual ~XSlider();
void mousePressEvent(QMouseEvent *e);//重载鼠标点击事件
};

void XSlider::mousePressEvent(QMouseEvent *e)
{
int value = ((float)(e->pos().x()) / (float)(this->width()))*(this->maximum()+1); //计算出位置
this->setValue(value); //定义滑块的位置
QSlider::mousePressEvent(e);
return;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值