当前位置: 首页 > news >正文

ubuntu18.04 OpenGL开发(显示YUV)

源码参考:https://download.csdn.net/download/weixin_55163060/88382816

安装opengl库

sudo apt install libglu1-mesa-dev freeglut3-dev mesa-common-dev
安装opengl工具包
sudo apt install mesa-utils
检查opengl版本信息(桌面终端执行)
sudo glxinfo | grep "OpenGL version"
显示:OpenGL version string: 3.3 (Compatibility Profile) Mesa 20.0.8
安装glfw窗口管理器
sudo apt-get install cmake xorg-dev libglu1-mesa-dev
wget https://sourceforge.net/projects/glfw/files/glfw/3.3.5/glfw-3.3.5.zip(wget https://github.com/glfw/glfw/releases/download/3.3.5/glfw-3.3.5.zip)
unzip glfw-3.3.5.zip
cd glfw-3.3.5
mkdir build
cd build
cmake -DCMAKE_INSTALL_PREFIX=/usr/local ..
make -j8
sudo make install
【window.c】 
#include <GLFW/glfw3.h>
#include <stdio.h>int main(void)
{GLFWwindow* window;/* Initialize the library */if (!glfwInit())return -1;/* Create a windowed mode window and its OpenGL context */window = glfwCreateWindow(640, 480, "Hello World", NULL, NULL);if (!window){glfwTerminate();return -1;}/* Make the window's context current */glfwMakeContextCurrent(window);/* Loop until the user closes the window */while (!glfwWindowShouldClose(window)){//glClearColor()命令指定了清除背景时用的颜色值,这里的(1,0,0,1)代表RGB中的红色,末尾的1表示不透明度glClearColor(1.0, 0.0, 0.0, 1.0);
        /* Render here */glClear(GL_COLOR_BUFFER_BIT);/* Swap front and back buffers */glfwSwapBuffers(window);/* Poll for and process events */glfwPollEvents();}glfwTerminate();return 0;
}
编译
gcc -o window window.c -lglfw3 -lGL -lX11 -lm -lpthread -ldl
执行显示一个红色窗口
【linmath.h】
https://github.com/datenwolf/linmath.h/blob/master/linmath.h
一个精简的线性数学库,旨在进行图形编程。 支持vec3,vec4,mat4x4和四元数
【GLAD库】(初始化后调用gl函数编译不会报错)
https://glad.dav1d.de/
GLAD是用来管理OpenGL的函数指针的,所以在调用任何OpenGL的函数之前我们需要初始化GLAD。GLAD也可以使OpenGL基础渲染变得简单。
【triangle.c】
//! [code]
#include "glad.h"
#define GLAD_GL_IMPLEMENTATION
#include <GL/gl.h>
//#include "glad.h"
#define GLFW_INCLUDE_NONE
#include <GLFW/glfw3.h>#include "linmath.h"#include <stdlib.h>
#include <stddef.h>
#include <stdio.h>typedef struct Vertex
{vec2 pos;vec3 col;
} Vertex;static const Vertex vertices[3] =
{{ { -0.6f, -0.4f }, { 1.f, 0.f, 0.f } },{ {  0.6f, -0.4f }, { 0.f, 1.f, 0.f } },{ {   0.f,  0.6f }, { 0.f, 0.f, 1.f } }
};static const char* vertex_shader_text =
"#version 330\n"
"uniform mat4 MVP;\n"
"in vec3 vCol;\n"
"in vec2 vPos;\n"
"out vec3 color;\n"
"void main()\n"
"{\n"
"    gl_Position = MVP * vec4(vPos, 0.0, 1.0);\n"
"    color = vCol;\n"
"}\n";static const char* fragment_shader_text =
"#version 330\n"
"in vec3 color;\n"
"out vec4 fragment;\n"
"void main()\n"
"{\n"
"    fragment = vec4(color, 1.0);\n"
"}\n";static void error_callback(int error, const char* description)
{fprintf(stderr, "Error: %s\n", description);
}static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods)
{if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)glfwSetWindowShouldClose(window, GLFW_TRUE);
}int main(void)
{glfwSetErrorCallback(error_callback);if (!glfwInit())exit(EXIT_FAILURE);glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);GLFWwindow* window = glfwCreateWindow(640, 480, "OpenGL Triangle", NULL, NULL);if (!window){glfwTerminate();exit(EXIT_FAILURE);}glfwSetKeyCallback(window, key_callback);glfwMakeContextCurrent(window);
    if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)){return -1;}glfwSwapInterval(1);// NOTE: OpenGL error checks have been omitted for brevityGLuint vertex_buffer;glGenBuffers(1, &vertex_buffer);glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer);glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);const GLuint vertex_shader = glCreateShader(GL_VERTEX_SHADER);glShaderSource(vertex_shader, 1, &vertex_shader_text, NULL);glCompileShader(vertex_shader);const GLuint fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);glShaderSource(fragment_shader, 1, &fragment_shader_text, NULL);glCompileShader(fragment_shader);const GLuint program = glCreateProgram();glAttachShader(program, vertex_shader);glAttachShader(program, fragment_shader);glLinkProgram(program);const GLint mvp_location = glGetUniformLocation(program, "MVP");const GLint vpos_location = glGetAttribLocation(program, "vPos");const GLint vcol_location = glGetAttribLocation(program, "vCol");GLuint vertex_array;glGenVertexArrays(1, &vertex_array);glBindVertexArray(vertex_array);glEnableVertexAttribArray(vpos_location);glVertexAttribPointer(vpos_location, 2, GL_FLOAT, GL_FALSE,sizeof(Vertex), (void*) offsetof(Vertex, pos));glEnableVertexAttribArray(vcol_location);glVertexAttribPointer(vcol_location, 3, GL_FLOAT, GL_FALSE,sizeof(Vertex), (void*) offsetof(Vertex, col));while (!glfwWindowShouldClose(window)){int width, height;glfwGetFramebufferSize(window, &width, &height);const float ratio = width / (float) height;glViewport(0, 0, width, height);glClear(GL_COLOR_BUFFER_BIT);mat4x4 m, p, mvp;mat4x4_identity(m);mat4x4_rotate_Z(m, m, (float) glfwGetTime());mat4x4_ortho(p, -ratio, ratio, -1.f, 1.f, 1.f, -1.f);mat4x4_mul(mvp, p, m);glUseProgram(program);glUniformMatrix4fv(mvp_location, 1, GL_FALSE, (const GLfloat*) &mvp);glBindVertexArray(vertex_array);glDrawArrays(GL_TRIANGLES, 0, 3);glfwSwapBuffers(window);glfwPollEvents();}glfwDestroyWindow(window);glfwTerminate();exit(EXIT_SUCCESS);
}//! [code]
编译
gcc -o triangle glad.c triangle.c -lglfw3 -lGL -lX11 -lm -lpthread -ldl
执行程序显示旋转的三角形
【YUV描述】
一般RGB用于渲染,YUV用于传输。
YUV4:4:4:完全采用表示每个像素点都有一个Y,U,V。一个YUV占 8+8+8 = 24bits,3个字节。
YUV4:2:2: 就是2:1的水平取样,垂直完全采样,表示水平的两个像素有两个Y但是只有一个U一个V的采用格式。一个YUV占 8+4+4 = 16bits 2个字节。
YUV4:2:0:就是2:1的水平取样,2:1的垂直采样,表示上下左右四个像素点有4个Y但是只取一个U和一个V,一个YUV占 8+2+2 = 12bits 1.5个字节
planar的YUV格式表示先连续存储所有像素点的Y,再紧接着存储所有的U,再就是V。Y、U和V组件存储为三个独立的数组中。
packed的YUV格式表示每个像素点的YUV是连续交替存储的,先存储像素点1的YUV再存在像素点2的YUV像素点。Y、U和V组件存储在一个数组中。每个像素点的Y,U,V是连续交错存储的
YUV420P(YU12和YV12)格式
YU12:安卓的模式。存储顺序是先存Y,再存U,最后存V。YYYYYYYY UUVV (I420格式)
YV12:存储顺序是先存Y,再存V,最后存U。YYYYYYYY VVUU
YUV420SP(NV12和NV21)格式
NV12 是 IOS 中有的模式,它的存储顺序是先存 Y 分量,再 UV 进行交替存储。
NV21 是 安卓 中有的模式,它的存储顺序是先存 Y 分量,在 VU 交替存储
【h264转YUV命令】
ffmpeg -i C:\Users\Administrator\Desktop\test.h264 -y -an -frames 1 -s 1920x1080 out.yuv
pause
【GLSL】
OpenGL着色语言(OpenGL Shading Language)是用来在OpenGL中着色编程的语言,也即开发人员写的短小的自定义程序,他们是在图形卡的GPU (Graphic Processor Unit图形处理单元)上执行的,代替了固定的渲染管线的一部分,使渲染管线中不同层次具有可编程性。比如:视图转换、投影转换等。GLSL(GL Shading Language)的着色器代码分成2个部分:Vertex Shader(顶点着色器)和Fragment(片断着色器),有时还会有Geometry Shader(几何着色器)。负责运行顶点着色的是顶点着色器。它可以得到当前OpenGL 中的状态,GLSL内置变量进行传递。GLSL其使用C语言作为基础高阶着色语言,避免了使用汇编语言或硬件规格语言的复杂性。
【yuv_show.cpp】
#include<string>
#include<fstream>
#include<sstream>
#include<iostream>
#include<stdio.h>
#include "glad.h"
#include <GLFW/glfw3.h>typedef unsigned char BYTE;
const unsigned int SCR_WIDTH = 500;
const unsigned int SCR_HEIGHT = 600;
const int len = 1920*1080 * 3/2;
BYTE YUVdata [len];unsigned int VBO = 0;
unsigned int VAO = 0;
unsigned int EBO = 0;
unsigned int texturePIC = 0;
int shaderProgram = 0;GLuint texIndexarray[3];
GLuint texUniformY = 99;
GLuint texUniformU = 99;
GLuint texUniformV = 99;void LoadPicture()
{glGenTextures(3, texIndexarray);//生成三个纹理索引glBindTexture(GL_TEXTURE_2D, texIndexarray[0]);//为bind的纹理设置环绕,过滤方式glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);glBindTexture(GL_TEXTURE_2D, texIndexarray[1]);//为bind的纹理设置环绕,过滤方式glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);glBindTexture(GL_TEXTURE_2D, texIndexarray[2]);//为bind的纹理设置环绕,过滤方式glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);//使用着色器程序,返回采样器的序号glUseProgram(shaderProgram);//该语句必须要有;安装 指定着色器程序texUniformY = glGetUniformLocation(shaderProgram, "dataY");texUniformU = glGetUniformLocation(shaderProgram, "dataU");texUniformV = glGetUniformLocation(shaderProgram, "dataV");----------加载数据--------------------------------------------------------FILE* fp = fopen("./out.yuv","rb+");//I420int returns  =fread(YUVdata,1,len,fp);int w = 1920;int h = 1080;int ysize = w*h;int uvsize = w * h / 4;void* uptr = &YUVdata[ysize];void* vptr = &YUVdata[ysize * 5 / 4];//---------------------------------------------------------------------------glActiveTexture(GL_TEXTURE0);glBindTexture(GL_TEXTURE_2D, texIndexarray[0]);// texindexarray[0] =1//使用GL_red表示单通道,glfw3里边没有YUV那个GL属性;glTexImage2D(GL_TEXTURE_2D, 0 , GL_RED, w, h ,0, GL_RED,GL_UNSIGNED_BYTE ,YUVdata);glUniform1i(texUniformY,0);                //通过 glUniform1i 的设置,保证每个 uniform 采样器对应着正确的纹理单元;注意这里不能用tesindexarray[0];glActiveTexture(GL_TEXTURE1);glBindTexture(GL_TEXTURE_2D, texIndexarray[1]);glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, w/2, h/2, 0, GL_RED, GL_UNSIGNED_BYTE,uptr);glUniform1i(texUniformU, 1);glActiveTexture(GL_TEXTURE2);glBindTexture(GL_TEXTURE_2D, texIndexarray[2]);glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, w/2, h/2, 0, GL_RED, GL_UNSIGNED_BYTE,vptr);glUniform1i(texUniformV,2);glUseProgram(0);
}void render()
{glBindVertexArray(VAO);glUseProgram(shaderProgram);glDrawElements(GL_TRIANGLES,6,GL_UNSIGNED_INT,0);//glDrawArrays(GL_TRIANGLE_FAN,0,4);也可glUseProgram(0);glBindVertexArray(0);
}void initmodule()
{//做个一模型;正方形;映射了顶点坐标和纹理坐标的对应关系float vertexs[] = {//顶点坐标-------纹理坐标(屏幕坐标翻转)1.0f,  1.0f, 0.0f,  1.0f, 0.0f,   1.0f, -1.0f, 0.0f,  1.0f, 1.0f,   -1.0f, -1.0f, 0.0f,  0.0f, 1.0f,   -1.0f,  1.0f, 0.0f,  0.0f, 0.0f    };//一个正方形是由两个三角形得来的;记录顶点的索引顺序unsigned int indexs[] = {0,1,3,1,2,3,};//做VAOglGenVertexArrays(1,&VAO);glBindVertexArray(VAO);//做VBOglGenBuffers(1, &VBO);glBindBuffer(GL_ARRAY_BUFFER, VBO);//创建显存空间glBufferData(GL_ARRAY_BUFFER,sizeof(vertexs), vertexs, GL_STATIC_DRAW);//设置索引缓冲glGenBuffers(1,&EBO);glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,EBO);glBufferData(GL_ELEMENT_ARRAY_BUFFER,sizeof(indexs),indexs,GL_STATIC_DRAW);    //加载纹理图片,生成纹理LoadPicture();//设置第0个锚点,3个点,不需要归一化,跨度5个float可以读下一个点glVertexAttribPointer(0,3,GL_FLOAT,GL_FALSE,5*sizeof(float),(void*)0);//打开顶点glEnableVertexAttribArray(0);//纹理属性设置,纹理在第一个锚点上(指定顶点数据)glVertexAttribPointer(1,2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float)));//打开纹理glEnableVertexAttribArray(1);//解除绑定VBOglBindBuffer(GL_ARRAY_BUFFER,0);//解绑VAOglBindVertexArray(0);}void initshader(const char* verpath,const char* fragpath)
{//编译shader,并记录shaderIDstd::string VerCode("");std::string fregCode("");//读文件std::ifstream  vShaderFile;std::ifstream  fShaderFile;vShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit);fShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit);try{vShaderFile.open(verpath);fShaderFile.open(fragpath);std::stringstream vsstream, fsstream;vsstream << vShaderFile.rdbuf();fsstream << fShaderFile.rdbuf();VerCode = vsstream.str();fregCode = fsstream.str();}catch (const std::exception&){std::cout << "read file error" << std::endl;}const char* vshader = VerCode.c_str();const char* fshader = fregCode.c_str();//shader 编译连接unsigned int vertexID = 0, fragID = 0;char infoLog[512];//存储错误信息int  successflag = 0;vertexID = glCreateShader(GL_VERTEX_SHADER);glShaderSource(vertexID,1,&vshader,NULL );glCompileShader(vertexID);//获取编译是否成功glGetShaderiv(vertexID,GL_COMPILE_STATUS,&successflag);if (!successflag){glGetShaderInfoLog(vertexID,512,NULL,infoLog);std::string errstr(infoLog);std::cout << "v shader err"<<infoLog;}//fragfragID = glCreateShader(GL_FRAGMENT_SHADER);glShaderSource(fragID, 1, &fshader, NULL);glCompileShader(fragID);//获取编译是否成功glGetShaderiv(fragID, GL_COMPILE_STATUS, &successflag);if (!successflag){glGetShaderInfoLog(fragID, 512, NULL, infoLog);std::string errstr(infoLog);std::cout << "f shader err"<<infoLog;}//链接shaderProgram = glCreateProgram();glAttachShader(shaderProgram,vertexID);glAttachShader(shaderProgram,fragID);glBindAttribLocation(shaderProgram, 0, "aPos");glBindAttribLocation(shaderProgram, 1, "texCoord");glLinkProgram(shaderProgram);glGetProgramiv(shaderProgram,GL_LINK_STATUS,&successflag);if (!successflag){glGetShaderInfoLog(shaderProgram, 512, NULL, infoLog);std::string errstr(infoLog);std::cout << "link error";}//编译完成后,可以把中间的步骤程序删除glDeleteShader(vertexID);glDeleteShader(fragID);
}
void processInput(GLFWwindow *window)
{if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS){//将窗口设置为关闭,跳出循环glfwSetWindowShouldClose(window, true);}
}void framebuffer_size_callback(GLFWwindow* window, int width, int height)
{glViewport(0, 0, width, height);
}int main()
{//glfw初始化glfwInit();glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);//glfw创建窗口GLFWwindow* window = glfwCreateWindow(500, 600, "LearnOpenGL", NULL, NULL);if (window == NULL){printf("创建窗口失败");//终止glfwTerminate();return -1;}//显示窗口glfwMakeContextCurrent(window);//设置回调,当窗口大小调整后将调用该回调函数glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);// glad初始化if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)){printf("加载失败");return -1;}initshader("vertexShader.glsl", "fragmentShader.glsl");//先编译着色器initmodule();// 使用循环达到循环渲染效果while (!glfwWindowShouldClose(window)){//自定义输入事件processInput(window);glClearColor(0.0f,0.0f,0.0f,1.0f);glClear(GL_COLOR_BUFFER_BIT);render();//交互缓冲区,否则显示空白glfwSwapBuffers(window);//输入输出事件,否则无法对窗口进行交互glfwPollEvents();}//终止渲染 关闭并清理glfw本地资源glfwTerminate();return 0;
}
【vertexShader.glsl】
#version 330 core
layout(location = 0) in vec3 aPos;
layout(location = 1) in vec2 texCoord; out vec2 TexCoord;
void main()
{gl_Position = vec4(aPos.x,aPos.y,aPos.z,1.0);TexCoord = texCoord;
};
【fragmentShader.glsl】
#version 330 core
layout(location = 0) out vec4 FragColor;
in vec2 TexCoord;
uniform sampler2D dataY;
uniform sampler2D dataU;
uniform sampler2D dataV;
vec3 yuv;
vec3 rgb;
void main()
{yuv.x = texture2D(dataY, TexCoord).r-0.0625;yuv.y = texture2D(dataU, TexCoord).r-0.5;yuv.z = texture2D(dataV, TexCoord).r-0.5;rgb = mat3(1,              1,      1,     0,       -0.18732, 1.8556,    1.57481, -0.46813,      0) * yuv;   FragColor = vec4(rgb.x, rgb.y,rgb.z,1); 
};
【编译】
g++ -o yuv_show glad.c yuv_show.cpp -lglfw3 -lGL -lX11 -lm -lpthread -ldl
【运行】
1、报错:v shader err0:2(1): error: shader output explicit location requires GL_ARB_separate_shader_objects extension or GLSL 4.20
原因:fragmentShader.glsl和vertexShader.glsl搞反了
2、报错:段错误
解决方法:sudo ./yuv_show
注:render()函数中增加LoadPicture()并修改其为读取不同的yuv数据可以实现视频流的播放。

相关文章:

ubuntu18.04 OpenGL开发(显示YUV)

源码参考&#xff1a;https://download.csdn.net/download/weixin_55163060/88382816 安装opengl库 sudo apt install libglu1-mesa-dev freeglut3-dev mesa-common-dev 安装opengl工具包 sudo apt install mesa-utils 检查opengl版本信息&#xff08;桌面终端执行&#xff09…...

React(react18)中组件通信06——redux-toolkit + react-redux

React&#xff08;react18&#xff09;中组件通信06——redux-toolkit react-redux 1 前言1.1 redux 和 react-redux1.2 关于redux-toolkit1.2.1 官网1.2.2 为什么要用Redux Toolkit&#xff1f; 1.3 安装 Redux Toolkit1.4 Redux Toolkit相关API 2. 开始例子——官网例子2.1 …...

第七章 查找 九、B+树

目录 一、定义 二、B树需要满足的条件 三、重要考点 一、定义 1、B树是一种常用的数据结构&#xff0c;用于实现关系型数据库中的索引。 2、其特点是可以在磁盘等外存储器上高效地存储大量数据&#xff0c;并支持快速的查询、插入、删除等操作。 3、B树的结构类似于二叉搜…...

XPD911协议系列-集成同步降压多口互联控制器

产品描述&#xff1a; XPD911 是一款集成 USB Type-C、USB Power Delivery&#xff08;PD&#xff09; 3.1 以及 PPS、 QC3.0/3.0 /2.0 快充协议、华为 FCP/SCP/HVSCP 快充协议、三星 AFC 快充协议、VOOC 快充协议、MTK PE 快充协议、BC1.2 DCP 以及苹果设备 2.4A 充电规范的多…...

数字反转(蓝桥杯)

数字反转 题目描述 给定一个整数&#xff0c;请将该数各个位上数字反转得到一个新数。新数也应满足整数的常见形式&#xff0c;即除非给定的原数为零&#xff0c;否则反转后得到的新数的最高位数字不应为零&#xff08;参见实例 2&#xff09;。 输入描述 输入共 1 行&…...

十一.EtherCAT开发之microchip MCU D51+ LAN9253 的开发FOE应用(SPI directly 模式)

十一.EtherCAT开发之microchip MCU D51+ LAN9253 的开发FOE应用(SPI directly 模式) 文章目录 十一.EtherCAT开发之microchip MCU D51+ LAN9253 的开发FOE应用(SPI directly 模式)11.0 软件更新方式11.1 SSC TOOL配置11.2 MCU D51 FOE函数支持11.2.1 下载download11.2.2 上传up…...

【分布式计算】二、架构(Architectures)

1.中心化架构&#xff08;Centralized Architectures&#xff09; 1.1.经典C/S模型 服务器&#xff1a;一个或多个进程提供服务 客户端&#xff1a;一个或多个进程使用服务 客户端和服务器可以在不同的机器上 客户端遵循请求/回复模型 1.2.传统三层视图 用户界面层&#x…...

Springboot对MVC、tomcat扩展配置

Springboot在web层的开发基本都是采用Springmvc框架技术&#xff0c;但是Springmvc中的某些配置在boot是没有的&#xff0c;我们就应该根据自己的需求进行对mvc扩展配置 Springboot1.x版本如何配置 通过注解Configuration一个类&#xff0c;继承webmvcconfigureradapter&#…...

网络子网划分练习

网络子网划分练习 1.背景&#xff1a; 在一个仓储企业网络拓朴结构如图1-所示&#xff0c;该企业占地500亩。有五层办公楼1栋&#xff0c;大型仓库10栋。每栋仓库内、外部配置视频监控16台&#xff0c;共计安装视频监控160台&#xff0c;Switch A、服务器、防火墙、管理机、Rou…...

Leetcode刷题笔记--Hot51-60

1--环形链表II 主要思路&#xff1a; 快慢指针&#xff0c;快指针每次走两步&#xff0c;慢指针每次走一步&#xff1b; 第一次相遇时&#xff0c;假设慢指针共走了 f 步&#xff0c;则快指针走了 2f 步&#xff1b; 假设起点到环入口结点的长度为 a&#xff08;不包括入口结点…...

广告牌安全监测系统,用科技护航大型广告牌安全

城市的街头巷尾&#xff0c;处处可见高耸的广告牌&#xff0c;它们以各种形式和颜色吸引着行人的目光。然而&#xff0c;作为城市景观的一部分&#xff0c;广告牌的安全性常常被我们所忽视。广告牌量大面大&#xff0c;由于设计、材料、施工方法的缺陷&#xff0c;加上后期的检…...

volatile

什么是volatile volatile是Java提供的一种轻量级的同步机制。Java 语言包含两种内在的同步机制&#xff1a;同步块&#xff08;或方法&#xff09;和 volatile 变量&#xff0c;相比于synchronized&#xff08;synchronized通常称为重量级锁&#xff09;&#xff0c;volatile更…...

JAVA:实现Excel和PDF上下标

1、简介 最近项目需要实现26个小写字母的上下标功能,自己去网上找了所有Unicode的上下标形式,缺少一些关键字母,顾后面考虑自己创建上下标字体样式,以此来记录。 2、Excel Excel本身是支持上下标,我们可以通过Excel单元格的样式来设置当前字体上下标,因使用的是POI的m…...

AI写稿软件,最新的AI写稿软件有哪些

写作已经成为各行各业无法绕开的重要环节。不论是企业的广告宣传、新闻媒体的报道、还是个人自媒体的内容创作&#xff0c;文字都扮演着不可或缺的角色。随着信息的爆炸式增长&#xff0c;写作的需求也不断攀升&#xff0c;这使得许多人感到困扰。时间不够用、创意枯竭、写作技…...

干货:数据仓库基础知识(全)

1、什么是数据仓库&#xff1f; 权威定义&#xff1a;数据仓库是一个面向主题的、集成的、相对稳定的、反映历史变化的数据集合&#xff0c;用于支持管理决策。 1&#xff09;数据仓库是用于支持决策、面向分析型数据处理&#xff1b; 2&#xff09;对多个异构的数据源有效集…...

二分搜索简介

概念&#xff1a; 二分搜索算法&#xff08;Binary Search&#xff09;是一种高效的搜索算法&#xff0c;用于在有序数组中查找特定元素的位置。它的基本思想是将数组分为两部分&#xff0c;通过比较目标值与数组中间元素的大小关系&#xff0c;确定目标值可能存在的区间&…...

虚拟车衣VR云展厅平台扩大了展览的触达范围

传统展厅主要是以静态陈列的形式来传达内容&#xff0c;主要的展示形式有图片、视频等&#xff0c;具有一定的局限性&#xff0c;体验感较差&#xff0c;客户往往不能深入地了解信息和细节内容。 VR全景看车是通过虚拟现实技术实现逼真的汽车观赏和试乘体验。消费者可以通过智能…...

云部署家里的服务器

1.固定静态ip 查看ip地址&#xff0c;en开头的 ifconfig查看路由器ip&#xff0c;via开头的 ip route修改配置文件 cd /etc/netplan/ #来到这个文件夹 sudo cp 01-network-manager-all.yaml 01-network-manager-all.yaml.bak #先备…...

【利用冒泡排序的思想模拟实现qsort函数】

1.qsort函数 1.1qsort函数的介绍 资源来源于cplusplus网站 1.2qsort函数的主要功能 对数组的元素进行排序 对数组中由 指向的元素进行排序&#xff0c;每个元素字节长&#xff0c;使用该函数确定顺序。 此函数使用的排序算法通过调用指定的函数来比较元素对&#xff0c;并将指…...

[plugin:vite:css] [sass] Undefined mixin.

前言&#xff1a; vite vue3 TypeScript环境 scss报错&#xff1a; [plugin:vite:css] [sass] Undefined mixin. 解决方案&#xff1a; 在vite.config.ts文件添加配置 css: {preprocessorOptions: {// 导入scss预编译程序scss: {additionalData: use "/resources/_ha…...

陀螺匠企业助手-产品

1. 功能说明维护出售产品的基本信息数据&#xff0c;支持在添加商机/合同中进行选择。2. 进入产品页面路径&#xff1a;客户>产品管理>产品3. 新增产品功能说明&#xff1a;维护产品信息&#xff0c;添加完成的产品信息&#xff0c;可以在添加商机/合同中进行选择。新增产…...

SignalAcquisition:嵌入式高精度信号采集与二进制串行传输框架

1. SignalAcquisition 库深度解析&#xff1a;面向嵌入式信号采集的高精度时序控制与二进制串行传输框架1.1 库定位与工程价值SignalAcquisition 是一个专为 Arduino IDE 设计的轻量级、高确定性信号采集库&#xff0c;其核心目标并非提供通用传感器驱动&#xff0c;而是构建一…...

ESLyric歌词源高效配置与避坑指南:Foobar2000用户进阶教程

ESLyric歌词源高效配置与避坑指南&#xff1a;Foobar2000用户进阶教程 【免费下载链接】ESLyric-LyricsSource Advanced lyrics source for ESLyric in foobar2000 项目地址: https://gitcode.com/gh_mirrors/es/ESLyric-LyricsSource ESLyric-LyricsSource是Foobar2000…...

Phi-4-Reasoning-Vision行业落地:教育领域图像题解与隐藏线索识别案例

Phi-4-Reasoning-Vision行业落地&#xff1a;教育领域图像题解与隐藏线索识别案例 1. 项目背景与价值 在教育领域&#xff0c;图像题解和隐藏线索识别一直是教学和考试中的难点。传统方法依赖人工标注和分析&#xff0c;效率低下且容易遗漏关键信息。Phi-4-Reasoning-Vision多…...

GCC编译选项详解与工程实践指南

GCC编译选项深度解析与工程实践指南1. 编译选项基础概念1.1 编译过程与选项作用GCC编译过程分为预处理、编译、汇编和链接四个阶段。编译选项通过控制这些阶段的行为&#xff0c;实现不同的编译目标&#xff1a;# 完整编译流程示例 gcc -E main.c -o main.i # 预处理 gcc -S…...

【读书笔记】《逆风跑者》

《逆风跑者》| 长跑人的阿甘正传 如果你也曾困顿过&#xff0c;迷茫过&#xff0c;被生活压得喘不过气来&#xff0c;那么就拉过一把椅子静静地坐一会儿吧。听我说说这位无声跑者的事儿&#xff0c;和他一起不屈不挠地寂静奔跑一次。 &#x1f4d6; 关于这本书 《逆风跑者》是…...

联想ThinkPad声卡驱动安装避坑指南:从E470到X1 Carbon的通用解法

ThinkPad声卡驱动安装全攻略&#xff1a;从型号识别到疑难排解 ThinkPad作为商务笔记本的代表&#xff0c;其稳定性和兼容性一直备受推崇。但即便是这样成熟的产品线&#xff0c;声卡驱动问题依然困扰着不少用户——从经典的E470到高端的X1 Carbon&#xff0c;不同机型可能面临…...

源网荷储全场景适配:新型电力系统时序数据库落地指南

新型电力系统应该用什么数据库&#xff1f;源网荷储四侧的时序数据库选型与落地实战 “双碳”目标的推进正在深刻重构电力系统的运行逻辑。新能源装机占比持续攀升&#xff0c;储能、虚拟电厂、需求响应等新业态快速涌现&#xff0c;源、网、荷、储各侧的角色与互动方式正在被…...

ArduPilot电机控制逻辑与PWM输出机制剖析

1. ArduPilot电机控制基础概念 当你第一次接触无人机飞控时&#xff0c;最让人困惑的莫过于电机控制逻辑了。想象一下&#xff0c;你手里拿着遥控器&#xff0c;轻轻推动摇杆&#xff0c;无人机就能平稳地上升、下降或者转向。这背后到底发生了什么&#xff1f;让我用最直白的…...

Simcenter Amesim 2023与Matlab 2023a联合仿真:从环境配置到实战例程详解

1. 联合仿真环境搭建前的准备工作 在开始Simcenter Amesim 2023与Matlab 2023a的联合仿真之前&#xff0c;我们需要做好充分的准备工作。这就像盖房子前要打好地基一样重要&#xff0c;否则后续工作可能会遇到各种意想不到的问题。 首先说说硬件要求。根据我的实测经验&#xf…...