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 void>) => {
              if (xComponentContext) {
                SRLog.i(TAG, "xComponentContext======")
                this.xComponentContext = xComponentContext as Record 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 SRWindowManager::m_nativeXComponentMap;
std::unordered_map 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(&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(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);
    }

你可能感兴趣的:(HarmonyOS,OpenHarmony)