一、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_END
static 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);
// y
if (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);
// u
if (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);
// v
if (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 textures
LogE("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);
}