OpenGL Texture C++ 预览Camera视频

打印 上一主题 下一主题

主题 984|帖子 984|积分 2952

OpenGL是一个图形API,并不是一个独立的平台。包含了一系列可以操作图形、图像的函数。基于Texture纹理强盛的功能,本篇文章实现Android OpenGL Texture C++ 预览Camera视频流的功能。
       项目github地址:https://github.com/wangyongyao1989/WyFFmpeg
        
一、代码实现步骤及图示预览:


二、Camera数据获取:

        Android Camera可以获取图片数据的视频流信息。
       1、 打开Camera后,获取ImageReader读取视频对应的相片数据。

  1.     /**
  2.      * Opens the camera.
  3.      */
  4.     @SuppressLint({"WrongConstant", "MissingPermission"})
  5.     public void openCamera() {
  6.         if (checkSelfPermission(mContext, Manifest.permission.CAMERA)
  7.                 != PackageManager.PERMISSION_GRANTED) {
  8.             return;
  9.         }
  10.         mImageReader = ImageReader.newInstance(mPreviewSize.getWidth()
  11.                 , mPreviewSize.getHeight()
  12.                 , ImageFormat.YUV_420_888, IMAGE_BUFFER_SIZE);
  13.         mImageReader.setOnImageAvailableListener(mVideoCapture
  14.                 , mBackgroundHandler);
  15.         Log.i(TAG, "openCamera");
  16.         CameraManager manager = (CameraManager)
  17.                 mContext.getSystemService(Context.CAMERA_SERVICE);
  18.         try {
  19.             if (!mCameraOpenCloseLock.tryAcquire(2500
  20.                     , TimeUnit.MILLISECONDS)) {
  21.                 throw new RuntimeException("Time out waiting " +
  22.                         "to lock camera opening.");
  23.             }
  24.             manager.openCamera(mCameraId, mStateCallback
  25.                     , mBackgroundHandler);
  26.         } catch (CameraAccessException e) {
  27.             Log.e(TAG, "Cannot " +
  28.                     "access the camera " + e);
  29.         } catch (InterruptedException e) {
  30.             throw new RuntimeException("Interrupted while " +
  31.                     "trying to lock camera opening.", e);
  32.         }
  33.     }
复制代码
        2、在监听ImageReader.OnImageAvailableListener中读取ImageReader并转换成YUV_420_888的数据。

  1.   @Override
  2.     public void onImageAvailable(ImageReader imageReader) {
  3.         Image image = imageReader.acquireLatestImage();
  4.         if (image != null) {
  5.             if (mPreviewFrameHandler != null) {
  6.                 mPreviewFrameHandler.onPreviewFrame(YUV_420_888_data(image), image.getWidth(), image.getHeight());
  7.             }
  8.             image.close();
  9.         }
  10.     }
  11.     private static byte[] YUV_420_888_data(Image image) {
  12.         final int imageWidth = image.getWidth();
  13.         final int imageHeight = image.getHeight();
  14.         final Image.Plane[] planes = image.getPlanes();
  15.         byte[] data = new byte[imageWidth * imageHeight *
  16.                 ImageFormat.getBitsPerPixel(ImageFormat.YUV_420_888) / 8];
  17.         int offset = 0;
  18.         for (int plane = 0; plane < planes.length; ++plane) {
  19.             final ByteBuffer buffer = planes[plane].getBuffer();
  20.             final int rowStride = planes[plane].getRowStride();
  21.             // Experimentally, U and V planes have |pixelStride| = 2, which
  22.             // essentially means they are packed.
  23.             final int pixelStride = planes[plane].getPixelStride();
  24.             final int planeWidth = (plane == 0) ? imageWidth : imageWidth / 2;
  25.             final int planeHeight = (plane == 0) ? imageHeight : imageHeight / 2;
  26.             if (pixelStride == 1 && rowStride == planeWidth) {
  27.                 // Copy whole plane from buffer into |data| at once.
  28.                 buffer.get(data, offset, planeWidth * planeHeight);
  29.                 offset += planeWidth * planeHeight;
  30.             } else {
  31.                 // Copy pixels one by one respecting pixelStride and rowStride.
  32.                 byte[] rowData = new byte[rowStride];
  33.                 for (int row = 0; row < planeHeight - 1; ++row) {
  34.                     buffer.get(rowData, 0, rowStride);
  35.                     for (int col = 0; col < planeWidth; ++col) {
  36.                         data[offset++] = rowData[col * pixelStride];
  37.                     }
  38.                 }
  39.                 // Last row is special in some devices and may not contain the full
  40.                 // |rowStride| bytes of data.
  41.                 // See http://developer.android.com/reference/android/media/Image.Plane.html#getBuffer()
  42.                 buffer.get(rowData, 0, Math.min(rowStride, buffer.remaining()));
  43.                 for (int col = 0; col < planeWidth; ++col) {
  44.                     data[offset++] = rowData[col * pixelStride];
  45.                 }
  46.             }
  47.         }
  48.         return data;
  49.     }
复制代码

三、设置OpenGL的使用场景:

        GLTextureCPlusVideoPlayerView继承GLSurfcaeView,实现GLSurfcaeView.Renderer接口:
  1. package com.wangyongyao.glplay.view;
  2. import android.content.Context;
  3. import android.opengl.GLSurfaceView;
  4. import android.util.AttributeSet;
  5. import android.util.Log;
  6. import com.wangyongyao.glplay.OpenGLPlayCallJni;
  7. import com.wangyongyao.glplay.camerahelper.camerahelper.CameraDataHelper;
  8. import com.wangyongyao.glplay.camerahelper.camerahelper.CameraDataListener;
  9. import com.wangyongyao.glplay.utils.OpenGLPlayFileUtils;
  10. import javax.microedition.khronos.egl.EGLConfig;
  11. import javax.microedition.khronos.opengles.GL10;
  12. /**
  13. * author : wangyongyao https://github.com/wangyongyao1989
  14. * Create Time : 2024/9/3 23:57
  15. * Descibe : MyyFFmpeg com.example.myyffmpeg.utils
  16. */
  17. public class GLTextureCPlusVideoPlayerView extends GLSurfaceView
  18.         implements GLSurfaceView.Renderer, CameraDataListener {
  19.     private static String TAG = GLTextureCPlusVideoPlayerView.class.getSimpleName();
  20.     private OpenGLPlayCallJni mJniCall;
  21.     private Context mContext;
  22.     private int mWidth;
  23.     private int mHeight;
  24.     private CameraDataHelper mCameraHelper;
  25.     public GLTextureCPlusVideoPlayerView(Context context, OpenGLPlayCallJni jniCall) {
  26.         super(context);
  27.         mContext = context;
  28.         mJniCall = jniCall;
  29.         init();
  30.     }
  31.     public GLTextureCPlusVideoPlayerView(Context context, AttributeSet attrs) {
  32.         super(context, attrs);
  33.         mContext = context;
  34.         init();
  35.     }
  36.     private void init() {
  37.         getHolder().addCallback(this);
  38.         setEGLContextClientVersion(3);
  39.         setEGLConfigChooser(8, 8, 8, 8, 16, 0);
  40.         String fragPath = OpenGLPlayFileUtils.getModelFilePath(mContext
  41.                 , "texture_video_play_frament.glsl");
  42.         String vertexPath = OpenGLPlayFileUtils.getModelFilePath(mContext
  43.                 , "texture_video_play_vert.glsl");
  44.         String picSrc1 = OpenGLPlayFileUtils.getModelFilePath(mContext
  45.                 , "wall.jpg");
  46.         mCameraHelper = new CameraDataHelper(getContext(), this);
  47.         mCameraHelper.startCamera();
  48.         mJniCall.glTextureVideoPlayCreate(0, vertexPath, fragPath);
  49.         setRenderer(this);
  50.         setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
  51.     }
  52.     private void stopCameraPreview() {
  53.         mCameraHelper.destroy();
  54.     }
  55.     public void onDrawFrame(GL10 gl) {
  56.         if (mJniCall != null) {
  57.             mJniCall.glTextureVideoPlayRender();
  58.         }
  59.     }
  60.     public void onSurfaceChanged(GL10 gl, int width, int height) {
  61.         Log.e(TAG, "onSurfaceChanged width:" + width + ",height" + height);
  62.         if (mJniCall != null) {
  63.             mJniCall.glTextureVideoPlayInit(null, null, width, height);
  64.         }
  65.         mWidth = width;
  66.         mHeight = height;
  67.         mCameraHelper.initialize(width, height);
  68.     }
  69.     @Override
  70.     public void onSurfaceCreated(GL10 gl10, EGLConfig eglConfig) {
  71.         Log.e(TAG, "onSurfaceCreated:");
  72.     }
  73.     @Override
  74.     public void onPreviewFrame(byte[] yuvData, int width, int height) {
  75.         mJniCall.glTextureVideoPlayDraw(yuvData, width, height, 90);
  76.         requestRender();
  77.     }
  78.     public void destroyRender() {
  79.         mJniCall.glTextureVideoPlayDestroy();
  80.         stopCameraPreview();
  81.     }
  82. }
复制代码
   这里需要留意的是要设置setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY),等待onPreviewFrame回调数据之后在进行Texture的帧渲染。
  1.     /**
  2.      * The renderer only renders
  3.      * when the surface is created, or when {@link #requestRender} is called.
  4.      *
  5.      * @see #getRenderMode()
  6.      * @see #setRenderMode(int)
  7.      * @see #requestRender()
  8.      */
  9.     public final static int RENDERMODE_WHEN_DIRTY = 0;
复制代码

 四、JNI层把Java的数据传入C++层:

        1、Java层实现:

        定义的实行流程的序次方法:glTextureVideoPlayeCreate -> glTextureVideoPlayeInit -> glTextureVideoPlayeCreate -> glTextureVideoPlayeDraw -> glTextureVideoPlayeRender 。
  1. /*********************** OpenGL Texture显示视频********************/
  2.     public void glTextureVideoPlayCreate(int type, String vertexPath, String fragPath) {
  3.         native_texture_video_play_create(type, vertexPath, fragPath);
  4.     }
  5.     public void glTextureVideoPlayDestroy() {
  6.         native_texture_video_play_destroy();
  7.     }
  8.     public void glTextureVideoPlayInit(Surface surface, AssetManager assetManager
  9.             , int width, int height) {
  10.         native_texture_video_play_init(surface, assetManager, width, height);
  11.     }
  12.     public void glTextureVideoPlayRender() {
  13.         native_texture_video_play_render();
  14.     }
  15.     public void glTextureVideoPlayDraw(byte[] data, int width, int height, int rotation) {
  16.         native_texture_video_play_draw(data, width, height, rotation);
  17.     }
  18.     public void glTextureVideoPlaySetParameters(int params) {
  19.         native_texture_video_play_set_parameters(params);
  20.     }
  21.     public int glTextureVideoPlayGetParameters() {
  22.         return native_texture_video_play_get_parameters();
  23.     }
  24.     private native void native_texture_video_play_create(int type, String vertexPath
  25.             , String fragPath);
  26.     private native void native_texture_video_play_destroy();
  27.     private native void native_texture_video_play_init(Surface surface
  28.             , AssetManager assetManager
  29.             , int width, int height);
  30.     private native void native_texture_video_play_render();
  31.     private native void native_texture_video_play_draw(byte[] data, int width
  32.             , int height, int rotation);
  33.     private native void native_texture_video_play_set_parameters(int params);
  34.     private native int native_texture_video_play_get_parameters();
复制代码
        2、JNI层实现:

  1. /*********************** OpenGL Texture预览Camera视频********************/
  2. extern "C"
  3. JNIEXPORT void JNICALL
  4. cpp_texture_video_play_creat(JNIEnv *env, jobject thiz, jint type,
  5.                              jstring vertex,
  6.                              jstring frag) {
  7.     const char *vertexPath = env->GetStringUTFChars(vertex, nullptr);
  8.     const char *fragPath = env->GetStringUTFChars(frag, nullptr);
  9.     if (textureVideoRender == nullptr)
  10.         textureVideoRender = new OpenglesTexureVideoRender();
  11.     textureVideoRender->setSharderPath(vertexPath, fragPath);
  12.     env->ReleaseStringUTFChars(vertex, vertexPath);
  13.     env->ReleaseStringUTFChars(frag, fragPath);
  14. }
  15. extern "C"
  16. JNIEXPORT void JNICALL
  17. cpp_texture_video_play_destroy(JNIEnv *env, jobject thiz) {
  18. }
  19. extern "C"
  20. JNIEXPORT void JNICALL
  21. cpp_texture_video_play_init(JNIEnv *env, jobject thiz,
  22.                             jobject surface,
  23.                             jobject assetManager,
  24.                             jint width,
  25.                             jint height) {
  26.     if (textureVideoRender != nullptr) {
  27.         ANativeWindow *window = surface ? ANativeWindow_fromSurface(env, surface) : nullptr;
  28.         auto *aAssetManager = assetManager ? AAssetManager_fromJava(env, assetManager) : nullptr;
  29.         textureVideoRender->init(window, aAssetManager, (size_t) width, (size_t) height);
  30.     }
  31. }
  32. extern "C"
  33. JNIEXPORT void JNICALL
  34. cpp_texture_video_play_render(JNIEnv *env, jobject thiz) {
  35.     if (textureVideoRender != nullptr) {
  36.         textureVideoRender->render();
  37.     }
  38. }
  39. extern "C"
  40. JNIEXPORT void JNICALL
  41. cpp_texture_video_play_draw(JNIEnv *env, jobject obj, jbyteArray data, jint width, jint height,
  42.                             jint rotation) {
  43.     jbyte *bufferPtr = env->GetByteArrayElements(data, nullptr);
  44.     jsize arrayLength = env->GetArrayLength(data);
  45.     if (textureVideoRender != nullptr) {
  46.         textureVideoRender->draw((uint8_t *) bufferPtr, (size_t) arrayLength, (size_t) width,
  47.                                  (size_t) height,
  48.                                  rotation);
  49.     }
  50.     env->ReleaseByteArrayElements(data, bufferPtr, 0);
  51. }
  52. extern "C"
  53. JNIEXPORT void JNICALL
  54. cpp_texture_video_play_setParameters(JNIEnv *env, jobject thiz, jint p) {
  55.     if (textureVideoRender != nullptr) {
  56.         textureVideoRender->setParameters((uint32_t) p);
  57.     }
  58. }
  59. extern "C"
  60. JNIEXPORT jint JNICALL
  61. cpp_texture_video_play_getParameters(JNIEnv *env, jobject thiz) {
  62.     if (textureVideoRender != nullptr) {
  63.         textureVideoRender->getParameters();
  64.     }
  65.     return 0;
  66. }
  67. static const JNINativeMethod methods[] = {
  68.         
  69.         /*********************** OpenGL Texture显示视频********************/
  70.         {"native_texture_video_play_create",         "(I"
  71.                                                      "Ljava/lang/String;"
  72.                                                      "Ljava/lang/String;)V",  (void *) cpp_texture_video_play_creat},
  73.         {"native_texture_video_play_destroy",        "()V",                   (void *) cpp_texture_video_play_destroy},
  74.         {"native_texture_video_play_init",           "(Landroid/view/Surface;"
  75.                                                      "Landroid/content/res"
  76.                                                      "/AssetManager;II)V",    (void *) cpp_texture_video_play_init},
  77.         {"native_texture_video_play_render",         "()V",                   (void *) cpp_texture_video_play_render},
  78.         {"native_texture_video_play_draw",           "([BIII)V",              (void *) cpp_texture_video_play_draw},
  79.         {"native_texture_video_play_set_parameters", "(I)V",                  (void *) cpp_texture_video_play_setParameters},
  80.         {"native_texture_video_play_get_parameters", "()I",                   (void *) cpp_texture_video_play_getParameters},
  81. };
  82. // 定义注册方法
  83. JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) {
  84.     LOGD("动态注册");
  85.     JNIEnv *env;
  86.     if ((vm)->GetEnv((void **) &env, JNI_VERSION_1_6) != JNI_OK) {
  87.         LOGD("动态注册GetEnv  fail");
  88.         return JNI_ERR;
  89.     }
  90.     // 获取类引用
  91.     jclass clazz = env->FindClass(rtmp_class_name);
  92.     // 注册native方法
  93.     jint regist_result = env->RegisterNatives(clazz, methods,
  94.                                               sizeof(methods) / sizeof(methods[0]));
  95.     if (regist_result) { // 非零true 进if
  96.         LOGE("动态注册 fail regist_result = %d", regist_result);
  97.     } else {
  98.         LOGI("动态注册 success result = %d", regist_result);
  99.     }
  100.     return JNI_VERSION_1_6;
  101. }
复制代码
       
五、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极点着色器:
  1. #version 320 es
  2. out vec2 v_texcoord;
  3. in vec4 position;
  4. in vec2 texcoord;
  5. void main() {
  6.     v_texcoord = texcoord;
  7.     gl_Position =  position;
  8. }
复制代码


  •  texture_video_play_fragment.glsl片断着色器:       
  1. #version 320 es
  2. precision mediump float;
  3. in vec2 v_texcoord;
  4. uniform lowp sampler2D s_textureY;
  5. uniform lowp sampler2D s_textureU;
  6. uniform lowp sampler2D s_textureV;
  7. out vec4 gl_FragColor;
  8. void main() {
  9.      float y, u, v, r, g, b;
  10.      y = texture(s_textureY, v_texcoord).r;
  11.      u = texture(s_textureU, v_texcoord).r;
  12.      v = texture(s_textureV, v_texcoord).r;
  13.      u = u - 0.5;
  14.      v = v - 0.5;
  15.      r = y + 1.403 * v;
  16.      g = y - 0.344 * u - 0.714 * v;
  17.      b = y + 1.770 * u;
  18.      gl_FragColor = vec4(r, g, b, 1.0);
  19. }
复制代码

2、OpenGLShader.cpp中着色器步伐编译、毗连、使用。

  1. //
  2. // Created by MMM on 2024/8/8.
  3. //
  4. #include "OpenGLShader.h"
  5. GLuint
  6. OpenGLShader::createProgram() {
  7.     vertexShader = loadShader(GL_VERTEX_SHADER, gVertexShaderCode);
  8.     LOGI("=====gVertexShaderCode :%s", gVertexShaderCode);
  9.     LOGI("======gFragmentShaderCode :%s", gFragmentShaderCode);
  10.     if (!vertexShader) {
  11.         checkGlError("loadShader GL_VERTEX_SHADER");
  12.         return 0;
  13.     }
  14.     fraShader = loadShader(GL_FRAGMENT_SHADER, gFragmentShaderCode);
  15.     if (!fraShader) {
  16.         checkGlError("loadShader GL_FRAGMENT_SHADER");
  17.         return 0;
  18.     }
  19.     shaderId = glCreateProgram();      //创建一个着色程序对象
  20.     if (shaderId) {
  21.         glAttachShader(shaderId, vertexShader);        //把着色器附加到了程序对象上
  22.         checkGlError("glAttachShader");
  23.         glAttachShader(shaderId, fraShader);
  24.         checkGlError("glAttachShader");
  25.         glLinkProgram(shaderId);   //链接程序对象
  26.         GLint linkStatus = GL_FALSE;
  27.         glGetProgramiv(shaderId, GL_LINK_STATUS, &linkStatus);  //检测链接着色器程序是否失败
  28.         if (linkStatus != GL_TRUE) {
  29.             GLint bufLength = 0;
  30.             glGetProgramiv(shaderId, GL_INFO_LOG_LENGTH, &bufLength);
  31.             if (bufLength) {
  32.                 char *buf = (char *) malloc(bufLength);
  33.                 if (buf) {
  34.                     glGetProgramInfoLog(shaderId, bufLength, NULL, buf);
  35.                     LOGE("Could not link shaderId:\n%s\n", buf);
  36.                     free(buf);
  37.                 }
  38.             }
  39.             glDeleteProgram(shaderId);     //
  40.             shaderId = 0;
  41.         }
  42.     }
  43.     return shaderId;
  44. }
  45. /**
  46. * 加载着色器
  47. * @param shaderType
  48. * @param pSource
  49. * @return
  50. */
  51. GLuint OpenGLShader::loadShader(GLenum shaderType, const char *pSource) {
  52.     GLuint shader = glCreateShader(shaderType);     //创建着色器
  53.     if (shader) {
  54.         glShaderSource(shader, 1, &pSource, NULL);  //着色器源码附加到着色器对象上
  55.         glCompileShader(shader);                    //编译着着色器
  56.         GLint compiled = 0;
  57.         glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
  58.         if (!compiled) {
  59.             GLint infoLen = 0;
  60.             glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen);
  61.             if (infoLen) {
  62.                 char *buf = (char *) malloc(infoLen);
  63.                 if (buf) {
  64.                     glGetShaderInfoLog(shader, infoLen, NULL, buf);
  65.                     LOGE("Could not compile shader %d:\n%s\n",
  66.                          shaderType, buf);
  67.                     free(buf);
  68.                 }
  69.                 glDeleteShader(shader);     //删除着色器对象
  70.                 shader = 0;
  71.             }
  72.         }
  73.     }
  74.     return shader;
  75. }
  76. bool OpenGLShader::getSharderPath(const char *vertexPath, const char *fragmentPath) {
  77.     ifstream vShaderFile;
  78.     ifstream fShaderFile;
  79.     // ensure ifstream objects can throw exceptions:
  80.     vShaderFile.exceptions(ifstream::failbit | ifstream::badbit);
  81.     fShaderFile.exceptions(ifstream::failbit | ifstream::badbit);
  82.     try {
  83.         // open files
  84.         vShaderFile.open(vertexPath);
  85.         fShaderFile.open(fragmentPath);
  86.         stringstream vShaderStream, fShaderStream;
  87.         // read file's buffer contents into streams
  88.         vShaderStream << vShaderFile.rdbuf();
  89.         fShaderStream << fShaderFile.rdbuf();
  90.         // close file handlers
  91.         vShaderFile.close();
  92.         fShaderFile.close();
  93.         // convert stream into string
  94.         vertexCode = vShaderStream.str();
  95.         fragmentCode = fShaderStream.str();
  96.     }
  97.     catch (ifstream::failure &e) {
  98.         LOGE("Could not getSharderPath error :%s", e.what());
  99.         return false;
  100.     }
  101.     gVertexShaderCode = vertexCode.c_str();
  102.     gFragmentShaderCode = fragmentCode.c_str();
  103.     return true;
  104. }
  105. void OpenGLShader::printGLString(const char *name, GLenum s) {
  106.     const char *v = (const char *) glGetString(s);
  107.     LOGI("OpenGL %s = %s\n", name, v);
  108. }
  109. void OpenGLShader::checkGlError(const char *op) {
  110.     for (GLint error = glGetError(); error; error = glGetError()) {
  111.         LOGI("after %s() glError (0x%x)\n", op, error);
  112.     }
  113. }
  114. OpenGLShader::~OpenGLShader() {
  115.     if (vertexShader) {
  116.         glDeleteShader(vertexShader);
  117.     }
  118.     if (fraShader) {
  119.         glDeleteShader(fraShader);
  120.     }
  121.     vertexCode.clear();
  122.     fragmentCode.clear();
  123.     gVertexShaderCode = nullptr;
  124.     gFragmentShaderCode = nullptr;
  125. }
  126. OpenGLShader::OpenGLShader() {
  127. }
复制代码
  
3、OpenGLTextureVideoRender.cpp进行YUV的Texture渲染:

        大抵流程为:createProgram() -> createTextures() -> draw() -> render()。


  • createProgram()创建步伐,获取着色器中的输入极点坐标、输入纹理极点坐标及uniform的参数:
  1. int
  2. OpenglesTexureVideoRender::createProgram() {
  3.     m_program = lightColorShader->createProgram();
  4.     m_vertexShader = lightColorShader->vertexShader;
  5.     m_pixelShader = lightColorShader->fraShader;
  6.     LOGI("OpenglesTexureVideoRender createProgram m_program:%d", m_program);
  7.     if (!m_program) {
  8.         LOGE("Could not create program.");
  9.         return 0;
  10.     }
  11.     //Get Uniform Variables Location
  12.     m_vertexPos = (GLuint) glGetAttribLocation(m_program, "position");
  13.     m_textureYLoc = glGetUniformLocation(m_program, "s_textureY");
  14.     m_textureULoc = glGetUniformLocation(m_program, "s_textureU");
  15.     m_textureVLoc = glGetUniformLocation(m_program, "s_textureV");
  16.     m_textureLoc = (GLuint) glGetAttribLocation(m_program, "texcoord");
  17.     return m_program;
  18. }
复制代码


  • createTextures()分别创建YUV三个通道的纹理:
  1. bool OpenglesTexureVideoRender::createTextures() {
  2.     auto widthY = (GLsizei) m_width;
  3.     auto heightY = (GLsizei) m_height;
  4.     glActiveTexture(GL_TEXTURE0);
  5.     glGenTextures(1, &m_textureIdY);
  6.     glBindTexture(GL_TEXTURE_2D, m_textureIdY);
  7.     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  8.     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
  9.     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  10.     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  11.     glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, widthY, heightY, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE,
  12.                  nullptr);
  13.     if (!m_textureIdY) {
  14. //        check_gl_error("Create Y texture");
  15.         return false;
  16.     }
  17.     GLsizei widthU = (GLsizei) m_width / 2;
  18.     GLsizei heightU = (GLsizei) m_height / 2;
  19.     glActiveTexture(GL_TEXTURE1);
  20.     glGenTextures(1, &m_textureIdU);
  21.     glBindTexture(GL_TEXTURE_2D, m_textureIdU);
  22.     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  23.     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
  24.     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  25.     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  26.     glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, widthU, heightU, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE,
  27.                  nullptr);
  28.     if (!m_textureIdU) {
  29. //        check_gl_error("Create U texture");
  30.         return false;
  31.     }
  32.     GLsizei widthV = (GLsizei) m_width / 2;
  33.     GLsizei heightV = (GLsizei) m_height / 2;
  34.     glActiveTexture(GL_TEXTURE2);
  35.     glGenTextures(1, &m_textureIdV);
  36.     glBindTexture(GL_TEXTURE_2D, m_textureIdV);
  37.     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  38.     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
  39.     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  40.     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  41.     glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, widthV, heightV, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE,
  42.                  nullptr);
  43.     if (!m_textureIdV) {
  44. //        check_gl_error("Create V texture");
  45.         return false;
  46.     }
  47.     return true;
  48. }
复制代码


  • draw()分离出YUV的每个通道的数据集:
  1. void OpenglesTexureVideoRender::draw(uint8_t *buffer, size_t length
  2.                                     , size_t width, size_t height,
  3.                                      float rotation) {
  4.     m_length = length;
  5.     m_rotation = rotation;
  6.     video_frame frame{};
  7.     frame.width = width;
  8.     frame.height = height;
  9.     frame.stride_y = width;
  10.     frame.stride_uv = width / 2;
  11.     frame.y = buffer;
  12.     frame.u = buffer + width * height;
  13.     frame.v = buffer + width * height * 5 / 4;
  14.     updateFrame(frame);
  15. }
  16. void OpenglesTexureVideoRender::updateFrame(const video_frame &frame) {
  17.     m_sizeY = frame.width * frame.height;
  18.     m_sizeU = frame.width * frame.height / 4;
  19.     m_sizeV = frame.width * frame.height / 4;
  20.     if (m_pDataY == nullptr || m_width != frame.width || m_height != frame.height) {
  21.         m_pDataY = std::make_unique<uint8_t[]>(m_sizeY + m_sizeU + m_sizeV);
  22.         m_pDataU = m_pDataY.get() + m_sizeY;
  23.         m_pDataV = m_pDataU + m_sizeU;
  24.         isProgramChanged = true;
  25.     }
  26.     m_width = frame.width;
  27.     m_height = frame.height;
  28.     if (m_width == frame.stride_y) {
  29.         memcpy(m_pDataY.get(), frame.y, m_sizeY);
  30.     } else {
  31.         uint8_t *pSrcY = frame.y;
  32.         uint8_t *pDstY = m_pDataY.get();
  33.         for (int h = 0; h < m_height; h++) {
  34.             memcpy(pDstY, pSrcY, m_width);
  35.             pSrcY += frame.stride_y;
  36.             pDstY += m_width;
  37.         }
  38.     }
  39.     if (m_width / 2 == frame.stride_uv) {
  40.         memcpy(m_pDataU, frame.u, m_sizeU);
  41.         memcpy(m_pDataV, frame.v, m_sizeV);
  42.     } else {
  43.         uint8_t *pSrcU = frame.u;
  44.         uint8_t *pSrcV = frame.v;
  45.         uint8_t *pDstU = m_pDataU;
  46.         uint8_t *pDstV = m_pDataV;
  47.         for (int h = 0; h < m_height / 2; h++) {
  48.             memcpy(pDstU, pSrcU, m_width / 2);
  49.             memcpy(pDstV, pSrcV, m_width / 2);
  50.             pDstU += m_width / 2;
  51.             pDstV += m_width / 2;
  52.             pSrcU += frame.stride_uv;
  53.             pSrcV += frame.stride_uv;
  54.         }
  55.     }
  56.     isDirty = true;
  57. }
复制代码


  • render()每个渲染时更新YUV三个纹理:
  1. void OpenglesTexureVideoRender::render() {
  2. //    LOGI("OpenglesTexureVideoRender render");
  3.     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  4.     glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
  5.     if (!updateTextures() || !useProgram()) return;
  6.     glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
  7. }
  8. bool OpenglesTexureVideoRender::updateTextures() {
  9.     if (!m_textureIdY
  10.             && !m_textureIdU
  11.             && !m_textureIdV
  12.             && !createTextures()) return false;
  13.                         
  14. //    LOGI("OpenglesTexureVideoRender updateTextures");
  15.     if (isDirty) {
  16.         glActiveTexture(GL_TEXTURE0);
  17.         glBindTexture(GL_TEXTURE_2D, m_textureIdY);
  18.         glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, (GLsizei) m_width, (GLsizei) m_height, 0,
  19.                      GL_LUMINANCE, GL_UNSIGNED_BYTE, m_pDataY.get());
  20.         glActiveTexture(GL_TEXTURE1);
  21.         glBindTexture(GL_TEXTURE_2D, m_textureIdU);
  22.         glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, (GLsizei) m_width / 2, (GLsizei) m_height / 2,
  23.                      0,
  24.                      GL_LUMINANCE, GL_UNSIGNED_BYTE, m_pDataU);
  25.         glActiveTexture(GL_TEXTURE2);
  26.         glBindTexture(GL_TEXTURE_2D, m_textureIdV);
  27.         glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, (GLsizei) m_width / 2, (GLsizei) m_height / 2,
  28.                      0,
  29.                      GL_LUMINANCE, GL_UNSIGNED_BYTE, m_pDataV);
  30.         isDirty = false;
  31.         return true;
  32.     }
  33.     return false;
  34. }
复制代码


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

小秦哥

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表