【QT项目:视频播放器——Qt opengl编程】通过shader完成显示yuv

通过Qt opengl不是为了3D绘制,而是为了将视频绘制起来
使用opengl 可以极大降低yuv转rgb的转换开销

使用Opengl需要考虑三大问题:

1、QOpenGLWidget(与界面如何交互)

1、为什么用QT的opengl
简单,界面可以自动叠加
void paintGL(); // 具体的绘制写在该函数里
void initializeGL(); // 材质初始化
void resizeGL(int width, int height); // 当窗口发生变化(缩放)
QOpenGLFunctions // 不需要手动添加库,直接继承该函数

2、Program GLSL 顶点和片元(如何与显卡交互)

GLSL是新的语言,通过GLSL与显卡进行交互,GLSL 跑在显卡上

QGLShaderProgram

Program用来编译和运行Shader代码,包括与shader的交互

编译和运行shader // shader两部分:顶点和片元
addShaderFromSourceCode // 加入shader代码
bindAttributeLocation // 设置传入的变量, 顶点和坐标
uniformLocation // 获取变量

GLSL着色器语言,专门针对opengl所设计,用于显卡运行

顶点着色器是针对每个顶点执行一次,用于确定顶点的位置;——三维
片元着色器是针对每个片元(可以理解为每个像素)执行一次,用于确定每个片元(像素)的颜色 ——平面
GLSL基本语法与C基本相同
它完美地支持向量和矩阵操作
GLSL提供了大量的内置函数来提供丰富的拓展功能
它是通过限定符操作来管理输入输出类型

顶点着色器(画两个三角形,形成一个矩形)

显卡运算能力:值以三角形为单位,所画的数量

顶点着色器被使用在传统的基于顶点的操作, 例如位移矩阵、计算光照方程、产生贴图坐标。
顶点着色器被应用指定, 应用于客户的顶点转化。
在这里插入图片描述

片元着色器

在片元着色器阶 段只有唯一的 varying 输出变量- 即内建变量: gl_FragColor(像素点颜色)
在这里插入图片描述

顶点信息

在这里插入图片描述
在这里插入图片描述

材质坐标信息(全部在第一象限)

在这里插入图片描述
在这里插入图片描述

传入顶点和材质坐标

glVertexAttribPointer(ATTRIB_VERTEX, 2, GL_FLOAT, 0, 0, vertexVertices); ATTRIB_VERTEX:顶点坐标 	2 :坐标数量 		GL_FLOAT:单位数0:法线		0:步宽	
glEnableVertexAttribArray(ATTRIB_VERTEX); 使生效
glVertexAttribPointer(ATTRIB_TEXTURE, 2, GL_FLOAT, 0, 0, textureVertices);材质坐标
glEnableVertexAttribArray(ATTRIB_TEXTURE);

三种GLSL变量类型

varying 顶点与片元共享 		// 算出顶点坐标
attribute 顶点使用,由bindAttributeLocation传入
uniform 程序传入 uniformLocation获取地址
glUniform1i(textureUniformY, 0); 设置

顶点shader

attribute vec4 vertexIn;   // 顶点输入
attribute vec2 textureIn;  // 材质输入void main(void) { gl_Position = vertexIn;textureOut = textureIn;  }

片元shader

varying vec2 textureOut;	//取出材质数值
uniform sampler2D tex_y;   // 三个材质
uniform sampler2D tex_u; 
uniform sampler2D tex_v; 
void main(void) {vec3 yuv; vec3 rgb;yuv.x = texture2D(tex_y, textureOut).r; yuv.y = texture2D(tex_u, textureOut).r - 0.5; yuv.z = texture2D(tex_v, textureOut).r - 0.5; rgb = mat3(1, 1, 1, 0, -0.39465, 2.03211, 1.13983, -0.58060, 0) * yuv; gl_FragColor = vec4(rgb, 1);}

3、材质Texture(如何写入ffmpeg数据)

前面通过OpenGLWidget管理整个窗口,最终显示涉及在某个材质上,最终要把ffmpeg数据写入,要考虑如何在材质中写入ffmpeg数据

创建材质

glGenTextures(1, t); 		// 创建材质个数,指针地址
glBindTexture(GL_TEXTURE_2D, *t);  // 绑定材质类型成2D图像
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);  // 放大、缩小(通过线性插值)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

glTexParameteri

glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER, GL_LINEAR); 
GL_TEXTURE_2D: 操作2D纹理.
GL_TEXTURE_MIN_FILTE: 缩小过滤
GL_TEXTURE_MAG_FILTER: 放大过滤
GL_LINEAR: 线性过滤, 使用距离当前渲染像素中心最近的4个纹素加权平均值.

ps:如果是一个点直接复制四倍的话,会产生马赛克的现象
加权计算的话就比较柔和

写入和绘制材质

glActiveTexture(GL_TEXTURE0); 		// 激活材质,通过编号
glBindTexture(GL_TEXTURE_2D, id_y);  // 绑定
glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, pixel_w, pixel_h, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, plane[0]); glUniform1i(textureUniformY, 0);    // 0层材质,材质可以多层
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);  // 从0开始绘制,4个
glViewport(0, 0, width, height);

glTexImage2D 材质创建函数

glTexImage2D(GL_TEXTURE_2D, 	// 在显存中创建纹理 
0, 				//细节 0默认 镜头拉远拉近
GL_RED, 		//gpu内部格式 
videoWidth, 	
videoHeight 
, GL_RED, 			//数据格式   数据格式和gpu内部格式 要一致GL_UNSIGNED_BYTE 	//像素的数据类型, data); glTexSubImage2D 	// 修改纹理

解决方案:VS2017中QT的ui文件打开闪退问题

https://blog.csdn.net/jiaolu295/article/details/115898600

项目代码 cpp

#include "XVideoWidget.h"
#include <QDebug>
#include <QTimer>
// 自动加双引号
#define GET_STR(x) #x
#define A_VER 3
#define T_VER 4FILE *fp = NULL;  // 文件接口// 顶点shader
const char *vString = GET_STR(attribute vec4 vertexIn;   // 顶点坐标attribute vec2 textureIn;  // 材质坐标varying vec2 textureOut;	// 顶点shader和片元shader共享的变量void main(void){gl_Position = vertexIn;textureOut = textureIn;}
);// 片元shader
const char *tString = GET_STR(varying vec2 textureOut;   // 共享变量uniform sampler2D tex_y;uniform sampler2D tex_u;uniform sampler2D tex_v;void main(void){vec3 yuv;vec3 rgb;yuv.x = texture2D(tex_y, textureOut).r;yuv.y = texture2D(tex_u, textureOut).r - 0.5;yuv.z = texture2D(tex_v, textureOut).r - 0.5;// 用矩阵转换yuvrgb = mat3(1.0, 1.0, 1.0,0, -0.39465, 2.03211,1.13983, -0.58060, 0.0)*yuv;// 获取输出颜色gl_FragColor = vec4(rgb, 1.0);}
);// 准备yuv数据
// ffmpeg -i v1080.mp4 -t 10  -s 240x128 -pix_fmt yuv420p  out240x128.yuv
//						-t 10: 时长10秒钟, 指定输出yuv420p
XVideoWidget::XVideoWidget(QWidget *parent):QOpenGLWidget(parent)
{}XVideoWidget::~XVideoWidget()
{}// 初始化opengl
void XVideoWidget::initializeGL()
{qDebug() << "initializeGL";// 初始化opengl函数(QOpenGLFunctions继承)函数initializeOpenGLFunctions();// 用program加载shader(顶点和片元)脚本// 片元(像素)shaderqDebug() << program.addShaderFromSourceCode(QGLShader::Fragment, tString);// 顶点shaderqDebug() << program.addShaderFromSourceCode(QGLShader::Vertex, vString);// #############################################以上shader已创建好,接下来要与shader进行交互// 设置顶点坐标的变量program.bindAttributeLocation("vertexIn", A_VER); // 将变量名称关联到一个索引中,索引可以用一个宏来实现// 设置材质坐标program.bindAttributeLocation("textureIn", T_VER);// 编译shader,打印qDebug() << "program.link() = " << program.link();// 绑定shader,打印qDebug() << "program.bind() = " << program.bind();   // 将opengl 和shader关联起来// 传递顶点和材质坐标// 顶点			顶点坐标是三维,但最后一位不传默认为0static const GLfloat ver[] = {-1.0f,-1.0f,1.0f,-1.0f,-1.0f,1.0f,1.0f,1.0f,};// 材质static const GLfloat tex[] = {0.0f, 1.0f,1.0f, 1.0f,0.0f, 0.0f,1.0f, 0.0f};// 将坐标写入opengl中//顶点				位置索引,一个顶点的元素个数(2),存放类型GL_FLOAT,是否有法线向量 0没有  0默认,ver顶点地址glVertexAttribPointer(A_VER, 2, GL_FLOAT, 0, 0, ver);glEnableVertexAttribArray(A_VER);  // 使顶点坐标生效// 材质glVertexAttribPointer(T_VER, 2, GL_FLOAT, 0, 0, tex);glEnableVertexAttribArray(T_VER);  // 使顶点坐标生效// 接下来对材质进行处理// 从shader获取材质unis[0] = program.uniformLocation("tex_y");unis[1] = program.uniformLocation("tex_u");unis[2] = program.uniformLocation("tex_v");// 创建材质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);// 分配材质内存空间 datas[0] = new unsigned char[width * height];		// Ydatas[1] = new unsigned char[width * height / 4];   // Udatas[2] = new unsigned char[width * height / 4];   // V fp = fopen("out240x128.yuv", "rb");if (!fp) // 读取失败{qDebug() << "out240x128.yuv file open failed!";}// 启动定时器QTimer *ti = new QTimer(this);connect(ti, SIGNAL(timeout()), this, SLOT(update()));   // 信号槽  timeout信号  this:当前窗体  更新ti->start(40);   // 25帧,40ms刷新一次}// 刷新显示,实现按钮的叠加
void XVideoWidget::paintGL()
{if (feof(fp))  // 假如到了结尾,移到开头的位置{fseek(fp, 0, SEEK_SET);// 循环播放}// 读取数据,存放在datasfread(datas[0], 1, width*height, fp);fread(datas[1], 1, width*height / 4, fp);fread(datas[2], 1, width*height / 4, fp);glActiveTexture(GL_TEXTURE0); // 激活第0层glBindTexture(GL_TEXTURE_2D, texs[0]); // 把0层 绑定到材质Y的位置				将显卡中创建的材质绑定到0层材质//修改材质内容(复制内存内容)glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RED, GL_UNSIGNED_BYTE, datas[0]);    // 再与内存空间datas进行关联// 与shader uni 变量关联起来glUniform1i(unis[0],0);glActiveTexture(GL_TEXTURE0 + 1 ); // 激活第1层glBindTexture(GL_TEXTURE_2D, texs[1]); // 把1层 绑定到材质U的位置				将显卡中创建的材质绑定到0层材质//修改材质内容(复制内存内容)glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width / 2, height / 2, GL_RED, GL_UNSIGNED_BYTE, datas[1]);    // 再与内存空间datas进行关联// 与shader uni 变量关联起来glUniform1i(unis[1], 1);glActiveTexture(GL_TEXTURE0 +  2); // 激活第2层glBindTexture(GL_TEXTURE_2D, texs[2]); // 把2层 绑定到材质V的位置				将显卡中创建的材质绑定到0层材质//修改材质内容(复制内存内容)glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width / 2, height / 2, GL_RED, GL_UNSIGNED_BYTE, datas[2]);    // 再与内存空间datas进行关联// 与shader uni 变量关联起来glUniform1i(unis[2], 2);// 开始画glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); // 从0 开始 画4个点qDebug() << "paintGL";}// 窗口尺寸变化
void XVideoWidget::resizeGL(int width, int height)
{qDebug() << "resizeGL"<< width<< height;
}

项目代码 头文件

#pragma once#include <QOpenGLWidget>
#include <QOpenGLFunctions>
#include <QGLShaderProgram>class XVideoWidget : public QOpenGLWidget, protected QOpenGLFunctions
{Q_OBJECTpublic:XVideoWidget(QWidget *parent);~XVideoWidget();
protected://重载三个函数// 刷新显示,实现按钮的叠加void paintGL();// 初始化glvoid initializeGL();// 窗口尺寸变化void resizeGL(int width, int height);private:// shader程序,通过program运行QGLShaderProgram program;// shader中yuv变量地址GLuint unis[3] = { 0 };// opengl的 texture 地址GLuint texs[3] = { 0 };// 材质的内存空间unsigned char *datas[3] = { 0 };int width = 240;int height = 128;};

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/27902.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【OpenGL】读取视频并渲染

&#x1f60f;★,:.☆(&#xffe3;▽&#xffe3;)/$:.★ &#x1f60f; 这篇文章主要介绍读取视频并渲染。 学其所用&#xff0c;用其所学。——梁启超 欢迎来到我的博客&#xff0c;一起学习&#xff0c;共同进步。 喜欢的朋友可以关注一下&#xff0c;下次更新不迷路&#…

unity rtsp 视频渲染(一)

unity unity 可以说是一个不错的工具&#xff0c;建立三维的场景非常方便&#xff0c;下面我们建立一个三维的场景&#xff0c;并且在三维的场景中和场景外分别建立系统去播放视频。所谓场景内就是在三维中播放视频&#xff0c;场景外就是在三维场景前表面的二维平面中播放视频…

Unity 视频渲染插件AVPro Movie Capture 简易教程

随着Unity 的 功能日益强大&#xff0c;Unity5的发布使的Unity的图形渲染能力达到了一个新的层次&#xff0c;全局光照的加入&#xff0c;各种新特性的加入&#xff0c;使视频的实时渲染不再是天方夜谈&#xff0c;Unity5发布时的演示视频《Adam》&#xff0c;画质惊人。Unity在…

最新 |《未来简史》作者赫拉利 演讲:AI不需要意识就可以毁灭人类文明 (全文+视频)...

作者&#xff1a;城主 | 编辑&#xff1a;腾讯新闻 郝博阳 编者导语&#xff1a; 最近两个月&#xff0c;自从《暂停AI声明书》发布后&#xff0c;我们看到了诸多AI行业内的专家大佬隔空辩论AI的潜在威胁和治理方法&#xff0c;场面一时无两&#xff0c;基本上把技术路径上AI可…

大模型基础知识 - 语言模型及其演进 公开版

本文为作者内部分享文档&#xff0c;由于不涉敏可以公开&#xff0c;分享本身是课程形式&#xff0c;有什么疑问欢迎在评论区留言。 开场白 人工智能发展到现在&#xff0c;在2个重要领域取得了重大突破&#xff0c;有望达到人类水平&#xff1a; 计算机视觉 &#xff08;Com…

使用ChatGPT帮助快速读书:《Rise of the Robots: Technology and the Threat of a Jobless Future》

有了ChatGPT的帮助&#xff0c;读书也快了&#xff0c;英文版的书也可以快速了解其主要内容&#xff0c;不知道这样囫囵吞枣的阅读有没有其它副作用&#xff0c;先读了几本再说。 《Rise of the Robots: Technology and the Threat of a Jobless Future》这本书我没找到中文版翻…

揭秘ChatGPT爆火的背后真相:学编程已经成为必选项!

这一阵最热门的话题&#xff0c;莫过于人工智能新选手—— ChatGPT&#xff0c;在推出后只用了两个月就积累了1亿用户&#xff01;它的出现在科技圈掀起了一阵“惊涛骇浪”&#xff0c;有人称ChatGPT的意义&#xff0c;堪比当年蒸汽机的出现&#xff0c;它足以爆发新一轮的“工…

【ChatGPT】AI 2.0 时代:拥抱先进的生产力

AI 2.0 时代:拥抱先进的生产力 目录 AI 2.0 时代:拥抱先进的生产力 康波周期是什么? 人类工业革命以来的近现代史 先进生产力的变成了信息与数据 AI科技改变世界

GraphPad Prism 科研绘图(一)

打开GraphPad软件&#xff0c;可以在左侧选择要绘制的图表类型&#xff0c;也可以在左下方直接打开现有的文件 graphpad的工作流程是&#xff0c;首先你需要输入你的数据&#xff0c;也就是你的实验原始数据&#xff0c;叫做Data Table 然后你可以对你的原始数据进行分析&…

科研绘图软件大全

作为材料&#xff0c;化学&#xff0c;环境&#xff0c;物理领域的科研工作者&#xff0c;你是否常为如何表达自己的思想而苦恼? 作为学术论文创造者&#xff0c;你是否为论文中图文单一而叹气? 在这里&#xff0c;推荐给你几款常用科研绘图软件&#xff0c;让你论文从此成为…

【知识图谱】知识图谱的本质是什么?

持续总结更新中 一句话总结知识图谱人工智能从感知到认知什么是知识&#xff1f;什么是先验知识&#xff1f;什么是知识表示&#xff1f;知识图谱的基本组成要素&#xff1f;什么是概念&#xff1f;什么是实体&#xff1f;什么是本体&#xff1f;谈谈本体构建什么是知识图谱的s…

【毕业季】毕业设计避坑指南

文章目录 前言&#x1f34a;缘由毕业季&#xff0c;毕业设计分手季 &#x1f3af;主要目标实现4大重点 &#x1f348;猜你想问如何与狗哥联系进行探讨1.关注公众号【JavaDog程序狗】2.踩踩狗哥博客 &#x1f36f;猜你喜欢文章推荐 正文1.毕业设计如何选题2.毕业设计如何去写3.网…

文心一言“插刀”百度?

在ChatGPT出世半年&#xff0c;爆火将近2月后&#xff0c;中国版AI大模型终于崭露头角。 3月16日&#xff0c;百度于北京总部召开新闻发布会&#xff0c;主题围绕基于文心大模型技术生成式对话产品——文心一言&#xff0c;这也预示着中国首个类ChatGPT产品面世。在其正式推出前…

MSRA王晋东:大模型时代,普通人的科研何去何从

王晋东 投稿量子位 | 公众号 QbitAI 最近&#xff0c;电子工业出版社送了我一本《一本书读懂AIGC&#xff1a;ChatGPT、AI绘画、智能文明与生产力变革》&#xff0c;不禁感叹&#xff1a;现在连写书都这么卷了&#xff01; 要知道&#xff0c;ChatGPT 于去年11月30日刚刚发布、…

ZadigX 发布:价值驱动一切 链接最酷玩家

Zadig 徜徉开源大漠&#xff0c;用爱发电两年之际&#xff0c;低调发布企业版 ZadigX&#xff0c;广泛链接一切价值创造者。发布会将在 2023 年 4 月 27 日 以全线上形式举办&#xff0c;特邀一位神秘总裁&#xff0c;两大车企总监&#xff0c;十大云原生盟主联创/CEO&#xff…

我是普通人,我居然可以这样借力ChatGPT?(此文不卖课)

昨天写了一篇《程序员&#xff0c;如何借力ChatGPT&#xff1f;》&#xff0c;分享了借助AI&#xff1a; &#xff08;1&#xff09;撰写通用代码&#xff1b; &#xff08;2&#xff09;协助寻找BUG&#xff1b; &#xff08;3&#xff09;协助优化算法性能&#xff1b; &…

没有ChatGPT和new bing ?加入文心一言!

前言: 话虽说ChatGPT和newbing已经席卷网络AI语言&#xff0c;当了现在ai的头号老大&#xff0c;但是那两个都是需要梯子才能使用&#xff0c;ChatGPT还需要付费&#xff0c;所以还是有很多童鞋是没有加入使用ai大军的&#xff0c;那我们不妨看一下这个:文心一言。 步入正题…

android自定义涂鸦,Android Studio:小Demo-“涂鸦”

一、在手机模拟器上显示一个图片 1、MainActivity.java里的代码 public class MainActivity extends AppCompatActivity { SuppressLint("ClickableViewAccessibility") Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanc…

android:在照片上绘制涂鸦

这个应该是简易版的美图秀秀(小伙伴们吐槽&#xff1a;你这也叫简易版的&#xff1f;&#xff1f;我们看着怎么不像啊……)。好吧&#xff0c;只是在图片上绘制涂鸦&#xff0c;然后保存。 一、选择图片 这个道长有必要说一下&#xff0c;在绘制涂鸦时&#xff0c;笔画会根据…

通过触摸屏事件实现在图片上涂鸦——Android

目的&#xff1a;记录在屏幕上滑动的轨迹&#xff0c;实现在图片上涂鸦的功能 开发工具&#xff1a;Android Studio3.3.2 实现过程&#xff1a; 第一步&#xff1a;新建drawBoard.java用于自定义view 将图片放到drawable文件夹下&#xff0c;用BitmapFactory.decodeResource加…