OpenGL是一个图形API,并不是一个独立的平台。包含了一系列可以操作图形、图像的函数。基于Texture纹理强盛的功能,本篇文章实现Android OpenGL Texture C++ 预览Camera视频流的功能。
项目github地址:https://github.com/wangyongyao1989/WyFFmpeg
一、代码实现步骤及图示预览:
二、Camera数据获取:
Android Camera可以获取图片数据的视频流信息。
1、 打开Camera后,获取ImageReader读取视频对应的相片数据。
- /**
- * Opens the camera.
- */
- @SuppressLint({"WrongConstant", "MissingPermission"})
- public void openCamera() {
- if (checkSelfPermission(mContext, Manifest.permission.CAMERA)
- != PackageManager.PERMISSION_GRANTED) {
- return;
- }
- mImageReader = ImageReader.newInstance(mPreviewSize.getWidth()
- , mPreviewSize.getHeight()
- , ImageFormat.YUV_420_888, IMAGE_BUFFER_SIZE);
- mImageReader.setOnImageAvailableListener(mVideoCapture
- , mBackgroundHandler);
- Log.i(TAG, "openCamera");
- CameraManager manager = (CameraManager)
- mContext.getSystemService(Context.CAMERA_SERVICE);
- try {
- if (!mCameraOpenCloseLock.tryAcquire(2500
- , TimeUnit.MILLISECONDS)) {
- throw new RuntimeException("Time out waiting " +
- "to lock camera opening.");
- }
- manager.openCamera(mCameraId, mStateCallback
- , mBackgroundHandler);
- } catch (CameraAccessException e) {
- Log.e(TAG, "Cannot " +
- "access the camera " + e);
- } catch (InterruptedException e) {
- throw new RuntimeException("Interrupted while " +
- "trying to lock camera opening.", e);
- }
- }
复制代码 2、在监听ImageReader.OnImageAvailableListener中读取ImageReader并转换成YUV_420_888的数据。
- @Override
- public void onImageAvailable(ImageReader imageReader) {
- Image image = imageReader.acquireLatestImage();
- if (image != null) {
- if (mPreviewFrameHandler != null) {
- mPreviewFrameHandler.onPreviewFrame(YUV_420_888_data(image), image.getWidth(), image.getHeight());
- }
- image.close();
- }
- }
- private static byte[] YUV_420_888_data(Image image) {
- final int imageWidth = image.getWidth();
- final int imageHeight = image.getHeight();
- final Image.Plane[] planes = image.getPlanes();
- byte[] data = new byte[imageWidth * imageHeight *
- ImageFormat.getBitsPerPixel(ImageFormat.YUV_420_888) / 8];
- int offset = 0;
- for (int plane = 0; plane < planes.length; ++plane) {
- final ByteBuffer buffer = planes[plane].getBuffer();
- final int rowStride = planes[plane].getRowStride();
- // Experimentally, U and V planes have |pixelStride| = 2, which
- // essentially means they are packed.
- final int pixelStride = planes[plane].getPixelStride();
- final int planeWidth = (plane == 0) ? imageWidth : imageWidth / 2;
- final int planeHeight = (plane == 0) ? imageHeight : imageHeight / 2;
- if (pixelStride == 1 && rowStride == planeWidth) {
- // Copy whole plane from buffer into |data| at once.
- buffer.get(data, offset, planeWidth * planeHeight);
- offset += planeWidth * planeHeight;
- } else {
- // Copy pixels one by one respecting pixelStride and rowStride.
- byte[] rowData = new byte[rowStride];
- for (int row = 0; row < planeHeight - 1; ++row) {
- buffer.get(rowData, 0, rowStride);
- for (int col = 0; col < planeWidth; ++col) {
- data[offset++] = rowData[col * pixelStride];
- }
- }
- // Last row is special in some devices and may not contain the full
- // |rowStride| bytes of data.
- // See http://developer.android.com/reference/android/media/Image.Plane.html#getBuffer()
- buffer.get(rowData, 0, Math.min(rowStride, buffer.remaining()));
- for (int col = 0; col < planeWidth; ++col) {
- data[offset++] = rowData[col * pixelStride];
- }
- }
- }
- return data;
- }
复制代码
三、设置OpenGL的使用场景:
GLTextureCPlusVideoPlayerView继承GLSurfcaeView,实现GLSurfcaeView.Renderer接口:
- package com.wangyongyao.glplay.view;
- import android.content.Context;
- import android.opengl.GLSurfaceView;
- import android.util.AttributeSet;
- import android.util.Log;
- import com.wangyongyao.glplay.OpenGLPlayCallJni;
- import com.wangyongyao.glplay.camerahelper.camerahelper.CameraDataHelper;
- import com.wangyongyao.glplay.camerahelper.camerahelper.CameraDataListener;
- import com.wangyongyao.glplay.utils.OpenGLPlayFileUtils;
- import javax.microedition.khronos.egl.EGLConfig;
- import javax.microedition.khronos.opengles.GL10;
- /**
- * author : wangyongyao https://github.com/wangyongyao1989
- * Create Time : 2024/9/3 23:57
- * Descibe : MyyFFmpeg com.example.myyffmpeg.utils
- */
- public class GLTextureCPlusVideoPlayerView extends GLSurfaceView
- implements GLSurfaceView.Renderer, CameraDataListener {
- private static String TAG = GLTextureCPlusVideoPlayerView.class.getSimpleName();
- private OpenGLPlayCallJni mJniCall;
- private Context mContext;
- private int mWidth;
- private int mHeight;
- private CameraDataHelper mCameraHelper;
- public GLTextureCPlusVideoPlayerView(Context context, OpenGLPlayCallJni jniCall) {
- super(context);
- mContext = context;
- mJniCall = jniCall;
- init();
- }
- public GLTextureCPlusVideoPlayerView(Context context, AttributeSet attrs) {
- super(context, attrs);
- mContext = context;
- init();
- }
- private void init() {
- getHolder().addCallback(this);
- setEGLContextClientVersion(3);
- setEGLConfigChooser(8, 8, 8, 8, 16, 0);
- String fragPath = OpenGLPlayFileUtils.getModelFilePath(mContext
- , "texture_video_play_frament.glsl");
- String vertexPath = OpenGLPlayFileUtils.getModelFilePath(mContext
- , "texture_video_play_vert.glsl");
- String picSrc1 = OpenGLPlayFileUtils.getModelFilePath(mContext
- , "wall.jpg");
- mCameraHelper = new CameraDataHelper(getContext(), this);
- mCameraHelper.startCamera();
- mJniCall.glTextureVideoPlayCreate(0, vertexPath, fragPath);
- setRenderer(this);
- setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
- }
- private void stopCameraPreview() {
- mCameraHelper.destroy();
- }
- public void onDrawFrame(GL10 gl) {
- if (mJniCall != null) {
- mJniCall.glTextureVideoPlayRender();
- }
- }
- public void onSurfaceChanged(GL10 gl, int width, int height) {
- Log.e(TAG, "onSurfaceChanged width:" + width + ",height" + height);
- if (mJniCall != null) {
- mJniCall.glTextureVideoPlayInit(null, null, width, height);
- }
- mWidth = width;
- mHeight = height;
- mCameraHelper.initialize(width, height);
- }
- @Override
- public void onSurfaceCreated(GL10 gl10, EGLConfig eglConfig) {
- Log.e(TAG, "onSurfaceCreated:");
- }
- @Override
- public void onPreviewFrame(byte[] yuvData, int width, int height) {
- mJniCall.glTextureVideoPlayDraw(yuvData, width, height, 90);
- requestRender();
- }
- public void destroyRender() {
- mJniCall.glTextureVideoPlayDestroy();
- stopCameraPreview();
- }
- }
复制代码 这里需要留意的是要设置setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY),等待onPreviewFrame回调数据之后在进行Texture的帧渲染。
- /**
- * The renderer only renders
- * when the surface is created, or when {@link #requestRender} is called.
- *
- * @see #getRenderMode()
- * @see #setRenderMode(int)
- * @see #requestRender()
- */
- public final static int RENDERMODE_WHEN_DIRTY = 0;
复制代码
四、JNI层把Java的数据传入C++层:
1、Java层实现:
定义的实行流程的序次方法:glTextureVideoPlayeCreate -> glTextureVideoPlayeInit -> glTextureVideoPlayeCreate -> glTextureVideoPlayeDraw -> glTextureVideoPlayeRender 。
- /*********************** OpenGL Texture显示视频********************/
- public void glTextureVideoPlayCreate(int type, String vertexPath, String fragPath) {
- native_texture_video_play_create(type, vertexPath, fragPath);
- }
- public void glTextureVideoPlayDestroy() {
- native_texture_video_play_destroy();
- }
- public void glTextureVideoPlayInit(Surface surface, AssetManager assetManager
- , int width, int height) {
- native_texture_video_play_init(surface, assetManager, width, height);
- }
- public void glTextureVideoPlayRender() {
- native_texture_video_play_render();
- }
- public void glTextureVideoPlayDraw(byte[] data, int width, int height, int rotation) {
- native_texture_video_play_draw(data, width, height, rotation);
- }
- public void glTextureVideoPlaySetParameters(int params) {
- native_texture_video_play_set_parameters(params);
- }
- public int glTextureVideoPlayGetParameters() {
- return native_texture_video_play_get_parameters();
- }
- private native void native_texture_video_play_create(int type, String vertexPath
- , String fragPath);
- private native void native_texture_video_play_destroy();
- private native void native_texture_video_play_init(Surface surface
- , AssetManager assetManager
- , int width, int height);
- private native void native_texture_video_play_render();
- private native void native_texture_video_play_draw(byte[] data, int width
- , int height, int rotation);
- private native void native_texture_video_play_set_parameters(int params);
- private native int native_texture_video_play_get_parameters();
复制代码 2、JNI层实现:
- /*********************** OpenGL Texture预览Camera视频********************/
- extern "C"
- JNIEXPORT void JNICALL
- cpp_texture_video_play_creat(JNIEnv *env, jobject thiz, jint type,
- jstring vertex,
- jstring frag) {
- const char *vertexPath = env->GetStringUTFChars(vertex, nullptr);
- const char *fragPath = env->GetStringUTFChars(frag, nullptr);
- if (textureVideoRender == nullptr)
- textureVideoRender = new OpenglesTexureVideoRender();
- textureVideoRender->setSharderPath(vertexPath, fragPath);
- env->ReleaseStringUTFChars(vertex, vertexPath);
- env->ReleaseStringUTFChars(frag, fragPath);
- }
- extern "C"
- JNIEXPORT void JNICALL
- cpp_texture_video_play_destroy(JNIEnv *env, jobject thiz) {
- }
- extern "C"
- JNIEXPORT void JNICALL
- cpp_texture_video_play_init(JNIEnv *env, jobject thiz,
- jobject surface,
- jobject assetManager,
- jint width,
- jint height) {
- if (textureVideoRender != nullptr) {
- ANativeWindow *window = surface ? ANativeWindow_fromSurface(env, surface) : nullptr;
- auto *aAssetManager = assetManager ? AAssetManager_fromJava(env, assetManager) : nullptr;
- textureVideoRender->init(window, aAssetManager, (size_t) width, (size_t) height);
- }
- }
- extern "C"
- JNIEXPORT void JNICALL
- cpp_texture_video_play_render(JNIEnv *env, jobject thiz) {
- if (textureVideoRender != nullptr) {
- textureVideoRender->render();
- }
- }
- extern "C"
- JNIEXPORT void JNICALL
- cpp_texture_video_play_draw(JNIEnv *env, jobject obj, jbyteArray data, jint width, jint height,
- jint rotation) {
- jbyte *bufferPtr = env->GetByteArrayElements(data, nullptr);
- jsize arrayLength = env->GetArrayLength(data);
- if (textureVideoRender != nullptr) {
- textureVideoRender->draw((uint8_t *) bufferPtr, (size_t) arrayLength, (size_t) width,
- (size_t) height,
- rotation);
- }
- env->ReleaseByteArrayElements(data, bufferPtr, 0);
- }
- extern "C"
- JNIEXPORT void JNICALL
- cpp_texture_video_play_setParameters(JNIEnv *env, jobject thiz, jint p) {
- if (textureVideoRender != nullptr) {
- textureVideoRender->setParameters((uint32_t) p);
- }
- }
- extern "C"
- JNIEXPORT jint JNICALL
- cpp_texture_video_play_getParameters(JNIEnv *env, jobject thiz) {
- if (textureVideoRender != nullptr) {
- textureVideoRender->getParameters();
- }
- return 0;
- }
- static const JNINativeMethod methods[] = {
-
- /*********************** OpenGL Texture显示视频********************/
- {"native_texture_video_play_create", "(I"
- "Ljava/lang/String;"
- "Ljava/lang/String;)V", (void *) cpp_texture_video_play_creat},
- {"native_texture_video_play_destroy", "()V", (void *) cpp_texture_video_play_destroy},
- {"native_texture_video_play_init", "(Landroid/view/Surface;"
- "Landroid/content/res"
- "/AssetManager;II)V", (void *) cpp_texture_video_play_init},
- {"native_texture_video_play_render", "()V", (void *) cpp_texture_video_play_render},
- {"native_texture_video_play_draw", "([BIII)V", (void *) cpp_texture_video_play_draw},
- {"native_texture_video_play_set_parameters", "(I)V", (void *) cpp_texture_video_play_setParameters},
- {"native_texture_video_play_get_parameters", "()I", (void *) cpp_texture_video_play_getParameters},
- };
- // 定义注册方法
- JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) {
- LOGD("动态注册");
- JNIEnv *env;
- if ((vm)->GetEnv((void **) &env, JNI_VERSION_1_6) != JNI_OK) {
- LOGD("动态注册GetEnv fail");
- return JNI_ERR;
- }
- // 获取类引用
- jclass clazz = env->FindClass(rtmp_class_name);
- // 注册native方法
- jint regist_result = env->RegisterNatives(clazz, methods,
- sizeof(methods) / sizeof(methods[0]));
- if (regist_result) { // 非零true 进if
- LOGE("动态注册 fail regist_result = %d", regist_result);
- } else {
- LOGI("动态注册 success result = %d", regist_result);
- }
- return JNI_VERSION_1_6;
- }
复制代码
五、C++层的OpenGL Texture渲染实现:
这里OpenGL相干的代码基于我的github项目:GitHub - wangyongyao1989/AndroidLearnOpenGL: OpenGL底子及运用
抽取过来进行实现的。
感爱好的可以去阅读我的关于OpenGL的相干的博客:https://blog.csdn.net/wangyongyao1989/category_6943979.html?spm=1001.2014.3001.5482
1、着色器步伐:
着色器步伐是GLSL的文件,把存放文件夹地址传入C++层的OpenGLShader.cpp中。
- texture_video_play_vert.glsl极点着色器:
- #version 320 es
- out vec2 v_texcoord;
- in vec4 position;
- in vec2 texcoord;
- void main() {
- v_texcoord = texcoord;
- gl_Position = position;
- }
复制代码
- texture_video_play_fragment.glsl片断着色器:
- #version 320 es
- precision mediump float;
- in vec2 v_texcoord;
- uniform lowp sampler2D s_textureY;
- uniform lowp sampler2D s_textureU;
- uniform lowp sampler2D s_textureV;
- out vec4 gl_FragColor;
- void main() {
- float y, u, v, r, g, b;
- y = texture(s_textureY, v_texcoord).r;
- u = texture(s_textureU, v_texcoord).r;
- v = texture(s_textureV, v_texcoord).r;
- u = u - 0.5;
- v = v - 0.5;
- r = y + 1.403 * v;
- g = y - 0.344 * u - 0.714 * v;
- b = y + 1.770 * u;
- gl_FragColor = vec4(r, g, b, 1.0);
- }
复制代码
2、OpenGLShader.cpp中着色器步伐编译、毗连、使用。
- //
- // Created by MMM on 2024/8/8.
- //
- #include "OpenGLShader.h"
- GLuint
- OpenGLShader::createProgram() {
- vertexShader = loadShader(GL_VERTEX_SHADER, gVertexShaderCode);
- LOGI("=====gVertexShaderCode :%s", gVertexShaderCode);
- LOGI("======gFragmentShaderCode :%s", gFragmentShaderCode);
- if (!vertexShader) {
- checkGlError("loadShader GL_VERTEX_SHADER");
- return 0;
- }
- fraShader = loadShader(GL_FRAGMENT_SHADER, gFragmentShaderCode);
- if (!fraShader) {
- checkGlError("loadShader GL_FRAGMENT_SHADER");
- return 0;
- }
- shaderId = glCreateProgram(); //创建一个着色程序对象
- if (shaderId) {
- glAttachShader(shaderId, vertexShader); //把着色器附加到了程序对象上
- checkGlError("glAttachShader");
- glAttachShader(shaderId, fraShader);
- checkGlError("glAttachShader");
- glLinkProgram(shaderId); //链接程序对象
- GLint linkStatus = GL_FALSE;
- glGetProgramiv(shaderId, GL_LINK_STATUS, &linkStatus); //检测链接着色器程序是否失败
- if (linkStatus != GL_TRUE) {
- GLint bufLength = 0;
- glGetProgramiv(shaderId, GL_INFO_LOG_LENGTH, &bufLength);
- if (bufLength) {
- char *buf = (char *) malloc(bufLength);
- if (buf) {
- glGetProgramInfoLog(shaderId, bufLength, NULL, buf);
- LOGE("Could not link shaderId:\n%s\n", buf);
- free(buf);
- }
- }
- glDeleteProgram(shaderId); //
- shaderId = 0;
- }
- }
- return shaderId;
- }
- /**
- * 加载着色器
- * @param shaderType
- * @param pSource
- * @return
- */
- GLuint OpenGLShader::loadShader(GLenum shaderType, const char *pSource) {
- GLuint shader = glCreateShader(shaderType); //创建着色器
- if (shader) {
- glShaderSource(shader, 1, &pSource, NULL); //着色器源码附加到着色器对象上
- glCompileShader(shader); //编译着着色器
- GLint compiled = 0;
- glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
- if (!compiled) {
- GLint infoLen = 0;
- glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen);
- if (infoLen) {
- char *buf = (char *) malloc(infoLen);
- if (buf) {
- glGetShaderInfoLog(shader, infoLen, NULL, buf);
- LOGE("Could not compile shader %d:\n%s\n",
- shaderType, buf);
- free(buf);
- }
- glDeleteShader(shader); //删除着色器对象
- shader = 0;
- }
- }
- }
- return shader;
- }
- bool OpenGLShader::getSharderPath(const char *vertexPath, const char *fragmentPath) {
- ifstream vShaderFile;
- ifstream fShaderFile;
- // ensure ifstream objects can throw exceptions:
- vShaderFile.exceptions(ifstream::failbit | ifstream::badbit);
- fShaderFile.exceptions(ifstream::failbit | ifstream::badbit);
- try {
- // open files
- vShaderFile.open(vertexPath);
- fShaderFile.open(fragmentPath);
- stringstream vShaderStream, fShaderStream;
- // read file's buffer contents into streams
- vShaderStream << vShaderFile.rdbuf();
- fShaderStream << fShaderFile.rdbuf();
- // close file handlers
- vShaderFile.close();
- fShaderFile.close();
- // convert stream into string
- vertexCode = vShaderStream.str();
- fragmentCode = fShaderStream.str();
- }
- catch (ifstream::failure &e) {
- LOGE("Could not getSharderPath error :%s", e.what());
- return false;
- }
- gVertexShaderCode = vertexCode.c_str();
- gFragmentShaderCode = fragmentCode.c_str();
- return true;
- }
- void OpenGLShader::printGLString(const char *name, GLenum s) {
- const char *v = (const char *) glGetString(s);
- LOGI("OpenGL %s = %s\n", name, v);
- }
- void OpenGLShader::checkGlError(const char *op) {
- for (GLint error = glGetError(); error; error = glGetError()) {
- LOGI("after %s() glError (0x%x)\n", op, error);
- }
- }
- OpenGLShader::~OpenGLShader() {
- if (vertexShader) {
- glDeleteShader(vertexShader);
- }
- if (fraShader) {
- glDeleteShader(fraShader);
- }
- vertexCode.clear();
- fragmentCode.clear();
- gVertexShaderCode = nullptr;
- gFragmentShaderCode = nullptr;
- }
- OpenGLShader::OpenGLShader() {
- }
复制代码
3、OpenGLTextureVideoRender.cpp进行YUV的Texture渲染:
大抵流程为:createProgram() -> createTextures() -> draw() -> render()。
- createProgram()创建步伐,获取着色器中的输入极点坐标、输入纹理极点坐标及uniform的参数:
- int
- OpenglesTexureVideoRender::createProgram() {
- m_program = lightColorShader->createProgram();
- m_vertexShader = lightColorShader->vertexShader;
- m_pixelShader = lightColorShader->fraShader;
- LOGI("OpenglesTexureVideoRender createProgram m_program:%d", m_program);
- if (!m_program) {
- LOGE("Could not create program.");
- return 0;
- }
- //Get Uniform Variables Location
- m_vertexPos = (GLuint) glGetAttribLocation(m_program, "position");
- m_textureYLoc = glGetUniformLocation(m_program, "s_textureY");
- m_textureULoc = glGetUniformLocation(m_program, "s_textureU");
- m_textureVLoc = glGetUniformLocation(m_program, "s_textureV");
- m_textureLoc = (GLuint) glGetAttribLocation(m_program, "texcoord");
- return m_program;
- }
复制代码
- createTextures()分别创建YUV三个通道的纹理:
- bool OpenglesTexureVideoRender::createTextures() {
- auto widthY = (GLsizei) m_width;
- auto heightY = (GLsizei) m_height;
- glActiveTexture(GL_TEXTURE0);
- glGenTextures(1, &m_textureIdY);
- glBindTexture(GL_TEXTURE_2D, m_textureIdY);
- glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- glTexParameterf(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);
- glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, widthY, heightY, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE,
- nullptr);
- if (!m_textureIdY) {
- // check_gl_error("Create Y texture");
- return false;
- }
- GLsizei widthU = (GLsizei) m_width / 2;
- GLsizei heightU = (GLsizei) m_height / 2;
- glActiveTexture(GL_TEXTURE1);
- glGenTextures(1, &m_textureIdU);
- glBindTexture(GL_TEXTURE_2D, m_textureIdU);
- glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- glTexParameterf(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);
- glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, widthU, heightU, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE,
- nullptr);
- if (!m_textureIdU) {
- // check_gl_error("Create U texture");
- return false;
- }
- GLsizei widthV = (GLsizei) m_width / 2;
- GLsizei heightV = (GLsizei) m_height / 2;
- glActiveTexture(GL_TEXTURE2);
- glGenTextures(1, &m_textureIdV);
- glBindTexture(GL_TEXTURE_2D, m_textureIdV);
- glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- glTexParameterf(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);
- glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, widthV, heightV, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE,
- nullptr);
- if (!m_textureIdV) {
- // check_gl_error("Create V texture");
- return false;
- }
- return true;
- }
复制代码
- void OpenglesTexureVideoRender::draw(uint8_t *buffer, size_t length
- , size_t width, size_t height,
- float rotation) {
- m_length = length;
- m_rotation = rotation;
- video_frame frame{};
- frame.width = width;
- frame.height = height;
- frame.stride_y = width;
- frame.stride_uv = width / 2;
- frame.y = buffer;
- frame.u = buffer + width * height;
- frame.v = buffer + width * height * 5 / 4;
- updateFrame(frame);
- }
- void OpenglesTexureVideoRender::updateFrame(const video_frame &frame) {
- m_sizeY = frame.width * frame.height;
- m_sizeU = frame.width * frame.height / 4;
- m_sizeV = frame.width * frame.height / 4;
- if (m_pDataY == nullptr || m_width != frame.width || m_height != frame.height) {
- m_pDataY = std::make_unique<uint8_t[]>(m_sizeY + m_sizeU + m_sizeV);
- m_pDataU = m_pDataY.get() + m_sizeY;
- m_pDataV = m_pDataU + m_sizeU;
- isProgramChanged = true;
- }
- m_width = frame.width;
- m_height = frame.height;
- if (m_width == frame.stride_y) {
- memcpy(m_pDataY.get(), frame.y, m_sizeY);
- } else {
- uint8_t *pSrcY = frame.y;
- uint8_t *pDstY = m_pDataY.get();
- for (int h = 0; h < m_height; h++) {
- memcpy(pDstY, pSrcY, m_width);
- pSrcY += frame.stride_y;
- pDstY += m_width;
- }
- }
- if (m_width / 2 == frame.stride_uv) {
- memcpy(m_pDataU, frame.u, m_sizeU);
- memcpy(m_pDataV, frame.v, m_sizeV);
- } else {
- uint8_t *pSrcU = frame.u;
- uint8_t *pSrcV = frame.v;
- uint8_t *pDstU = m_pDataU;
- uint8_t *pDstV = m_pDataV;
- for (int h = 0; h < m_height / 2; h++) {
- memcpy(pDstU, pSrcU, m_width / 2);
- memcpy(pDstV, pSrcV, m_width / 2);
- pDstU += m_width / 2;
- pDstV += m_width / 2;
- pSrcU += frame.stride_uv;
- pSrcV += frame.stride_uv;
- }
- }
- isDirty = true;
- }
复制代码
- void OpenglesTexureVideoRender::render() {
- // LOGI("OpenglesTexureVideoRender render");
- glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
- glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
- if (!updateTextures() || !useProgram()) return;
- glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
- }
- bool OpenglesTexureVideoRender::updateTextures() {
- if (!m_textureIdY
- && !m_textureIdU
- && !m_textureIdV
- && !createTextures()) return false;
-
- // LOGI("OpenglesTexureVideoRender updateTextures");
- if (isDirty) {
- glActiveTexture(GL_TEXTURE0);
- glBindTexture(GL_TEXTURE_2D, m_textureIdY);
- glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, (GLsizei) m_width, (GLsizei) m_height, 0,
- GL_LUMINANCE, GL_UNSIGNED_BYTE, m_pDataY.get());
- glActiveTexture(GL_TEXTURE1);
- glBindTexture(GL_TEXTURE_2D, m_textureIdU);
- glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, (GLsizei) m_width / 2, (GLsizei) m_height / 2,
- 0,
- GL_LUMINANCE, GL_UNSIGNED_BYTE, m_pDataU);
- glActiveTexture(GL_TEXTURE2);
- glBindTexture(GL_TEXTURE_2D, m_textureIdV);
- glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, (GLsizei) m_width / 2, (GLsizei) m_height / 2,
- 0,
- GL_LUMINANCE, GL_UNSIGNED_BYTE, m_pDataV);
- isDirty = false;
- return true;
- }
- return false;
- }
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |