播放器实战17 xvideowidget
int main(int argc, char *argv[])
{testtread tt;tt.init();QApplication a(argc, argv);Xplay2 w;w.show();w.ui.openGLWidget->Init(tt.demux.width, tt.demux.height);tt.video = w.ui.openGLWidget;tt.start();return a.exec();
}
在实战14中,是直接读取的yuv文件然后用OpenGL进行绘制:
fp = fopen(“out240x128.yuv”, “rb”);
这里我们是利用解码获得的frame来进行绘制
打开.ui文件,添加OpenGL控件:
提升为类xvideowidget:
在ui_Xplay2文件中可以看到如下代码:
class Ui_Xplay2Class
{public:xvideowidget *openGLWidget;void setupUi(QWidget *Xplay2Class){if (Xplay2Class->objectName().isEmpty())Xplay2Class->setObjectName(QString::fromUtf8("Xplay2Class"));Xplay2Class->resize(1072, 790);openGLWidget = new xvideowidget(Xplay2Class);openGLWidget->setObjectName(QString::fromUtf8("openGLWidget"));openGLWidget->setGeometry(QRect(149, 129, 800, 600));retranslateUi(Xplay2Class);QMetaObject::connectSlotsByName(Xplay2Class);} // setupUivoid retranslateUi(QWidget *Xplay2Class){Xplay2Class->setWindowTitle(QCoreApplication::translate("Xplay2Class", "Xplay2", nullptr));} // retranslateUi};
可以看到xvideowidget *openGLWidget;在这个界面的大类里放了个指向xvideowidget的指针OpenGLwidget,并用该指针调用resize等方法
在代码中添加xvideowidget.h:
#include <QOpenGLWidget>
#include <QOpenGLFunctions>
#include <QGLShaderProgram>
#include <mutex>
struct AVFrame;
class xvideowidget : public QOpenGLWidget, protected QOpenGLFunctions
{Q_OBJECTpublic:void Init(int width, int height);//不管成功与否都释放frame空间virtual void Repaint(AVFrame* frame);xvideowidget(QWidget* parent);~xvideowidget();
protected://刷新显示void paintGL();//初始化glvoid initializeGL();// 窗口尺寸变化void resizeGL(int width, int height);
private:std::mutex mux;//shader程序QGLShaderProgram program;//shader中yuv变量地址GLuint unis[3] = { 0 };//openg的 texture地址GLuint texs[3] = { 0 };//材质内存空间unsigned char* datas[3] = { 0 };int width = 0;int height = 0;
};
xvideowidget.cpp与实战14中不同的是实战14中将宽与高是提前定死的,而这里根据传进来的数据来设定宽高,并提供了一个新接口,目的是设置宽高,分配材质内存空间,设置放大缩小方式:
void xvideowidget::Init(int width, int height)
{mux.lock();this->width = width;this->height = height;delete datas[0];delete datas[1];delete datas[2];///分配材质内存空间datas[0] = new unsigned char[width * height]; //Ydatas[1] = new unsigned char[width * height / 4]; //Udatas[2] = new unsigned char[width * height / 4]; //Vif (texs[0]){glDeleteTextures(3, texs);}//创建材质glGenTextures(3, texs);//YglBindTexture(GL_TEXTURE_2D, texs[0]);//放大过滤,线性插值 GL_NEAREST(效率高,但马赛克严重)glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);//创建材质显卡空间glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, width, height, 0, GL_RED, GL_UNSIGNED_BYTE, 0);//UglBindTexture(GL_TEXTURE_2D, texs[1]);//放大过滤,线性插值glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);//创建材质显卡空间glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, width / 2, height / 2, 0, GL_RED, GL_UNSIGNED_BYTE, 0);//VglBindTexture(GL_TEXTURE_2D, texs[2]);//放大过滤,线性插值glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);//创建材质显卡空间glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, width / 2, height / 2, 0, GL_RED, GL_UNSIGNED_BYTE, 0);mux.unlock();
}
因为创建材质也用到高和宽,所以也放到这个接口中
创建材质显卡空间要用到tex,删除也会删tex,为了防止用到一半被删掉导致程序宕掉,加个锁,其他函数用到data与tex的也要加锁,对于repaint()这种频繁出现的,要注意加锁的代码量,会影响性能,对于init这种只出现一次的无所谓
读与绘制会阻塞,因此使用QThread:
class testtread :public QThread
{public:void init(){const char* path = "E:\\ffmpeg\\test.mp4";const char* url = "rtsp://27.22.78.122:8554/1";cout << "demux.Open = " << demux.Open(path) << endl;cout << "vdecode.open()" << vdecode.open(demux.CopyVPara()) << endl;cout << "adecode.open()" << adecode.open(demux.CopyAPara()) << endl;}void run(){for (;;){AVPacket* pkt = demux.readfz();if (demux.isvideo(pkt) == true){vdecode.send(pkt);AVFrame* frame = vdecode.receive();//cout << "视频解码" <<frame<< endl;video->Repaint(frame);Sleep(40);}else{//adecode.send(pkt);//AVFrame* frame = adecode.receive();//cout << "音频解码" <<frame<< endl;}if (!pkt)break;}}xdemux demux;xvideowidget* video;
protected:xdecode vdecode;xdecode adecode;};
因为主线程退出后video被删了,然而该线程还在,所以会出点小问题,后面再解决
main函数:
int main(int argc, char *argv[])
{testtread tt;tt.init();QApplication a(argc, argv);Xplay2 w;w.show();w.ui.openGLWidget->Init(tt.demux.width, tt.demux.height);tt.video = w.ui.openGLWidget;tt.start();return a.exec();
}
1.实例化一个线程,
实例化线程的同时会实例化demux,vdecode,adecode,xvideowidget*,并将解封装后的视频信息传给vdecode,音频信息传给adecode
2.打开一个QT的窗口
3.将解封装得到的宽高信息传给ui窗口里添加的控件的初始化函数,让QT窗口上可以显示一个与我们的媒体文件同样宽高的视频窗口,只不过不能显示画面
tt的demux与video,w的ui都为类外访问,所以要把这些成员开放出去设为public
4.让线程中的指向xvideowidget的指针指向我们添加的控件,调用start即调用线程的run,在run里将解码得到的packet发给openg进行绘制并显示在控件上
void xvideowidget::Repaint(AVFrame* frame)
{if (!frame){qDebug() << "show failed1" ;return;}mux.lock();//容错,保证尺寸正确if (!datas[0] || width * height == 0 || frame->width != this->width || frame->height != this->height){av_frame_free(&frame);mux.unlock();qDebug() << "show failed2";return;}memcpy(datas[0], frame->data[0], width * height);memcpy(datas[1], frame->data[1], width * height / 4);memcpy(datas[2], frame->data[2], width * height / 4);//行对齐问题mux.unlock();//刷新显示update();qDebug()<< "repaint" ;
}
运行情况如下:
播放器实战17 xvideowidget相关推荐
- 播放器实战28 总结
至此,播放器的基本功能已经实现,进行一个总结: 一,仅进行播放时的函数调用流程 只做一个大致的梳理且不涉及seek等操作): 01.QT中的整个控件为QWidget类,Xplay2类为其继承,在mai ...
- 基于 Vue 的直播播放器实战
原文地址:点击进入 前言 时下直播的盛行让很多人对直播技术产生浓厚的兴趣,orange 本人也不例外,本文借着实战的目的完成一个 demo,并没有深入的讲解直播技术的实现原理以及推流和拉流的实现,为什 ...
- vue实现音乐播放器实战笔记
一.项目说明 该播放器的是基于学习vue的实战练习,不用于其他途径.应用中的全部数据来自于 QQ音乐 移动端(https://m.y.qq.com/),利用 jsonp 以及 axios 代理后端请求 ...
- 播放器实战19 Xaudio打开音频
1.xaudio.h #pragma once class xaudioplay {public:static xaudioplay* get();xaudioplay();//一定得是虚析构函数,d ...
- vue 判断同一数组内的值是否一直_前端代码+后端API,值得一学的Vue高仿音乐播放器实战项目
项目名称:vue-fds_music 项目作者:符道胜 开源许可协议:Apache-2.0 项目地址:https://gitee.com/fudaosheng/vue-fds_music 项目简介 V ...
- 妙味课堂H5音乐播放器实战视频课程 ajax实战教程
课程介绍: 本次课程涉及的知识点包括移动端H5.CSS3.JS.滑屏.HTTP协议.AJAX.跨域.前后端交互.PHP.mySql.jQuery--配合这些知识点,讲师写了一个H5播放器demo,用来 ...
- 后端实体类接收数组_前端代码+后端API,值得一学的Vue高仿音乐播放器实战项目...
项目名称:vue-fds_music 项目作者:符道胜 开源许可协议:Apache-2.0 项目地址:https://gitee.com/fudaosheng/vue-fds_music 项目简介 V ...
- 前端代码+后端API,值得一学的Vue高仿音乐播放器实战项目
项目名称:vue-fds_music 项目作者:符道胜 开源许可协议:Apache-2.0 项目地址:https://gitee.com/fudaosheng/vue-fds_music 项目简介 V ...
- 播放器实战22 解决花屏与卡顿问题
1.内存对齐 1.1什么是内存对齐 在C语言中,结构是一种复合数据类型,其构成元素既可以是基本数据类型(如int.long.float等)的变量,也可以是一些复合数据类型(如数组.结构.联合等)的数据 ...
最新文章
- Bug tracker .net 部署经验(完善中)
- 干货丨吴恩达深度学习课程的思维导图总结
- 举例讲清楚模型树和回归树的区别
- C#2.0新特性探究之模拟泛型和内置算法
- vue 打包后本地先自己启动服务 anywhere 非常好用
- 英雄由此诞生------直击微软2008发布大会
- OpenTSDB的读写API
- 网银安全控件远程代码执行漏洞分析
- 快速学会普源示波器的调节和使用
- world2016论文脚注问题
- uni-app开发模式中的选择图片(uni.chooseImage)、上传图片(uni.uploadFile)、图片预览(uni.previewImage)
- 基于Python热点新闻关键词数据分析系统
- 计算机自动计算的条件,电脑表格怎样自动计算
- Webpack--模块热替换(HMR)
- 数字经济的发展需要包括区块链在内的八大技术的支撑360云储
- 如何写英文科技论文 papers
- 中英文互译之Excel表格
- 常数和基本初等函数的导数
- 用C语言实现一个函数,判断一个数是不是素数
- 【windows】实战部署一(安装)SVNserver服务端+SVNclient客户端