HarmonyOS通过OpenGL渲染显示yuv数据

一、UI页面render_page.ets

Column() {XComponent({id: "XComponent88",type: XCompentConstants.XCOMPONENT_TYPE,libraryname: XCompentConstants.XCOMPONENT_LIBRARY_NAME}).width(640).height(360).onLoad((xComponentContext?: object | Record<string, () => void>) => {if (xComponentContext) {SRLog.i(TAG, "xComponentContext======")this.xComponentContext = xComponentContext as Record<string, (userid: number, streamid: number) => void>;this.xComponentContext.setBindUser(123, 1);}})
}

 二、通过NAPI创建RenderManager管理Xcompent的windows窗口

1、NAPI初始化:init_napi.cpp

#include "util/Log.h"
#include "napi/native_api.h"
#include "rtc/SRRtcVideoEngineNapi.h"
#include "SRWindowManager.h"
#include "net/SRHttpManager.h"EXTERN_C_START
static napi_value Init(napi_env env, napi_value exports) {napi_property_descriptor desc[] = {{"testRender", nullptr, SRRtcVideoEngineNapi::testRender, nullptr, nullptr, nullptr, napi_default, nullptr},{"getNativeLifeCycle", nullptr, SRWindowManager::getNativeLifeCycle, nullptr, nullptr, nullptr, napi_default,nullptr}};if (napi_ok != napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc)) {LogE("init_napi===napi_define_properties failed");return nullptr;}SRWindowManager::GetInstance()->Export(env, exports);return exports;
}
EXTERN_C_ENDstatic napi_module demoModule = {.nm_version = 1,.nm_flags = 0,.nm_filename = nullptr,.nm_register_func = Init,.nm_modname = "rtcvideo",.nm_priv = ((void *)0),.reserved = {0},
};extern "C" __attribute__((constructor)) void RegisterRtcvideoModule(void) { napi_module_register(&demoModule); }

2、绑定XCompendNative的实现:SRWindowManager.cpp

std::unordered_map<std::string, OH_NativeXComponent *> SRWindowManager::m_nativeXComponentMap;
std::unordered_map<std::string, SRGLRender *> SRWindowManager::m_SRGLRenderMap;
void SRWindowManager::Export(napi_env env, napi_value exports) {LogE("PluginManager::Export====");if ((nullptr == env) || (nullptr == exports)) {LogE("PluginManager::Export: env or exports is null");return;}napi_value exportInstance = nullptr;if (napi_ok != napi_get_named_property(env, exports, OH_NATIVE_XCOMPONENT_OBJ, &exportInstance)) {LogE("PluginManager::Export: napi_get_named_property fail");return;}OH_NativeXComponent *nativeXComponent = nullptr;if (napi_ok != napi_unwrap(env, exportInstance, reinterpret_cast<void **>(&nativeXComponent))) {LogE("PluginManager::Export: napi_unwrap fail");return;}char idStr[OH_XCOMPONENT_ID_LEN_MAX + 1] = {'\0'};uint64_t idSize = OH_XCOMPONENT_ID_LEN_MAX + 1;if (OH_NATIVEXCOMPONENT_RESULT_SUCCESS != OH_NativeXComponent_GetXComponentId(nativeXComponent, idStr, &idSize)) {LogE("Export: OH_NativeXComponent_GetXComponentId fail");return;}std::string id(idStr);auto context = SRWindowManager::GetInstance();if ((nullptr != context) && (nullptr != nativeXComponent)) {context->SetNativeXComponent(id, nativeXComponent);auto render = context->GetRender(id);OH_NativeXComponent_RegisterCallback(nativeXComponent, &SRGLRender::m_callback);if (nullptr != render) {render->Export(env, exports);}}
}void SRWindowManager::SetNativeXComponent(std::string &id, OH_NativeXComponent *nativeXComponent) {if (nullptr == nativeXComponent) {return;}if (m_nativeXComponentMap.find(id) == m_nativeXComponentMap.end()) {m_nativeXComponentMap[id] = nativeXComponent;return;}if (m_nativeXComponentMap[id] != nativeXComponent) {OH_NativeXComponent *tmp = m_nativeXComponentMap[id];delete tmp;tmp = nullptr;m_nativeXComponentMap[id] = nativeXComponent;}
}SRGLRender *SRWindowManager::GetRender(std::string &id) {if (m_SRGLRenderMap.find(id) == m_SRGLRenderMap.end()) {SRGLRender *instance = SRGLRender::GetInstance(id);m_SRGLRenderMap[id] = instance;return instance;}return m_SRGLRenderMap[id];
}

三、OpenGL渲染模块

1、定义Shader

const char VERTEX_SHADER11[] = "attribute vec4 vPosition;\n""attribute vec2 a_texCoord;\n""varying vec2 tc;\n"" uniform mat4 uMVPMatrix;\n""void main() {\n""gl_Position =uMVPMatrix * vPosition  ;\n""tc = a_texCoord;\n""}\n";const char FRAGMENT_SHADER11[] = "precision mediump float;\n""uniform sampler2D tex_y;\n""uniform sampler2D tex_u;\n""uniform sampler2D tex_v;\n""varying vec2 tc;\n""void main() {\n""vec4 c = vec4((texture2D(tex_y, tc).r - 16./255.) * 1.164);\n""vec4 U = vec4(texture2D(tex_u, tc).r - 128./255.);\n""vec4 V = vec4(texture2D(tex_v, tc).r - 128./255.);\n""c += V * vec4(1.596, -0.813, 0, 0);\n""c += U * vec4(0, -0.392, 2.017, 0);\n""c.a = 1.0;\n""gl_FragColor = c;\n""}\n";

2、初始化EglContextInit

bool EGLCore::EglContextInit(void *window, int width, int height) {LogE("EGLCore::EglContextInit execute===width:%d,height:%d", width, height);if (nullptr == window) {LogE("EGLCore::EglContextInit window=nullptr");}if ((nullptr == window) || (0 >= width) || (0 >= height)) {LogE("EGLCore::EglContextInit: param error");return false;}w_width = width;w_height = height;LogE("EGLCore::EglContextInit: param m_width:%d;%d", w_width, w_height);m_eglWindow = reinterpret_cast<EGLNativeWindowType>(window);// Init display.m_eglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);if (EGL_NO_DISPLAY == m_eglDisplay) {LogE("EGLCore:: eglGetDisplay: unable to get EGL display");return false;}EGLint majorVersion;EGLint minorVersion;if (!eglInitialize(m_eglDisplay, &majorVersion, &minorVersion)) {LogE("EGLCore:: eglInitialize: unable to get initialize EGL display");return false;}// Select configuration.const EGLint maxConfigSize = 1;EGLint numConfigs;if (!eglChooseConfig(m_eglDisplay, ATTRIB_LIST, &m_eglConfig, maxConfigSize, &numConfigs)) {LogE("EGLCore::eglChooseConfig: unable to choose configs");return false;}bool isCreateEnvironment = CreateEnvironment();if (isCreateEnvironment) {glClearColor(0.0, 0.0, 0.0, 0.0);GLuint textures[1];glGenTextures(1, &textures[0]);}return isCreateEnvironment;
}bool EGLCore::CreateEnvironment() {// Create surface.m_eglSurface = eglCreateWindowSurface(m_eglDisplay, m_eglConfig, m_eglWindow, NULL);if (nullptr == m_eglSurface) {LogE("EGLCore:: eglCreateWindowSurface: unable to create surface");return false;}// Create context.m_eglContext = eglCreateContext(m_eglDisplay, m_eglConfig, EGL_NO_CONTEXT, CONTEXT_ATTRIBS);if (!eglMakeCurrent(m_eglDisplay, m_eglSurface, m_eglSurface, m_eglContext)) {LogE("EGLCore::eglMakeCurrent failed");return false;}// Create program.m_program = CreateProgram(VERTEX_SHADER11, FRAGMENT_SHADER11);if (PROGRAM_ERROR == m_program) {LogE("EGLCore::CreateProgram: unable to create program");return false;}// 获取着色器的aPostion和a_textCoord_positionHandle = glGetAttribLocation(m_program, "vPosition");mMatrixHandle = glGetUniformLocation(m_program, "uMVPMatrix");_coordHandle = glGetAttribLocation(m_program, "a_texCoord");_yhandle = glGetUniformLocation(m_program, "tex_y");_uhandle = glGetUniformLocation(m_program, "tex_u");_vhandle = glGetUniformLocation(m_program, "tex_v");LogE("EGLCore::CreateProgram: ""_positionHandle:%d;mMatrixHandle:%d;_coordHandle:%d;_yhandle:%d;_uhandle:%d;_vhandle:%d",_positionHandle, mMatrixHandle, _coordHandle, _yhandle, _uhandle, _vhandle);_textureI = GL_TEXTURE0;_textureII = GL_TEXTURE1;_textureIII = GL_TEXTURE2;LogE("EGLCore::CreateProgram: _textureI:%d;_textureII:%d;_textureIII:%d", _textureI, _textureII, _textureIII);return true;
}GLuint EGLCore::CreateProgram(const char *vertexShader, const char *fragShader) {if ((nullptr == vertexShader) || (nullptr == fragShader)) {LogE("EGLCore:: createProgram: vertexShader or fragShader is null");return PROGRAM_ERROR;}GLuint vertex_shader;vertex_shader = LoadShader(GL_VERTEX_SHADER, vertexShader);if (PROGRAM_ERROR == vertex_shader) {LogE("EGLCore:: createProgram vertex error");return PROGRAM_ERROR;}GLuint fragment_shader;fragment_shader = LoadShader(GL_FRAGMENT_SHADER, fragShader);if (PROGRAM_ERROR == fragment_shader) {LogE("EGLCore:: createProgram fragment error");return PROGRAM_ERROR;}GLint vCompiled[4] = {0};
//    glGetShaderiv(vertex_shader, GL_COMPILE_STATUS, vCompiled);
//    if (vCompiled[0] == 0) {
//        glDeleteShader(vertex_shader);
//    }glGetShaderiv(vertex_shader, GL_COMPILE_STATUS, vCompiled);if (vCompiled[0] != GL_TRUE) {LogE("EGLCore:: createProgram vertex_shader error");//        DeleteProgram();return PROGRAM_ERROR;}glGetShaderiv(fragment_shader, GL_COMPILE_STATUS, vCompiled);if (vCompiled[0] != GL_TRUE) {LogE("EGLCore:: createProgram fragment_shader error");//        DeleteProgram();return PROGRAM_ERROR;}GLuint program;program = glCreateProgram();if (PROGRAM_ERROR == program) {LogE("EGLCore:: createProgram program error");glDeleteShader(vertex_shader);glDeleteShader(fragment_shader);return PROGRAM_ERROR;} else {LogE("EGLCore:: createProgram 加载着色器");glAttachShader(program, vertex_shader);glAttachShader(program, fragment_shader);glLinkProgram(program);// 存放链接成功的program的数组GLint linkedStatus[4] = {0};glGetProgramiv(program, GL_LINK_STATUS, linkedStatus);if (linkedStatus[0] != GL_TRUE) {LogE("EGLCore:: createProgram linkedStatus==error=linkedStatus[0]:%d", linkedStatus[0]);glDeleteShader(program);return PROGRAM_ERROR;}glUseProgram(program);}glDeleteShader(vertex_shader);glDeleteShader(fragment_shader);LogE("EGLCore:: createProgram linked success");return program;
}GLuint EGLCore::LoadShader(GLenum type, const char *shaderSrc) {if ((0 >= type) || (nullptr == shaderSrc)) {LogE("EGLCore:: glCreateShader type or shaderSrc error");return PROGRAM_ERROR;}GLuint shader;shader = glCreateShader(type);if (0 == shader) {LogE("EGLCore:: glCreateShader unable to load shader");return PROGRAM_ERROR;}// The gl function has no return value.glShaderSource(shader, 1, &shaderSrc, nullptr);glCompileShader(shader);return shader;
}

3、渲染实现

void EGLCore::onRenderData(void *yData, void *uData, void *vData, int width, int height) {if ((nullptr == m_eglDisplay) || (nullptr == m_eglSurface) || (nullptr == m_eglContext) ||(!eglMakeCurrent(m_eglDisplay, m_eglSurface, m_eglSurface, m_eglContext))) {LogE("EGLCore:: PrepareDraw: param error");return;}// The gl function has no return value.LogE("EGLCore:: PrepareDraw: param m_height:%d,m_width:%d", w_height, w_width);glViewport(0, 0, w_width, w_height);glClearColor(0, 0, 0, 1.0);glClear(GL_COLOR_BUFFER_BIT);glUseProgram(m_program);// 开始渲染LogE("EGLCore::draw: ""_positionHandle:%d;mMatrixHandle:%d;_coordHandle:%d;_yhandle:%d;_uhandle:%d;_vhandle:%d",_positionHandle, mMatrixHandle, _coordHandle, _yhandle, _uhandle, _vhandle);// yif (m_glTexture[0] < 0) {glGenTextures(1, &m_glTexture[0]);LogE("EGLCore::CreateProgram:  _ytid ", m_glTexture[0]);}glBindTexture(GL_TEXTURE_2D, m_glTexture[0]);glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, width, height, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, yData);glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);// uif (m_glTexture[1] < 0) {glGenTextures(1, &m_glTexture[1]);LogE("EGLCore::draw:  _utid ", m_glTexture[1]);}int w1 = (width + 1) / 2;int h1 = (height + 1) / 2;glBindTexture(GL_TEXTURE_2D, m_glTexture[1]);glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, w1, h1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, uData);glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);// vif (m_glTexture[2] < 0) {glGenTextures(1, &m_glTexture[2]);LogE("EGLCore::CreateProgram:  _vtid ", m_glTexture[2]);}glBindTexture(GL_TEXTURE_2D, m_glTexture[2]);glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, w1, h1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, vData);glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);// draw//  使用shader程序glUseProgram(m_program);// 将最终变换矩阵传入shader程序glUniformMatrix4fv(mMatrixHandle, 1, false, mMMatrix);// 顶点位置数据传入着色器glVertexAttribPointer(_positionHandle, 2, GL_FLOAT, false, 8, vertices);glEnableVertexAttribArray(_positionHandle);glVertexAttribPointer(_coordHandle, 2, GL_FLOAT, false, 8, texCoords);// 允许使用顶点坐标数组glEnableVertexAttribArray(_coordHandle);// bind texturesLogE("EGLCore::draw: _textureI:%d;_textureII:%d;_textureIII:%d", _textureI, _textureII, _textureIII);// 绑定纹理glActiveTexture(_textureI);glBindTexture(GL_TEXTURE_2D, m_glTexture[0]);glUniform1i(_yhandle, _tIindex);glActiveTexture(_textureII);glBindTexture(GL_TEXTURE_2D, m_glTexture[1]);glUniform1i(_uhandle, _tIIindex);glActiveTexture(_textureIII);glBindTexture(GL_TEXTURE_2D, m_glTexture[2]);glUniform1i(_vhandle, _tIIIindex);// 图形绘制glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);//    glFinish();glDisableVertexAttribArray(_positionHandle);glDisableVertexAttribArray(_coordHandle);glFlush();glFinish();eglSwapBuffers(m_eglDisplay, m_eglSurface);
}

4、测试代码实现

 std::string id(idStr);SRGLRender *render = SRGLRender::GetInstance(id);if (nullptr != render) {int width = 960;int height = 540;int uWidth = width / 2;int uHeight = height / 2;unsigned char *yData = new unsigned char[width * height];unsigned char *uData = new unsigned char[(width * height) / 2];unsigned char *vData = new unsigned char[(width * height) / 2];for (int i = 0; i < width * height; ++i) {yData[i] = color;}// 填充Y数据为红色for (int i = 0; i < (uWidth * uHeight); ++i) {uData[i] = color;vData[i] = color;}render->m_eglCore->onRenderData(yData, uData, vData, width, height);}

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

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

相关文章

【RPC】基础

RPC 基本概念组成存在的问题python实现 基本概念 RPC是一个计算机通信协议&#xff0c;允许运行在一台计算机的程序调用另一台计算机的子程序&#xff0c;允许调用远程服务&#xff0c;是一个C/S模式。下图是百度百科的信息&#xff0c;可以看到&#xff0c;它的作用就是我想用…

history和hash两种路由模式原理,和优缺点

Hash Hash 模式是在 URL 中使用井号&#xff08;#&#xff09;来作为路由的模式。在 Hash 模式下&#xff0c;即使页面刷新&#xff0c;浏览器仍然只会请求页面的初始 HTML 文件&#xff0c;所有的路由变化都会在 URL 前面添加 “#/” 符号。 原理 在 Hash 模式下&#xff0c;路…

gitlab高级功能之CI/CD组件 - 实践(二)

上一篇主要讲解了CI/CD组件的原理&#xff0c;看起来稍微有一点枯燥&#xff0c;那么接下来给大家演示下如何使用。 案例 创建一个项目&#xff08;README.md&#xff0c;template目录&#xff09; 案例1 step1: 在template中新建yml文件&#xff0c;cat templates/test-st…

Verilog 入门(六)行为建模

文章目录 过程结构initial 语句always 语句 事件控制语句块顺序语句块并行语句块 过程性赋值阻塞性过程赋值非阻塞性过程赋值 过程结构 下述两种语句是为一个设计的行为建模的主要机制&#xff1a; initial 语句always 语句 一个模块中可以包含任意多个 initial 或 always 语…

C/C++11 语法/概念易错总结(1)

文章目录 缺省参数函数重载引用引用和指针内联宏的优缺点auto范围forNULL和nullptr 缺省参数 半缺省参数必须从右往左依次来给出&#xff0c;不能间隔着给 void Func(int a, int b 10, int c 20){cout<<"a "<<a<<endl;cout<<"b &…

一些ab命令

1.ab简介 ab是apache自带的压力测试工具&#xff0c;是apachebench命令的缩写。ab非常实用&#xff0c;它不仅可以对apache服务器进行网站访问压力测试&#xff0c;也可以对或其它类型的服务器如nginx、tomcat、IIS等进行压力测试。 ab的原理&#xff1a;ab命令会创建多个并发…

在编程中遇到的问题总结

IDEA空包粘黏问题 创建好目录以后会发现idea自动将空包合并在一起了&#xff0c;而且点击设置里面也没有Compact Middle Package Compact Middle Package如果不在设置的主面板上&#xff0c;则点击Tree Appearance&#xff0c;会发现Compact Middle Package在Tree Appearance里…

elupload base64

创作灵感也许就是这会儿还没有入睡吧&#xff0c;对接百度图片OCR功能&#xff0c;需要将图片转为BASE64上传调用百度的接口api&#xff0c;进行研究实现。页面如下&#xff0c;点击后选择图片文件后不是直接上传&#xff0c;而是获取图片的bytes数据&#xff01; <el-uploa…

516. 最长回文子序列

给你一个字符串 s &#xff0c;找出其中最长的回文子序列&#xff0c;并返回该序列的长度。 子序列定义为&#xff1a;不改变剩余字符顺序的情况下&#xff0c;删除某些字符或者不删除任何字符形成的一个序列。 示例 1&#xff1a; 输入&#xff1a;s "bbbab" 输出…

力扣117. 填充每个节点的下一个右侧节点指针 II

“递归” 思路&#xff1a; 基于节点&#xff0c;创建下一层&#xff08;L 1&#xff09;节点的 next 指针&#xff1a; 确定当前节点下一层节点 next 链表的起始节点&#xff0c;迭代到需要找非孩子的 next 节点时&#xff0c;根据其当层&#xff08;L&#xff09; next 链表…

IO / day01 作业。

1.使用fgets统计一个文件的行号 //使用fgets统计一个文件的行号#include <string.h> #include <stdlib.h> #include <stdio.h>int main(int argc, const char *argv[]) {if(argc<2) //获取文件名{printf("input error\n!");printf("usage…

将不同时间点的登录状态记录转化为不同时间段的相同登录状态SQL求解

题目 有不同时间点的登录状态记录表state_log如下 请使用sql将其转化为如下表的不同时间段的相同登录状态记录 思路分析&#xff1a; 此类问题需要用到lag或lead函数取上下行对应的数据&#xff0c;然后对前后结果做比较打标签&#xff08;0或1&#xff09;&#xff0c;再…

pycharm中绘制一个3D曲线

import numpy as np import matplotlib.pyplot as plt # 中文的设置 import matplotlib as mp1 from mpl_toolkits.mplot3d import Axes3D mp1.rcParams["font.sans-serif"] ["kaiti"] mp1.rcParams["axes.unicode_minus"] False # 数据创建 X…

基于SSM的经典电影推荐网站设计与实现

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;Vue 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#xff1a;是 目录…

从react到xflow

从react到xflow 注意&#xff1a;xflow 1.0版本已经停止维护&#xff0c;2.0版本目前没有任何文档&#xff0c;也不太推荐使用 0、学习目标 可以使用react框架构建出前端web页面&#xff0c;并且使用xflow插入流程图 1、为什么要使用react&#xff1f; 优点&#xff1a;使用…

解决VSCode按住Ctrl(or Command) 点击鼠标左键不跳转的问题(不能Go to Definition)

问题出现 往往在升级了VSCode以后&#xff0c;就会出现按住Ctrl&#xff08;or Command&#xff09; 点击鼠标左键不跳转的问题&#xff0c;这个问题很常见。 解决办法 1 进入VScode的首选项&#xff0c;选择设置 2 输入Go to definition&#xff0c;找到如下两个设置&#…

如何创建百科?建立百科词条的意义何在?九问百科营销

在营销工作实践中&#xff0c;小马识途营销顾问经常接到关于百科营销的咨询&#xff0c;现整理了最受关注的九个问题分享给热爱营销工作的小伙伴。 一、什么是百科营销&#xff1f; 百科营销是借助百科知识传播&#xff0c;可以将企业、品牌、人物所拥有的对用户有价值的信息&a…

【存储测试】fio存储性能测试工具

一、前言 GitHub地址&#xff1a;fio 官方文档&#xff1a;HOWTO 1、介绍 fio&#xff08;flexible I/O Tester&#xff09; 是一款由 Jens Axboe 开发的用于测评和压力/硬件验证的自由开源的软件&#xff0c;适用于文件及块接口性能测试。 fio常用的I/O引擎主要分为以下两种…

熬夜会秃头——beta冲刺Day3

这个作业属于哪个课程2301-计算机学院-软件工程社区-CSDN社区云这个作业要求在哪里团队作业—beta冲刺事后诸葛亮-CSDN社区这个作业的目标记录beta冲刺Day3团队名称熬夜会秃头团队置顶集合随笔链接熬夜会秃头——Beta冲刺置顶随笔-CSDN社区 目录 一、团队成员会议总结 1、成员…

【算法】单调栈题单——字典序最小⭐(一种类型的模板题)

文章目录 题目列表316. 去除重复字母⭐⭐⭐⭐⭐&#xff08;类型题模板&#xff1a;单调栈&#xff0c;字典序最小&#xff09;221021天池-03. 整理书架&#xff08;保留数量为 limit 的字典序最小&#xff09;402. 移掉 K 位数字&#xff08;最多删除 k 次 前导零的处理&…