一、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);}