├── .gitignore ├── app ├── .gitignore ├── CMakeLists.txt ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── cgfay │ │ └── eglnativerender │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── cpp │ │ ├── NativeEglController.cpp │ │ ├── cainfilter │ │ │ ├── GLImageFilter.cpp │ │ │ ├── GLImageFilter.h │ │ │ ├── GLImageInputFilter.cpp │ │ │ ├── GLImageInputFilter.h │ │ │ ├── adjust │ │ │ │ ├── GLBrightnessImageFilter.cpp │ │ │ │ ├── GLBrightnessImageFilter.h │ │ │ │ ├── GLContrastImageFilter.cpp │ │ │ │ ├── GLContrastImageFilter.h │ │ │ │ ├── GLExposureImageFilter.cpp │ │ │ │ ├── GLExposureImageFilter.h │ │ │ │ ├── GLHueImageFilter.cpp │ │ │ │ ├── GLHueImageFilter.h │ │ │ │ ├── GLSaturationImageFilter.cpp │ │ │ │ ├── GLSaturationImageFilter.h │ │ │ │ ├── GLSharpnessImageFilter.cpp │ │ │ │ └── GLSharpnessImageFilter.h │ │ │ └── input │ │ │ │ ├── ABGRImageInputFilter.cpp │ │ │ │ ├── ABGRImageInputFilter.h │ │ │ │ ├── ARGBImageInputfilter.cpp │ │ │ │ ├── ARGBImageInputfilter.h │ │ │ │ ├── BGRImageInputfilter.cpp │ │ │ │ ├── BGRImageInputfilter.h │ │ │ │ ├── I420ImageInputFilter.cpp │ │ │ │ ├── I420ImageInputFilter.h │ │ │ │ ├── NV12ImageInputFilter.cpp │ │ │ │ ├── NV12ImageInputFilter.h │ │ │ │ ├── NV21ImageInputFilter.cpp │ │ │ │ ├── NV21ImageInputFilter.h │ │ │ │ ├── RGBImageInputFilter.cpp │ │ │ │ └── RGBImageInputFilter.h │ │ ├── caingles │ │ │ ├── EglCore.cpp │ │ │ ├── EglCore.h │ │ │ ├── EglSurfaceBase.cpp │ │ │ ├── EglSurfaceBase.h │ │ │ ├── GlShaders.cpp │ │ │ ├── GlShaders.h │ │ │ ├── GlUtils.cpp │ │ │ ├── GlUtils.h │ │ │ ├── OffscreenSurface.cpp │ │ │ ├── OffscreenSurface.h │ │ │ ├── WindowSurface.cpp │ │ │ └── WindowSurface.h │ │ ├── cainrender │ │ │ ├── GLRender.cpp │ │ │ ├── GLRender.h │ │ │ ├── Triangle.cpp │ │ │ └── Triangle.h │ │ └── common │ │ │ ├── Looper.cpp │ │ │ ├── Looper.h │ │ │ ├── MyLooper.cpp │ │ │ ├── MyLooper.h │ │ │ └── native_log.h │ ├── java │ │ └── com │ │ │ └── cgfay │ │ │ └── eglnativerender │ │ │ ├── EGLRender.java │ │ │ ├── Main2Activity.java │ │ │ ├── Main3Activity.java │ │ │ ├── MainActivity.java │ │ │ ├── filter │ │ │ ├── BaseImageFilter.java │ │ │ ├── DisplayFilter.java │ │ │ └── OESInputFilter.java │ │ │ ├── gles │ │ │ ├── EglCore.java │ │ │ ├── EglSurfaceBase.java │ │ │ ├── OffscreenSurface.java │ │ │ └── WindowSurface.java │ │ │ └── utils │ │ │ ├── BitmapUtils.java │ │ │ ├── GlUtil.java │ │ │ ├── Size.java │ │ │ └── TextureRotationUtils.java │ └── res │ │ ├── drawable-v24 │ │ └── ic_launcher_foreground.xml │ │ ├── drawable │ │ └── ic_launcher_background.xml │ │ ├── layout │ │ ├── activity_main.xml │ │ ├── activity_main2.xml │ │ └── activity_main3.xml │ │ ├── mipmap-anydpi-v26 │ │ ├── ic_launcher.xml │ │ └── ic_launcher_round.xml │ │ ├── mipmap-hdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-mdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ └── values │ │ ├── colors.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── com │ └── cgfay │ └── eglnativerender │ └── ExampleUnitTest.java ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | .idea/ 5 | .DS_Store 6 | /build 7 | /captures 8 | .externalNativeBuild 9 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /.externalNativeBuild 2 | /build 3 | -------------------------------------------------------------------------------- /app/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # For more information about using CMake with Android Studio, read the 2 | # documentation: https://d.android.com/studio/projects/add-native-code.html 3 | 4 | # Sets the minimum version of CMake required to build the native library. 5 | 6 | cmake_minimum_required(VERSION 3.4.1) 7 | 8 | # Creates and names a library, sets it as either STATIC 9 | # or SHARED, and provides the relative paths to its source code. 10 | # You can define multiple libraries, and CMake builds them for you. 11 | # Gradle automatically packages shared libraries with your APK. 12 | 13 | add_library( # Sets the name of the library. 14 | nativeEgl 15 | 16 | # Sets the library as a shared library. 17 | SHARED 18 | 19 | # cainfilter 20 | src/main/cpp/cainfilter/GLImageFilter.cpp 21 | src/main/cpp/cainfilter/GLImageInputFilter.cpp 22 | 23 | src/main/cpp/cainfilter/adjust/GLBrightnessImageFilter.cpp 24 | src/main/cpp/cainfilter/adjust/GLContrastImageFilter.cpp 25 | src/main/cpp/cainfilter/adjust/GLExposureImageFilter.cpp 26 | src/main/cpp/cainfilter/adjust/GLHueImageFilter.cpp 27 | src/main/cpp/cainfilter/adjust/GLSaturationImageFilter.cpp 28 | src/main/cpp/cainfilter/adjust/GLSharpnessImageFilter.cpp 29 | 30 | src/main/cpp/cainfilter/input/ABGRImageInputFilter.cpp 31 | src/main/cpp/cainfilter/input/ARGBImageInputFilter.cpp 32 | src/main/cpp/cainfilter/input/BGRImageInputFilter.cpp 33 | src/main/cpp/cainfilter/input/I420ImageInputFilter.cpp 34 | src/main/cpp/cainfilter/input/NV12ImageInputFilter.cpp 35 | src/main/cpp/cainfilter/input/NV21ImageInputFilter.cpp 36 | src/main/cpp/cainfilter/input/RGBImageInputFilter.cpp 37 | 38 | # caingles 39 | src/main/cpp/caingles/EglCore.cpp 40 | src/main/cpp/caingles/EglSurfaceBase.cpp 41 | src/main/cpp/caingles/GlShaders.cpp 42 | src/main/cpp/caingles/GlUtils.cpp 43 | src/main/cpp/caingles/OffscreenSurface.cpp 44 | src/main/cpp/caingles/WindowSurface.cpp 45 | 46 | # cainrender 47 | src/main/cpp/cainrender/GLRender.cpp 48 | src/main/cpp/cainrender/Triangle.cpp 49 | 50 | # common 51 | src/main/cpp/common/Looper.cpp 52 | src/main/cpp/common/MyLooper.cpp 53 | 54 | src/main/cpp/NativeEglController.cpp ) 55 | 56 | # Searches for a specified prebuilt library and stores the path as a 57 | # variable. Because CMake includes system libraries in the search path by 58 | # default, you only need to specify the name of the public NDK library 59 | # you want to add. CMake verifies that the library exists before 60 | # completing its build. 61 | 62 | find_library( # Sets the name of the path variable. 63 | log-lib 64 | 65 | # Specifies the name of the NDK library that 66 | # you want CMake to locate. 67 | log ) 68 | 69 | find_library( EGL-lib EGL ) 70 | find_library( GLESv2-lib GLESv2 ) 71 | 72 | # Specifies libraries CMake should link to your target library. You 73 | # can link multiple libraries, such as libraries you define in this 74 | # build script, prebuilt third-party libraries, or system libraries. 75 | 76 | target_link_libraries( # Specifies the target library. 77 | nativeEgl 78 | 79 | # Links the target library to the log library 80 | # included in the NDK. 81 | -ljnigraphics 82 | -landroid 83 | ${log-lib} 84 | ${EGL-lib} 85 | ${GLESv2-lib} ) -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 26 5 | defaultConfig { 6 | applicationId "com.cgfay.eglnativerender" 7 | minSdkVersion 19 8 | targetSdkVersion 26 9 | versionCode 1 10 | versionName "1.0" 11 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 12 | externalNativeBuild { 13 | cmake { 14 | cppFlags "" 15 | } 16 | } 17 | } 18 | buildTypes { 19 | release { 20 | minifyEnabled false 21 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 22 | } 23 | } 24 | externalNativeBuild { 25 | cmake { 26 | path "CMakeLists.txt" 27 | } 28 | } 29 | } 30 | 31 | dependencies { 32 | implementation fileTree(dir: 'libs', include: ['*.jar']) 33 | implementation 'com.android.support:appcompat-v7:26.1.0' 34 | implementation 'com.android.support.constraint:constraint-layout:1.0.2' 35 | testImplementation 'junit:junit:4.12' 36 | androidTestImplementation 'com.android.support.test:runner:1.0.1' 37 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1' 38 | } 39 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/cgfay/eglnativerender/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.cgfay.eglnativerender; 2 | 3 | import android.content.Context; 4 | import android.support.test.InstrumentationRegistry; 5 | import android.support.test.runner.AndroidJUnit4; 6 | 7 | import org.junit.Test; 8 | import org.junit.runner.RunWith; 9 | 10 | import static org.junit.Assert.*; 11 | 12 | /** 13 | * Instrumented test, which will execute on an Android device. 14 | * 15 | * @see Testing documentation 16 | */ 17 | @RunWith(AndroidJUnit4.class) 18 | public class ExampleInstrumentedTest { 19 | @Test 20 | public void useAppContext() throws Exception { 21 | // Context of the app under test. 22 | Context appContext = InstrumentationRegistry.getTargetContext(); 23 | 24 | assertEquals("com.cgfay.eglnativesample", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /app/src/main/cpp/NativeEglController.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "common/Looper.h" 3 | #include "common/MyLooper.h" 4 | #include 5 | #include 6 | 7 | MyLooper *mLooper = NULL; 8 | ANativeWindow *mWindow = NULL; 9 | 10 | extern "C" 11 | JNIEXPORT void JNICALL 12 | Java_com_cgfay_eglnativerender_EGLRender_nativeInit(JNIEnv *env, jobject instance) { 13 | 14 | // TODO 15 | mLooper = new MyLooper(); 16 | } 17 | 18 | extern "C" 19 | JNIEXPORT void JNICALL 20 | Java_com_cgfay_eglnativerender_EGLRender_nativeRelease(JNIEnv *env, jobject instance) { 21 | if (mLooper != NULL) { 22 | mLooper->quit(); 23 | delete mLooper; 24 | mLooper = NULL; 25 | } 26 | if (mWindow) { 27 | ANativeWindow_release(mWindow); 28 | mWindow = NULL; 29 | } 30 | } 31 | 32 | extern "C" 33 | JNIEXPORT void JNICALL 34 | Java_com_cgfay_eglnativerender_EGLRender_onSurfaceCreated(JNIEnv *env, jobject instance, 35 | jobject surface) { 36 | if (mWindow) { 37 | ANativeWindow_release(mWindow); 38 | mWindow = NULL; 39 | } 40 | mWindow = ANativeWindow_fromSurface(env, surface); 41 | if (mLooper) { 42 | mLooper->postMessage(kMsgSurfaceCreated, mWindow); 43 | } 44 | } 45 | 46 | extern "C" 47 | JNIEXPORT void JNICALL 48 | Java_com_cgfay_eglnativerender_EGLRender_onSurfaceChanged(JNIEnv *env, jobject instance, 49 | jint width, jint height) { 50 | if (mLooper) { 51 | mLooper->postMessage(kMsgSurfaceChanged, width, height); 52 | } 53 | 54 | } 55 | 56 | extern "C" 57 | JNIEXPORT void JNICALL 58 | Java_com_cgfay_eglnativerender_EGLRender_onSurfaceDestroyed(JNIEnv *env, jobject instance) { 59 | 60 | if (mLooper) { 61 | mLooper->postMessage(kMsgSurfaceDestroyed); 62 | } 63 | 64 | } -------------------------------------------------------------------------------- /app/src/main/cpp/cainfilter/GLImageFilter.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by cain on 2018/2/11. 3 | // 4 | 5 | #include "GLImageFilter.h" 6 | 7 | /** 8 | * 构造器 9 | */ 10 | GLImageFilter::GLImageFilter() { 11 | GLImageFilter(getVertexShader(), getFragmentShader()); 12 | } 13 | 14 | /** 15 | * 构造器 16 | * @param vertexShader 17 | * @param fragmentShader 18 | */ 19 | GLImageFilter::GLImageFilter(const char *vertexShader, const char *fragmentShader) { 20 | programHandle = createProgram(vertexShader, fragmentShader); 21 | initHandle(); 22 | initIdentityMatrix(); 23 | initCoordinates(); 24 | textureWidth = 0; 25 | textureHeight = 0; 26 | displayWidth = 0; 27 | displayHeight = 0; 28 | } 29 | 30 | /** 31 | * 析构 32 | */ 33 | GLImageFilter::~GLImageFilter() { 34 | release(); 35 | } 36 | 37 | const char* GLImageFilter::getVertexShader() { 38 | return GlShader_GetShader(VERTEX_DEFAULT); 39 | } 40 | 41 | const char* GLImageFilter::getFragmentShader() { 42 | return GlShader_GetShader(FRAGMENT_ABGR); 43 | } 44 | 45 | /** 46 | * 初始化句柄 47 | */ 48 | void GLImageFilter::initHandle() { 49 | if (programHandle == GL_NONE) { 50 | ALOGE("program is empty!"); 51 | return; 52 | } 53 | positionHandle = glGetAttribLocation(programHandle, "aPosition"); 54 | textureCoordsHandle = glGetAttribLocation(programHandle, "aTextureCoord"); 55 | mvpMatrixHandle = glGetAttribLocation(programHandle, "uMVPMatrix"); 56 | inputTextureHandle = glGetUniformLocation(programHandle, "inputTexture"); 57 | } 58 | 59 | /** 60 | * 绑定值 61 | * @param texture 62 | * @param vertices 63 | * @param textureCoords 64 | */ 65 | void GLImageFilter::bindValue(GLint texture, GLfloat *vertices, GLfloat *textureCoords) { 66 | glVertexAttribPointer(positionHandle, 2, GL_FLOAT, GL_FALSE, 0, vertices); 67 | glEnableVertexAttribArray(positionHandle); 68 | 69 | glVertexAttribPointer(textureCoordsHandle, 2, GL_FLOAT, GL_FALSE, 0, textureCoords); 70 | glEnableVertexAttribArray(textureCoordsHandle); 71 | 72 | glUniform4fv(mvpMatrixHandle, 1, mvpMatrix->m); 73 | 74 | glActiveTexture(GL_TEXTURE0); 75 | glBindTexture(GL_TEXTURE_2D, texture); 76 | glUniform1i(inputTextureHandle, 0); 77 | } 78 | 79 | /** 80 | * 解绑 81 | */ 82 | void GLImageFilter::unbindValue() { 83 | glDisableVertexAttribArray(positionHandle); 84 | glDisableVertexAttribArray(textureCoordsHandle); 85 | glBindTexture(GL_TEXTURE_2D, 0); 86 | } 87 | 88 | /** 89 | * 渲染之前的操作 90 | */ 91 | void GLImageFilter::onDrawBegin() { 92 | 93 | } 94 | 95 | /** 96 | * 渲染之后的操作 97 | */ 98 | void GLImageFilter::onDrawAfter() { 99 | 100 | } 101 | 102 | /** 103 | * 释放资源 104 | */ 105 | void GLImageFilter::release() { 106 | // MTK有些设备的创建得到的program是从0开始的 107 | if (programHandle >= 0) { 108 | glDeleteProgram(programHandle); 109 | programHandle = -1; 110 | } 111 | if (mvpMatrix) { 112 | free(mvpMatrix); 113 | mvpMatrix = NULL; 114 | } 115 | } 116 | 117 | /** 118 | * 初始化坐标缓冲 119 | */ 120 | void GLImageFilter::initCoordinates() { 121 | // 初始化顶点坐标 122 | // 0 bottom left 123 | vertexCoordinates[0] = -1.0f; 124 | vertexCoordinates[1] = -1.0f; 125 | // 1 bottom right 126 | vertexCoordinates[2] = 1.0f; 127 | vertexCoordinates[3] = -1.0f; 128 | // 2 top left 129 | vertexCoordinates[4] = -1.0f; 130 | vertexCoordinates[5] = 1.0f; 131 | // 3 top right 132 | vertexCoordinates[6] = 1.0f; 133 | vertexCoordinates[7] = 1.0f; 134 | 135 | // 初始化纹理坐标 136 | // 0 bottom left 137 | textureCoordinates[0] = 0.0f; 138 | textureCoordinates[1] = 0.0f; 139 | // 1 bottom right 140 | textureCoordinates[2] = 1.0f; 141 | textureCoordinates[3] = 0.0f; 142 | // 2 top left 143 | textureCoordinates[4] = 0.0f; 144 | textureCoordinates[5] = 1.0f; 145 | // 3 top right 146 | textureCoordinates[6] = 1.0f; 147 | textureCoordinates[7] = 1.0f; 148 | } 149 | 150 | 151 | /** 152 | * 输入大小发生变化 153 | * @param width 154 | * @param height 155 | */ 156 | void GLImageFilter::onInputSizeChanged(int width, int height) { 157 | textureWidth = width; 158 | textureHeight = height; 159 | } 160 | 161 | /** 162 | * 界面大小发生变化 163 | * @param width 164 | * @param height 165 | */ 166 | void GLImageFilter::onDisplayChanged(int width, int height) { 167 | displayWidth = width; 168 | displayHeight = height; 169 | } 170 | 171 | /** 172 | * 渲染 173 | * @param texture 174 | * @return 175 | */ 176 | bool GLImageFilter::drawFrame(int texture) { 177 | return drawFrame(texture, vertexCoordinates, textureCoordinates); 178 | } 179 | 180 | /** 181 | * 渲染 182 | * @param texture 183 | * @param vertices 184 | * @param textureCoords 185 | * @return 186 | */ 187 | bool GLImageFilter::drawFrame(int texture, GLfloat *vertices, GLfloat *textureCoords) { 188 | if (texture < 0 || programHandle < 0) { 189 | return false; 190 | } 191 | glUseProgram(programHandle); 192 | bindValue(texture, vertices, textureCoords); 193 | onDrawBegin(); 194 | glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); 195 | onDrawAfter(); 196 | unbindValue(); 197 | glUseProgram(0); 198 | return true; 199 | } 200 | 201 | /** 202 | * 初始化单位矩阵 203 | */ 204 | void GLImageFilter::initIdentityMatrix() { 205 | setIdentityM(mvpMatrix); 206 | } 207 | 208 | /** 209 | * 设置总变换矩阵 210 | * @param matrix 211 | */ 212 | void GLImageFilter::setMVPMatrix(ESMatrix *matrix) { 213 | ESMatrix *temp = mvpMatrix; 214 | mvpMatrix = matrix; 215 | free(temp); 216 | } -------------------------------------------------------------------------------- /app/src/main/cpp/cainfilter/GLImageFilter.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by cain on 2018/2/11. 3 | // 4 | 5 | #ifndef CAINCAMERA_GLIMAGEFILTER_H 6 | #define CAINCAMERA_GLIMAGEFILTER_H 7 | 8 | #include "../caingles/GlUtils.h" 9 | #include "../caingles/GlShaders.h" 10 | #include "../common/native_log.h" 11 | 12 | class GLImageFilter { 13 | public: 14 | GLImageFilter(void); 15 | GLImageFilter(const char *vertexShader, const char *fragmentShader); 16 | virtual ~GLImageFilter(); 17 | // 输入大小发生变化 18 | virtual void onInputSizeChanged(int width, int height); 19 | // 界面大小发生变化 20 | virtual void onDisplayChanged(int width, int height); 21 | // 绘制视频帧 22 | virtual bool drawFrame(int texture); 23 | // 绘制视频帧 24 | virtual bool drawFrame(int texture, GLfloat vertices[], GLfloat textureCoords[]); 25 | // 设置单位矩阵 26 | void initIdentityMatrix(); 27 | // 设置总变换 28 | void setMVPMatrix(ESMatrix *matrix); 29 | 30 | protected: 31 | // 获取VertexShader 32 | virtual const char *getVertexShader(void); 33 | // 获取FragmentShader 34 | virtual const char *getFragmentShader(void); 35 | // 初始化句柄 36 | virtual void initHandle(void); 37 | // 绑定数据 38 | virtual void bindValue(GLint texture, GLfloat vertices[], GLfloat textureCoords[]); 39 | // 解除绑定 40 | virtual void unbindValue(void); 41 | // 实际绘制之前 42 | virtual void onDrawBegin(void); 43 | // 绘制之后 44 | virtual void onDrawAfter(void); 45 | // 释放资源 46 | virtual void release(void); 47 | // 初始化坐标 48 | void initCoordinates(); 49 | 50 | protected: 51 | // 顶点坐标 52 | GLfloat vertexCoordinates[8] = {0}; 53 | // 纹理坐标 54 | GLfloat textureCoordinates[8] = {0}; 55 | // 句柄 56 | GLint programHandle; 57 | GLint mvpMatrixHandle; 58 | GLint positionHandle; 59 | GLint textureCoordsHandle; 60 | GLint inputTextureHandle; 61 | ESMatrix *mvpMatrix; 62 | // 输入宽度 63 | int textureWidth; 64 | // 输入高度 65 | int textureHeight; 66 | // 显示宽度 67 | int displayWidth; 68 | // 显示高度 69 | int displayHeight; 70 | 71 | }; 72 | 73 | 74 | #endif //CAINCAMERA_GLIMAGEFILTER_H 75 | 76 | -------------------------------------------------------------------------------- /app/src/main/cpp/cainfilter/GLImageInputFilter.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by admin on 2018/4/4. 3 | // 4 | 5 | #include "GLImageInputFilter.h" 6 | 7 | GLImageInputFilter::GLImageInputFilter() { 8 | GLImageInputFilter(getVertexShader(), getFragmentShader()); 9 | } 10 | 11 | GLImageInputFilter::GLImageInputFilter(const char *vertexShader, const char *fragmentShader) { 12 | programHandle = createProgram(vertexShader, fragmentShader); 13 | initHandle(); 14 | initIdentityMatrix(); 15 | initCoordinates(); 16 | } 17 | 18 | GLImageInputFilter::~GLImageInputFilter() { 19 | release(); 20 | } 21 | 22 | /** 23 | * 输入大小发生变化 24 | * @param width 25 | * @param height 26 | */ 27 | void GLImageInputFilter::onInputSizeChanged(int width, int height) { 28 | videoWidth = width; 29 | videoHeight = height; 30 | initTexture(width, height); 31 | } 32 | 33 | /** 34 | * 初始化Texture 35 | * @param width 36 | * @param height 37 | */ 38 | void GLImageInputFilter::initTexture(int width, int height) { 39 | glGenTextures(1, &mTextureId[0]); 40 | glActiveTexture(GL_TEXTURE0); 41 | glBindTexture(GL_TEXTURE_2D, mTextureId[0]); 42 | glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER, 43 | GL_LINEAR); 44 | glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER, GL_LINEAR); 45 | glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, width, height, 0, 46 | GL_LUMINANCE, GL_UNSIGNED_BYTE, NULL); 47 | glUniform1i(inputTextureHandle[0], 0); 48 | 49 | glGenTextures(1, &mTextureId[1]); 50 | glActiveTexture(GL_TEXTURE1); 51 | glBindTexture(GL_TEXTURE_2D, mTextureId[1]); 52 | glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER, 53 | GL_LINEAR); 54 | glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER, GL_LINEAR); 55 | glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, width/2, height/2, 0, 56 | GL_LUMINANCE, GL_UNSIGNED_BYTE, NULL); 57 | glUniform1i(inputTextureHandle[1], 1); 58 | 59 | 60 | glGenTextures(1, &mTextureId[2]); 61 | glActiveTexture(GL_TEXTURE2); 62 | glBindTexture(GL_TEXTURE_2D, mTextureId[2]); 63 | glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER, 64 | GL_LINEAR); 65 | glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER, GL_LINEAR); 66 | glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, width/2, height/2, 0, 67 | GL_LUMINANCE, GL_UNSIGNED_BYTE, NULL); 68 | glUniform1i(inputTextureHandle[2], 2); 69 | } 70 | 71 | /** 72 | * 显示发生改变 73 | * @param width 74 | * @param height 75 | */ 76 | void GLImageInputFilter::onDisplayChanged(int width, int height) { 77 | screenWidth = width; 78 | screenHeight = height; 79 | // 重新计算屏幕位置 80 | viewport(); 81 | } 82 | 83 | /** 84 | * 绘制RGB 85 | * @param bufRGB 86 | * @return 87 | */ 88 | bool GLImageInputFilter::drawFrame(void *bufRGB) { 89 | drawFrame(bufRGB, vertexCoordinates, textureCoordinates); 90 | } 91 | 92 | /** 93 | * 绘制RGB 94 | * @param bufRGB 95 | * @param vertices 96 | * @param textureCoords 97 | * @return 98 | */ 99 | bool GLImageInputFilter::drawFrame(void *bufRGB, GLfloat *vertices, GLfloat *textureCoords) { 100 | if (programHandle < 0 || bufRGB == NULL) { 101 | return false; 102 | } 103 | glUseProgram(programHandle); 104 | 105 | glVertexAttribPointer(positionHandle, 2, GL_FLOAT, GL_FALSE, 0, vertices); 106 | glEnableVertexAttribArray(positionHandle); 107 | 108 | glVertexAttribPointer(textureCoordsHandle, 2, GL_FLOAT, GL_FALSE, 0, textureCoords); 109 | glEnableVertexAttribArray(textureCoordsHandle); 110 | 111 | glUniform4fv(mvpMatrixHandle, 1, mvpMatrix->m); 112 | 113 | glActiveTexture(GL_TEXTURE0); 114 | glBindTexture(GL_TEXTURE_2D, mTextureId[0]); 115 | glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, videoWidth, videoHeight, 116 | GL_LUMINANCE, GL_UNSIGNED_BYTE, bufRGB); 117 | 118 | glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); 119 | 120 | glDisableVertexAttribArray(positionHandle); 121 | glDisableVertexAttribArray(textureCoordsHandle); 122 | glBindTexture(GL_TEXTURE_2D, 0); 123 | 124 | glUseProgram(0); 125 | return true; 126 | } 127 | 128 | /** 129 | * 绘制yuv 130 | * @param bufY 131 | * @param bufU 132 | * @param bufV 133 | * @return 134 | */ 135 | bool GLImageInputFilter::drawFrame(void *bufY, void *bufU, void *bufV) { 136 | return drawFrame(bufY, bufU, bufV, vertexCoordinates, textureCoordinates); 137 | } 138 | 139 | /** 140 | * 绘制YUV 141 | * @param bufY 142 | * @param bufU 143 | * @param bufV 144 | * @param vertices 145 | * @param textureCoords 146 | * @return 147 | */ 148 | bool GLImageInputFilter::drawFrame(void *bufY, void *bufU, void *bufV, GLfloat vertices[], 149 | GLfloat textureCoords[]) { 150 | 151 | if (programHandle < 0 || bufY == NULL || bufU == NULL || bufV == NULL) { 152 | return false; 153 | } 154 | glUseProgram(programHandle); 155 | 156 | glVertexAttribPointer(positionHandle, 2, GL_FLOAT, GL_FALSE, 0, vertices); 157 | glEnableVertexAttribArray(positionHandle); 158 | 159 | glVertexAttribPointer(textureCoordsHandle, 2, GL_FLOAT, GL_FALSE, 0, textureCoords); 160 | glEnableVertexAttribArray(textureCoordsHandle); 161 | 162 | glUniform4fv(mvpMatrixHandle, 1, mvpMatrix->m); 163 | 164 | glActiveTexture(GL_TEXTURE0); 165 | glBindTexture(GL_TEXTURE_2D, mTextureId[0]); 166 | glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, videoWidth, videoHeight, 167 | GL_LUMINANCE, GL_UNSIGNED_BYTE, bufY); 168 | 169 | glActiveTexture(GL_TEXTURE1); 170 | glBindTexture(GL_TEXTURE_2D, mTextureId[1]); 171 | glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, videoWidth / 2, videoWidth / 2, 172 | GL_LUMINANCE, GL_UNSIGNED_BYTE, bufU); 173 | 174 | glActiveTexture(GL_TEXTURE2); 175 | glBindTexture(GL_TEXTURE_2D, mTextureId[2]); 176 | glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, videoWidth / 2, videoWidth / 2, 177 | GL_LUMINANCE, GL_UNSIGNED_BYTE, bufV); 178 | 179 | glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); 180 | 181 | glDisableVertexAttribArray(positionHandle); 182 | glDisableVertexAttribArray(textureCoordsHandle); 183 | glBindTexture(GL_TEXTURE_2D, 0); 184 | 185 | glUseProgram(0); 186 | return true; 187 | } 188 | 189 | /** 190 | * 将RGB绘制到FBO 191 | * @param bufRGB 192 | * @return 193 | */ 194 | int GLImageInputFilter::drawFrameBuffer(void *bufRGB) { 195 | drawFrameBuffer(bufRGB, vertexCoordinates, textureCoordinates); 196 | } 197 | 198 | /** 199 | * 将RGB图像数据绘制到FBO 200 | * @param bufRGB 201 | * @param vertices 202 | * @param textureCoords 203 | * @return 204 | */ 205 | int GLImageInputFilter::drawFrameBuffer(void *bufRGB, GLfloat *vertices, GLfloat *textureCoords) { 206 | if (mFrameBuffers[0] == GL_NONE) { 207 | return GL_NONE; 208 | } 209 | glViewport(0, 0, mFrameWidth, mFrameHeight); 210 | glBindFramebuffer(GL_FRAMEBUFFER, mFrameBuffers[0]); 211 | glUseProgram(programHandle); 212 | 213 | glVertexAttribPointer(positionHandle, 2, GL_FLOAT, GL_FALSE, 0, vertices); 214 | glEnableVertexAttribArray(positionHandle); 215 | 216 | glVertexAttribPointer(textureCoordsHandle, 2, GL_FLOAT, GL_FALSE, 0, textureCoords); 217 | glEnableVertexAttribArray(textureCoordsHandle); 218 | 219 | glUniform4fv(mvpMatrixHandle, 1, mvpMatrix->m); 220 | 221 | glActiveTexture(GL_TEXTURE0); 222 | glBindTexture(GL_TEXTURE_2D, mTextureId[0]); 223 | glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, videoWidth, videoHeight, 224 | GL_LUMINANCE, GL_UNSIGNED_BYTE, bufRGB); 225 | 226 | glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); 227 | 228 | glDisableVertexAttribArray(positionHandle); 229 | glDisableVertexAttribArray(textureCoordsHandle); 230 | glBindTexture(GL_TEXTURE_2D, 0); 231 | 232 | glUseProgram(0); 233 | glBindFramebuffer(GL_FRAMEBUFFER, 0); 234 | 235 | return mFrameBufferTextures[0]; 236 | } 237 | 238 | /** 239 | * 将YUV图像数据绘制到FBO 240 | * @param bufY 241 | * @param bufU 242 | * @param bufV 243 | * @return 244 | */ 245 | int GLImageInputFilter::drawFrameBuffer(void *bufY, void *bufU, void *bufV) { 246 | return drawFrameBuffer(bufY, bufU, bufV, vertexCoordinates, textureCoordinates); 247 | } 248 | 249 | /** 250 | * 将YUV图像数据绘制到FBO 251 | * @param bufY 252 | * @param bufU 253 | * @param bufV 254 | * @param vertices 255 | * @param textureCoords 256 | * @return 257 | */ 258 | int GLImageInputFilter::drawFrameBuffer(void *bufY, void *bufU, void *bufV, GLfloat *vertices, 259 | GLfloat *textureCoords) { 260 | if (mFrameBuffers[0] == GL_NONE) { 261 | return GL_NONE; 262 | } 263 | glViewport(0, 0, mFrameWidth, mFrameHeight); 264 | glBindFramebuffer(GL_FRAMEBUFFER, mFrameBuffers[0]); 265 | glUseProgram(programHandle); 266 | 267 | glVertexAttribPointer(positionHandle, 2, GL_FLOAT, GL_FALSE, 0, vertices); 268 | glEnableVertexAttribArray(positionHandle); 269 | 270 | glVertexAttribPointer(textureCoordsHandle, 2, GL_FLOAT, GL_FALSE, 0, textureCoords); 271 | glEnableVertexAttribArray(textureCoordsHandle); 272 | 273 | glUniform4fv(mvpMatrixHandle, 1, mvpMatrix->m); 274 | 275 | glActiveTexture(GL_TEXTURE0); 276 | glBindTexture(GL_TEXTURE_2D, mTextureId[0]); 277 | glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, videoWidth, videoHeight, 278 | GL_LUMINANCE, GL_UNSIGNED_BYTE, bufY); 279 | 280 | glActiveTexture(GL_TEXTURE1); 281 | glBindTexture(GL_TEXTURE_2D, mTextureId[1]); 282 | glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, videoWidth / 2, videoWidth / 2, 283 | GL_LUMINANCE, GL_UNSIGNED_BYTE, bufU); 284 | 285 | glActiveTexture(GL_TEXTURE2); 286 | glBindTexture(GL_TEXTURE_2D, mTextureId[2]); 287 | glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, videoWidth / 2, videoWidth / 2, 288 | GL_LUMINANCE, GL_UNSIGNED_BYTE, bufV); 289 | 290 | glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); 291 | 292 | glDisableVertexAttribArray(positionHandle); 293 | glDisableVertexAttribArray(textureCoordsHandle); 294 | glBindTexture(GL_TEXTURE_2D, 0); 295 | 296 | glUseProgram(0); 297 | glBindFramebuffer(GL_FRAMEBUFFER, 0); 298 | return mFrameBufferTextures[0]; 299 | } 300 | 301 | /** 302 | * 计算viewport 303 | */ 304 | void GLImageInputFilter::viewport() { 305 | int left,top; 306 | if (screenHeight > screenWidth) { 307 | left = 0; 308 | viewWidth = screenWidth; 309 | viewHeight = (int)(videoHeight * 1.0f / videoWidth * viewWidth); 310 | top = (screenHeight - viewHeight) / 2; 311 | } else { 312 | top = 0; 313 | viewHeight = screenHeight; 314 | viewWidth = (int)(videoWidth * 1.0f / videoHeight * viewHeight); 315 | left = (screenWidth - viewWidth) / 2; 316 | } 317 | glViewport(left, top, viewWidth, viewHeight); 318 | } 319 | 320 | /** 321 | * 初始化单位矩阵 322 | */ 323 | void GLImageInputFilter::initIdentityMatrix() { 324 | setIdentityM(mvpMatrix); 325 | } 326 | 327 | /** 328 | * 设置MVP矩阵 329 | * @param matrix 330 | */ 331 | void GLImageInputFilter::setMVPMatrix(ESMatrix *matrix) { 332 | ESMatrix *temp = mvpMatrix; 333 | mvpMatrix = matrix; 334 | free(temp); 335 | } 336 | 337 | /** 338 | * 初始化句柄 339 | */ 340 | void GLImageInputFilter::initHandle(void) { 341 | if (programHandle == GL_NONE) { 342 | ALOGE("program is empty!"); 343 | return; 344 | } 345 | positionHandle = glGetAttribLocation(programHandle, "aPosition"); 346 | textureCoordsHandle = glGetAttribLocation(programHandle, "aTextureCoord"); 347 | mvpMatrixHandle = glGetAttribLocation(programHandle, "uMVPMatrix"); 348 | // YUV渲染 349 | if (getShaderType() == FRAGMENT_I420 || getShaderType() == FRAGMENT_NV12 350 | || getShaderType() == FRAGMENT_NV21) { 351 | inputTextureHandle[0] = glGetUniformLocation(programHandle, "inputTextureY"); 352 | inputTextureHandle[1] = glGetUniformLocation(programHandle, "inputTextureU"); 353 | inputTextureHandle[2] = glGetUniformLocation(programHandle, "inputTextureV"); 354 | } else if (getShaderType() == FRAGMENT_ABGR || getShaderType() == FRAGMENT_ARGB 355 | || getShaderType() == FRAGMENT_BGR || getShaderType() == FRAGMENT_RGB) { 356 | inputTextureHandle[0] = glGetAttribLocation(programHandle, "inputTexture"); 357 | } else { 358 | ALOGE("unsupport shader type!"); 359 | } 360 | } 361 | 362 | // 释放资源 363 | void GLImageInputFilter::release(void) { 364 | if (programHandle >= 0) { 365 | glDeleteProgram(programHandle); 366 | programHandle = -1; 367 | } 368 | if (mvpMatrix) { 369 | free(mvpMatrix); 370 | mvpMatrix = NULL; 371 | } 372 | // 删除Texture 373 | glDeleteTextures(3, mTextureId); 374 | } 375 | 376 | // 初始化坐标 377 | void GLImageInputFilter::initCoordinates() { 378 | // 初始化顶点坐标 379 | // 0 bottom left 380 | vertexCoordinates[0] = -1.0f; 381 | vertexCoordinates[1] = -1.0f; 382 | // 1 bottom right 383 | vertexCoordinates[2] = 1.0f; 384 | vertexCoordinates[3] = -1.0f; 385 | // 2 top left 386 | vertexCoordinates[4] = -1.0f; 387 | vertexCoordinates[5] = 1.0f; 388 | // 3 top right 389 | vertexCoordinates[6] = 1.0f; 390 | vertexCoordinates[7] = 1.0f; 391 | 392 | // 初始化纹理坐标 393 | // 0 bottom left 394 | textureCoordinates[0] = 0.0f; 395 | textureCoordinates[1] = 0.0f; 396 | // 1 bottom right 397 | textureCoordinates[2] = 1.0f; 398 | textureCoordinates[3] = 0.0f; 399 | // 2 top left 400 | textureCoordinates[4] = 0.0f; 401 | textureCoordinates[5] = 1.0f; 402 | // 3 top right 403 | textureCoordinates[6] = 1.0f; 404 | textureCoordinates[7] = 1.0f; 405 | } 406 | 407 | /** 408 | * 初始化FBO 409 | * @param width 410 | * @param height 411 | */ 412 | void GLImageInputFilter::initFrameBuffer(int width, int height) { 413 | if (mFrameBuffers[0] != GL_NONE && (mFrameWidth != width || mFrameHeight != height)) { 414 | destroyFrameBuffer(); 415 | } 416 | if (mFrameBuffers[0] == GL_NONE) { 417 | mFrameWidth = width; 418 | mFrameHeight = height; 419 | createFrameBuffer(mFrameBuffers, mFrameBufferTextures, width, height); 420 | } 421 | } 422 | 423 | /** 424 | * 销毁FBO 425 | */ 426 | void GLImageInputFilter::destroyFrameBuffer() { 427 | if (mFrameBufferTextures[0] != GL_NONE) { 428 | glDeleteTextures(1, mFrameBufferTextures); 429 | mFrameBufferTextures[0] = GL_NONE; 430 | } 431 | if (mFrameBuffers[0] != GL_NONE) { 432 | glDeleteFramebuffers(1, mFrameBuffers); 433 | mFrameBuffers[0] = GL_NONE; 434 | } 435 | mFrameWidth = -1; 436 | mFrameHeight = -1; 437 | } 438 | 439 | const char* GLImageInputFilter::getVertexShader() { 440 | return GlShader_GetShader(VERTEX_REVERSE); 441 | } 442 | 443 | const char* GLImageInputFilter::getFragmentShader() { 444 | return GlShader_GetShader(getShaderType()); 445 | } 446 | 447 | ShaderType GLImageInputFilter::getShaderType() { 448 | return FRAGMENT_RGB; 449 | } -------------------------------------------------------------------------------- /app/src/main/cpp/cainfilter/GLImageInputFilter.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by admin on 2018/4/4. 3 | // 4 | 5 | #ifndef EGLNATIVESAMPLE_GLIMAGEINPUTFILTER_H 6 | #define EGLNATIVESAMPLE_GLIMAGEINPUTFILTER_H 7 | 8 | #include "../caingles/GlUtils.h" 9 | 10 | class GLImageInputFilter { 11 | 12 | public: 13 | GLImageInputFilter(); 14 | GLImageInputFilter(const char *vertexShader, const char *fragmentShader); 15 | virtual ~GLImageInputFilter(); 16 | // 输入大小发生变化 17 | virtual void onInputSizeChanged(int width, int height); 18 | // 界面大小发生变化 19 | virtual void onDisplayChanged(int width, int height); 20 | // 绘制RGB图像数据 21 | virtual bool drawFrame(void *bufRGB); 22 | // 绘制RGB图像数据 23 | virtual bool drawFrame(void *bufRGB, GLfloat vertices[], GLfloat textureCoords[]); 24 | // 绘制YUV图像数据 25 | virtual bool drawFrame(void *bufY, void *bufU, void *bufV); 26 | // 绘制YUV图像数据 27 | virtual bool drawFrame(void *bufY, void *bufU, void *bufV, GLfloat vertices[], GLfloat textureCoords[]); 28 | // 将RGB图像数据绘制到FBO 29 | virtual int drawFrameBuffer(void *bufRGB); 30 | // 将RGB图像数据绘制到FBO 31 | virtual int drawFrameBuffer(void *bufRGB, GLfloat vertices[], GLfloat textureCoords[]); 32 | // 将YUV图像数据绘制到FBO 33 | virtual int drawFrameBuffer(void *bufY, void *bufU, void *bufV); 34 | // 将YUV图像数据绘制到FBO 35 | virtual int drawFrameBuffer(void *bufY, void *bufU, void *bufV, GLfloat vertices[], GLfloat textureCoords[]); 36 | // 设置总变换 37 | void setMVPMatrix(ESMatrix *matrix); 38 | // 初始化FBO 39 | virtual void initFrameBuffer(int width, int height); 40 | // 销毁FBO 41 | virtual void destroyFrameBuffer(); 42 | 43 | protected: 44 | // 加载 vertex shader 45 | virtual const char *getVertexShader(void); 46 | // 加载 fragment shader 47 | virtual const char *getFragmentShader(void); 48 | // 设置单位矩阵 49 | void initIdentityMatrix(); 50 | // 初始化句柄 51 | virtual void initHandle(void); 52 | // 句柄 53 | virtual void viewport(); 54 | // 初始化Texture 55 | virtual void initTexture(int width, int height); 56 | // 释放资源 57 | virtual void release(void); 58 | // 初始化坐标 59 | virtual void initCoordinates(); 60 | // 获取输入类型 61 | virtual ShaderType getShaderType(void); 62 | // 顶点坐标 63 | GLfloat vertexCoordinates[8] = {0}; 64 | // 纹理坐标 65 | GLfloat textureCoordinates[8] = {0}; 66 | // 句柄 67 | GLint programHandle; 68 | GLint mvpMatrixHandle; 69 | GLint positionHandle; 70 | GLint textureCoordsHandle; 71 | GLint inputTextureHandle[3] = {0}; 72 | 73 | // 矩阵对象 74 | ESMatrix *mvpMatrix; 75 | // yuv的Texture 76 | GLuint mTextureId[3]; 77 | 78 | // 输入宽度 79 | int videoWidth; 80 | // 输入高度 81 | int videoHeight; 82 | // Surface的宽度 83 | int screenWidth; 84 | // Surface的高度 85 | int screenHeight; 86 | // 实际显示的宽度 87 | int viewWidth; 88 | // 实际显示的高度 89 | int viewHeight; 90 | 91 | // FBO 92 | GLuint mFrameBuffers[1]; 93 | GLuint mFrameBufferTextures[1]; 94 | int mFrameWidth; 95 | int mFrameHeight; 96 | }; 97 | 98 | 99 | #endif //EGLNATIVESAMPLE_GLIMAGEINPUTFILTER_H 100 | -------------------------------------------------------------------------------- /app/src/main/cpp/cainfilter/adjust/GLBrightnessImageFilter.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by admin on 2018/4/4. 3 | // 4 | 5 | #include "GLBrightnessImageFilter.h" 6 | 7 | static const char fragment_brightness[] = SHADER_STRING( 8 | precision highp float; 9 | 10 | varying highp vec2 textureCoordinate; 11 | uniform lowp sampler2D inputTexture; 12 | uniform lowp float brightness; 13 | 14 | void main() 15 | { 16 | lowp vec4 textureColor = texture2D(inputTexture, textureCoordinate); 17 | gl_FragColor = vec4((textureColor.rgb + vec3(brightness)), textureColor.w); 18 | } 19 | ); 20 | 21 | GLBrightnessImageFilter::GLBrightnessImageFilter() { 22 | GLBrightnessImageFilter(getVertexShader(), getFragmentShader()); 23 | } 24 | 25 | GLBrightnessImageFilter::GLBrightnessImageFilter(const char *vertexShader, 26 | const char *fragmentShader) : GLImageFilter( 27 | vertexShader, fragmentShader) { 28 | } 29 | 30 | const char *GLBrightnessImageFilter::getFragmentShader(void) { 31 | return fragment_brightness; 32 | } 33 | 34 | void GLBrightnessImageFilter::initHandle(void) { 35 | GLImageFilter::initHandle(); 36 | mBrightnessLoc = glGetUniformLocation(programHandle, "brightness"); 37 | setBrightness(1.0); 38 | } 39 | 40 | void GLBrightnessImageFilter::bindValue(GLint texture, GLfloat *vertices, GLfloat *textureCoords) { 41 | GLImageFilter::bindValue(texture, vertices, textureCoords); 42 | glUniform1f(mBrightnessLoc, brightness); 43 | } 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /app/src/main/cpp/cainfilter/adjust/GLBrightnessImageFilter.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by admin on 2018/4/4. 3 | // 4 | 5 | #ifndef EGLNATIVESAMPLE_GLBRIGHTNESSIMAGEFILTER_H 6 | #define EGLNATIVESAMPLE_GLBRIGHTNESSIMAGEFILTER_H 7 | 8 | 9 | #include "../GLImageFilter.h" 10 | 11 | class GLBrightnessImageFilter : public GLImageFilter { 12 | public: 13 | GLBrightnessImageFilter(); 14 | 15 | GLBrightnessImageFilter(const char *vertexShader, const char *fragmentShader); 16 | 17 | inline void setBrightness(float brightness) { 18 | this->brightness = brightness; 19 | } 20 | 21 | protected: 22 | virtual void initHandle(void); 23 | 24 | virtual void bindValue(GLint texture, GLfloat *vertices, GLfloat *textureCoords); 25 | 26 | virtual const char *getFragmentShader(void); 27 | 28 | private: 29 | int mBrightnessLoc; 30 | float brightness; 31 | }; 32 | 33 | 34 | #endif //EGLNATIVESAMPLE_GLBRIGHTNESSIMAGEFILTER_H 35 | -------------------------------------------------------------------------------- /app/src/main/cpp/cainfilter/adjust/GLContrastImageFilter.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by admin on 2018/4/4. 3 | // 4 | 5 | #include "GLContrastImageFilter.h" 6 | 7 | static const char fragment_contrast[] = SHADER_STRING( 8 | precision highp float; 9 | 10 | varying highp vec2 textureCoordinate; 11 | uniform lowp sampler2D inputTexture; 12 | uniform lowp float contrast; 13 | 14 | void main() 15 | { 16 | lowp vec4 textureColor = texture2D(inputTexture, textureCoordinate); 17 | gl_FragColor = vec4(((textureColor.rgb - vec3(0.5)) * contrast + vec3(0.5)), textureColor.w); 18 | } 19 | ); 20 | 21 | GLContrastImageFilter::GLContrastImageFilter() { 22 | GLContrastImageFilter(getVertexShader(), getFragmentShader()); 23 | } 24 | 25 | GLContrastImageFilter::GLContrastImageFilter(const char *vertexShader, const char *fragmentShader) 26 | : GLImageFilter(vertexShader, fragmentShader) { 27 | } 28 | 29 | const char *GLContrastImageFilter::getFragmentShader(void) { 30 | return fragment_contrast; 31 | } 32 | 33 | void GLContrastImageFilter::initHandle(void) { 34 | GLImageFilter::initHandle(); 35 | mContrastLoc = glGetUniformLocation(programHandle, "contrast"); 36 | setContrast(1.0); 37 | } 38 | 39 | void GLContrastImageFilter::bindValue(GLint texture, GLfloat *vertices, GLfloat *textureCoords) { 40 | GLImageFilter::bindValue(texture, vertices, textureCoords); 41 | glUniform1f(mContrastLoc, contrast); 42 | } 43 | -------------------------------------------------------------------------------- /app/src/main/cpp/cainfilter/adjust/GLContrastImageFilter.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by admin on 2018/4/4. 3 | // 4 | 5 | #ifndef EGLNATIVESAMPLE_GLCONTRASTIMAGEFILTER_H 6 | #define EGLNATIVESAMPLE_GLCONTRASTIMAGEFILTER_H 7 | 8 | 9 | #include "../GLImageFilter.h" 10 | 11 | class GLContrastImageFilter : public GLImageFilter { 12 | public: 13 | GLContrastImageFilter(); 14 | 15 | GLContrastImageFilter(const char *vertexShader, const char *fragmentShader); 16 | 17 | inline void setContrast(float contrast) { 18 | this->contrast = contrast; 19 | } 20 | 21 | protected: 22 | virtual void initHandle(void); 23 | 24 | virtual void bindValue(GLint texture, GLfloat *vertices, GLfloat *textureCoords); 25 | 26 | virtual const char *getFragmentShader(void); 27 | 28 | private: 29 | int mContrastLoc; 30 | float contrast; 31 | }; 32 | 33 | 34 | #endif //EGLNATIVESAMPLE_GLCONTRASTIMAGEFILTER_H 35 | -------------------------------------------------------------------------------- /app/src/main/cpp/cainfilter/adjust/GLExposureImageFilter.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by admin on 2018/4/4. 3 | // 4 | 5 | #include "GLExposureImageFilter.h" 6 | 7 | static const char fragment_exposure[] = SHADER_STRING( 8 | precision highp float; 9 | 10 | varying highp vec2 textureCoordinate; 11 | uniform lowp sampler2D inputTexture; 12 | uniform highp float exposure; 13 | 14 | void main() 15 | { 16 | highp vec4 textureColor = texture2D(inputTexture, textureCoordinate); 17 | gl_FragColor = vec4(textureColor.rgb * pow(2.0, exposure), textureColor.w); 18 | } 19 | ); 20 | 21 | GLExposureImageFilter::GLExposureImageFilter() { 22 | GLExposureImageFilter(getVertexShader(), getFragmentShader()); 23 | 24 | } 25 | 26 | GLExposureImageFilter::GLExposureImageFilter(const char *vertexShader, const char *fragmentShader) 27 | : GLImageFilter(vertexShader, fragmentShader) { 28 | 29 | } 30 | 31 | const char *GLExposureImageFilter::getFragmentShader(void) { 32 | return fragment_exposure; 33 | } 34 | 35 | void GLExposureImageFilter::initHandle(void) { 36 | GLImageFilter::initHandle(); 37 | mExposureLoc = glGetUniformLocation(programHandle, "exposure"); 38 | setExposure(0); 39 | 40 | } 41 | 42 | void GLExposureImageFilter::bindValue(GLint texture, GLfloat *vertices, GLfloat *textureCoords) { 43 | GLImageFilter::bindValue(texture, vertices, textureCoords); 44 | } 45 | 46 | 47 | -------------------------------------------------------------------------------- /app/src/main/cpp/cainfilter/adjust/GLExposureImageFilter.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by admin on 2018/4/4. 3 | // 4 | 5 | #ifndef EGLNATIVESAMPLE_GLEXPOSUREIMAGEFILTER_H 6 | #define EGLNATIVESAMPLE_GLEXPOSUREIMAGEFILTER_H 7 | 8 | 9 | #include "../GLImageFilter.h" 10 | 11 | class GLExposureImageFilter : public GLImageFilter { 12 | public: 13 | GLExposureImageFilter(); 14 | 15 | GLExposureImageFilter(const char *vertexShader, const char *fragmentShader); 16 | 17 | inline void setExposure(float exposure) { 18 | this->exposure = exposure; 19 | } 20 | 21 | protected: 22 | virtual void initHandle(void); 23 | 24 | virtual void bindValue(GLint texture, GLfloat *vertices, GLfloat *textureCoords); 25 | 26 | virtual const char *getFragmentShader(void); 27 | 28 | private: 29 | int mExposureLoc; 30 | float exposure; 31 | }; 32 | 33 | 34 | #endif //EGLNATIVESAMPLE_GLEXPOSUREIMAGEFILTER_H 35 | -------------------------------------------------------------------------------- /app/src/main/cpp/cainfilter/adjust/GLHueImageFilter.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by admin on 2018/4/4. 3 | // 4 | 5 | #include "GLHueImageFilter.h" 6 | 7 | static const char fragment_hue[] = SHADER_STRING( 8 | precision highp float; 9 | varying highp vec2 textureCoordinate; 10 | 11 | uniform sampler2D inputTexture; 12 | uniform mediump float hueAdjust; 13 | const highp vec4 kRGBToYPrime = vec4 (0.299, 0.587, 0.114, 0.0); 14 | const highp vec4 kRGBToI = vec4 (0.595716, -0.274453, -0.321263, 0.0); 15 | const highp vec4 kRGBToQ = vec4 (0.211456, -0.522591, 0.31135, 0.0); 16 | 17 | const highp vec4 kYIQToR = vec4 (1.0, 0.9563, 0.6210, 0.0); 18 | const highp vec4 kYIQToG = vec4 (1.0, -0.2721, -0.6474, 0.0); 19 | const highp vec4 kYIQToB = vec4 (1.0, -1.1070, 1.7046, 0.0); 20 | 21 | void main () 22 | { 23 | highp vec4 color = texture2D(inputTexture, textureCoordinate); 24 | 25 | // Convert to YIQ 26 | highp float YPrime = dot (color, kRGBToYPrime); 27 | highp float I = dot (color, kRGBToI); 28 | highp float Q = dot (color, kRGBToQ); 29 | 30 | // Calculate the hue and chroma 31 | highp float hue = atan (Q, I); 32 | highp float chroma = sqrt (I * I + Q * Q); 33 | 34 | // Make the user's adjustments 35 | hue += (-hueAdjust); //why negative rotation? 36 | 37 | // Convert back to YIQ 38 | Q = chroma * sin (hue); 39 | I = chroma * cos (hue); 40 | 41 | // Convert back to RGB 42 | highp vec4 yIQ = vec4 (YPrime, I, Q, 0.0); 43 | color.r = dot (yIQ, kYIQToR); 44 | color.g = dot (yIQ, kYIQToG); 45 | color.b = dot (yIQ, kYIQToB); 46 | 47 | // Save the result 48 | gl_FragColor = color; 49 | } 50 | ); 51 | 52 | 53 | GLHueImageFilter::GLHueImageFilter() { 54 | GLHueImageFilter(getVertexShader(), getFragmentShader()); 55 | } 56 | 57 | GLHueImageFilter::GLHueImageFilter(const char *vertexShader, const char *fragmentShader) 58 | : GLImageFilter(vertexShader, fragmentShader) {} 59 | 60 | void GLHueImageFilter::initHandle(void) { 61 | GLImageFilter::initHandle(); 62 | mHueLoc = glGetUniformLocation(programHandle, "hueAdjust"); 63 | setHue(0); 64 | } 65 | 66 | void GLHueImageFilter::bindValue(GLint texture, GLfloat *vertices, GLfloat *textureCoords) { 67 | GLImageFilter::bindValue(texture, vertices, textureCoords); 68 | float hueAdjust = (float)((hue % 360) * (float) PI / 180.0); 69 | glUniform1f(mHueLoc, hueAdjust); 70 | } 71 | 72 | const char *GLHueImageFilter::getFragmentShader(void) { 73 | return fragment_hue; 74 | } 75 | -------------------------------------------------------------------------------- /app/src/main/cpp/cainfilter/adjust/GLHueImageFilter.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by admin on 2018/4/4. 3 | // 4 | 5 | #ifndef EGLNATIVESAMPLE_GLHUEIMAGEFILTER_H 6 | #define EGLNATIVESAMPLE_GLHUEIMAGEFILTER_H 7 | 8 | 9 | #include "../GLImageFilter.h" 10 | 11 | class GLHueImageFilter : public GLImageFilter { 12 | public: 13 | GLHueImageFilter(); 14 | 15 | GLHueImageFilter(const char *vertexShader, const char *fragmentShader); 16 | 17 | inline void setHue(int hue) { 18 | this->hue = hue; 19 | } 20 | 21 | protected: 22 | virtual void initHandle(void); 23 | 24 | virtual void bindValue(GLint texture, GLfloat *vertices, GLfloat *textureCoords); 25 | 26 | virtual const char *getFragmentShader(void); 27 | 28 | private: 29 | int mHueLoc; 30 | int hue; 31 | }; 32 | 33 | 34 | #endif //EGLNATIVESAMPLE_GLHUEIMAGEFILTER_H 35 | -------------------------------------------------------------------------------- /app/src/main/cpp/cainfilter/adjust/GLSaturationImageFilter.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by admin on 2018/4/4. 3 | // 4 | 5 | #include "GLSaturationImageFilter.h" 6 | 7 | static const char fragment_satutation[] = SHADER_STRING( 8 | precision mediump float; 9 | varying highp vec2 textureCoordinate; 10 | uniform sampler2D inputTexture; 11 | uniform lowp float inputLevel; 12 | const mediump vec3 luminanceWeighting = vec3(0.2125, 0.7154, 0.0721); 13 | void main() { 14 | lowp vec4 textureColor = texture2D(inputTexture, textureCoordinate); 15 | lowp float luminance = dot(textureColor.rgb, luminanceWeighting); 16 | lowp vec3 greyScaleColor = vec3(luminance); 17 | gl_FragColor = vec4(mix(greyScaleColor, textureColor.rgb, inputLevel), textureColor.w); 18 | } 19 | ); 20 | 21 | GLSatutationImageFilter::GLSatutationImageFilter() { 22 | GLSatutationImageFilter(getVertexShader(), getFragmentShader()); 23 | } 24 | 25 | GLSatutationImageFilter::GLSatutationImageFilter(const char *vertexShader, 26 | const char *fragmentShader) : GLImageFilter( 27 | vertexShader, fragmentShader) {} 28 | 29 | const char *GLSatutationImageFilter::getFragmentShader(void) { 30 | return fragment_satutation; 31 | } 32 | 33 | void GLSatutationImageFilter::initHandle(void) { 34 | GLImageFilter::initHandle(); 35 | mSaturationLoc = glGetUniformLocation(programHandle, "inputLevel"); 36 | setSaturation(1.0); 37 | } 38 | 39 | void GLSatutationImageFilter::bindValue(GLint texture, GLfloat *vertices, GLfloat *textureCoords) { 40 | GLImageFilter::bindValue(texture, vertices, textureCoords); 41 | glUniform1f(mSaturationLoc, saturation); 42 | } 43 | -------------------------------------------------------------------------------- /app/src/main/cpp/cainfilter/adjust/GLSaturationImageFilter.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by admin on 2018/4/4. 3 | // 4 | 5 | #ifndef EGLNATIVESAMPLE_GLSATURATIONIMAGEFILTER_H 6 | #define EGLNATIVESAMPLE_GLSATURATIONIMAGEFILTER_H 7 | 8 | 9 | #include "../GLImageFilter.h" 10 | 11 | class GLSatutationImageFilter : public GLImageFilter { 12 | public: 13 | GLSatutationImageFilter(); 14 | 15 | GLSatutationImageFilter(const char *vertexShader, const char *fragmentShader); 16 | 17 | inline void setSaturation(float saturation) { 18 | this->saturation = saturation; 19 | } 20 | 21 | protected: 22 | virtual const char *getFragmentShader(void); 23 | 24 | virtual void bindValue(GLint texture, GLfloat *vertices, GLfloat *textureCoords); 25 | 26 | virtual void initHandle(void); 27 | 28 | private: 29 | int mSaturationLoc; 30 | float saturation; 31 | }; 32 | 33 | 34 | #endif //EGLNATIVESAMPLE_GLSATURATIONIMAGEFILTER_H 35 | -------------------------------------------------------------------------------- /app/src/main/cpp/cainfilter/adjust/GLSharpnessImageFilter.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by admin on 2018/4/4. 3 | // 4 | 5 | #include "GLSharpnessImageFilter.h" 6 | 7 | static const char vertex_sharpness[] = SHADER_STRING( 8 | uniform mat4 uMVPMatrix; 9 | attribute vec4 aPosition; 10 | attribute vec4 aTextureCoord; 11 | 12 | uniform float imageWidthFactor; 13 | uniform float imageHeightFactor; 14 | uniform float sharpness; 15 | 16 | varying vec2 textureCoordinate; 17 | varying vec2 leftTextureCoordinate; 18 | varying vec2 rightTextureCoordinate; 19 | varying vec2 topTextureCoordinate; 20 | varying vec2 bottomTextureCoordinate; 21 | 22 | varying float centerMultiplier; 23 | varying float edgeMultiplier; 24 | void main() 25 | { 26 | gl_Position = aPosition; 27 | 28 | mediump vec2 widthStep = vec2(imageWidthFactor, 0.0); 29 | mediump vec2 heightStep = vec2(0.0, imageHeightFactor); 30 | 31 | textureCoordinate = aTextureCoord.xy; 32 | leftTextureCoordinate = aTextureCoord.xy - widthStep; 33 | rightTextureCoordinate = aTextureCoord.xy + widthStep; 34 | topTextureCoordinate = aTextureCoord.xy + heightStep; 35 | bottomTextureCoordinate = aTextureCoord.xy - heightStep; 36 | 37 | centerMultiplier = 1.0 + 4.0 * sharpness; 38 | edgeMultiplier = sharpness; 39 | } 40 | ); 41 | 42 | static const char fragment_sharpness[] = SHADER_STRING( 43 | precision highp float; 44 | 45 | varying highp vec2 textureCoordinate; 46 | varying highp vec2 leftTextureCoordinate; 47 | varying highp vec2 rightTextureCoordinate; 48 | varying highp vec2 topTextureCoordinate; 49 | varying highp vec2 bottomTextureCoordinate; 50 | 51 | varying highp float centerMultiplier; 52 | varying highp float edgeMultiplier; 53 | 54 | uniform sampler2D inputImageTexture; 55 | 56 | void main() 57 | { 58 | mediump vec3 textureColor = texture2D(inputImageTexture, textureCoordinate).rgb; 59 | mediump vec3 leftTextureColor = texture2D(inputImageTexture, leftTextureCoordinate).rgb; 60 | mediump vec3 rightTextureColor = texture2D(inputImageTexture, rightTextureCoordinate).rgb; 61 | mediump vec3 topTextureColor = texture2D(inputImageTexture, topTextureCoordinate).rgb; 62 | mediump vec3 bottomTextureColor = texture2D(inputImageTexture, bottomTextureCoordinate).rgb; 63 | 64 | gl_FragColor = vec4((textureColor * centerMultiplier 65 | - (leftTextureColor * edgeMultiplier 66 | + rightTextureColor * edgeMultiplier 67 | + topTextureColor * edgeMultiplier 68 | + bottomTextureColor * edgeMultiplier)), 69 | texture2D(inputImageTexture, bottomTextureCoordinate).w); 70 | } 71 | ); 72 | 73 | GLSharpnessImageFilter::GLSharpnessImageFilter() { 74 | GLSharpnessImageFilter(getVertexShader(), getFragmentShader()); 75 | } 76 | 77 | GLSharpnessImageFilter::GLSharpnessImageFilter(const char *vertexShader, const char *fragmentShader) 78 | : GLImageFilter(vertexShader, fragmentShader) { 79 | widthFactor = 0.0; 80 | heightFactor = 0.0; 81 | } 82 | 83 | const char *GLSharpnessImageFilter::getVertexShader(void) { 84 | return vertex_sharpness; 85 | } 86 | const char *GLSharpnessImageFilter::getFragmentShader(void) { 87 | return fragment_sharpness; 88 | } 89 | 90 | void GLSharpnessImageFilter::initHandle(void) { 91 | GLImageFilter::initHandle(); 92 | mImageWidthLoc = glGetUniformLocation(programHandle, "imageWidthFactor"); 93 | mImageHeightLoc = glGetUniformLocation(programHandle, "imageHeightFactor"); 94 | mSharpnessLoc = glGetUniformLocation(programHandle, "sharpness"); 95 | setSharpness(0.0); 96 | } 97 | 98 | void GLSharpnessImageFilter::bindValue(GLint texture, GLfloat *vertices, GLfloat *textureCoords) { 99 | GLImageFilter::bindValue(texture, vertices, textureCoords); 100 | glUniform1f(mImageWidthLoc, widthFactor); 101 | glUniform1f(mImageHeightLoc, heightFactor); 102 | glUniform1f(mSharpnessLoc, sharpness); 103 | } 104 | 105 | void GLSharpnessImageFilter::onInputSizeChanged(int width, int height) { 106 | GLImageFilter::onInputSizeChanged(width, height); 107 | widthFactor = 1.0f / width; 108 | heightFactor = 1.0f / height; 109 | } 110 | 111 | 112 | -------------------------------------------------------------------------------- /app/src/main/cpp/cainfilter/adjust/GLSharpnessImageFilter.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by admin on 2018/4/4. 3 | // 4 | 5 | #ifndef EGLNATIVESAMPLE_GLSHARPNESSIMAGEFILTER_H 6 | #define EGLNATIVESAMPLE_GLSHARPNESSIMAGEFILTER_H 7 | 8 | #include "../GLImageFilter.h" 9 | 10 | class GLSharpnessImageFilter : public GLImageFilter { 11 | public: 12 | GLSharpnessImageFilter(); 13 | 14 | GLSharpnessImageFilter(const char *vertexShader, const char *fragmentShader); 15 | 16 | inline void setSharpness(float sharpness) { 17 | this->sharpness = sharpness; 18 | } 19 | 20 | protected: 21 | virtual void bindValue(GLint texture, GLfloat *vertices, GLfloat *textureCoords); 22 | 23 | public: 24 | virtual void onInputSizeChanged(int width, int height); 25 | 26 | protected: 27 | virtual void initHandle(void); 28 | 29 | virtual const char *getVertexShader(void); 30 | 31 | virtual const char *getFragmentShader(void); 32 | 33 | private: 34 | int mSharpnessLoc; 35 | int mImageWidthLoc; 36 | int mImageHeightLoc; 37 | float sharpness; 38 | float widthFactor; 39 | float heightFactor; 40 | 41 | }; 42 | 43 | 44 | #endif //EGLNATIVESAMPLE_GLSHARPNESSIMAGEFILTER_H 45 | -------------------------------------------------------------------------------- /app/src/main/cpp/cainfilter/input/ABGRImageInputFilter.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by admin on 2018/4/4. 3 | // 4 | 5 | #include "ABGRImageInputFilter.h" 6 | 7 | ABGRImageInputFilter::ABGRImageInputFilter() { 8 | ABGRImageInputFilter(getVertexShader(), getFragmentShader()); 9 | } 10 | 11 | ABGRImageInputFilter::ABGRImageInputFilter(const char *vertexShader, const char *fragmentShader) 12 | : GLImageInputFilter(vertexShader, fragmentShader) {} 13 | 14 | ShaderType ABGRImageInputFilter::getShaderType(void) { 15 | return FRAGMENT_ABGR; 16 | } 17 | 18 | bool ABGRImageInputFilter::drawFrame(void *bufY, void *bufU, void *bufV) { 19 | return GLImageInputFilter::drawFrame(bufY, bufU, bufV); 20 | } 21 | 22 | bool ABGRImageInputFilter::drawFrame(void *bufY, void *bufU, void *bufV, GLfloat *vertices, 23 | GLfloat *textureCoords) { 24 | return GLImageInputFilter::drawFrame(bufY, bufU, bufV, vertices, textureCoords); 25 | } 26 | 27 | 28 | int ABGRImageInputFilter::drawFrameBuffer(void *bufY, void *bufU, void *bufV, GLfloat *vertices, 29 | GLfloat *textureCoords) { 30 | return GLImageInputFilter::drawFrameBuffer(bufY, bufU, bufV, vertices, textureCoords); 31 | } 32 | 33 | int ABGRImageInputFilter::drawFrameBuffer(void *bufY, void *bufU, void *bufV) { 34 | return GLImageInputFilter::drawFrameBuffer(bufY, bufU, bufV); 35 | } 36 | -------------------------------------------------------------------------------- /app/src/main/cpp/cainfilter/input/ABGRImageInputFilter.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by admin on 2018/4/4. 3 | // 4 | 5 | #ifndef EGLNATIVESAMPLE_ABGRIMAGEINPUTFILTER_H 6 | #define EGLNATIVESAMPLE_ABGRIMAGEINPUTFILTER_H 7 | 8 | 9 | #include "../GLImageInputFilter.h" 10 | 11 | class ABGRImageInputFilter : public GLImageInputFilter { 12 | public: 13 | ABGRImageInputFilter(); 14 | 15 | ABGRImageInputFilter(const char *vertexShader, const char *fragmentShader); 16 | 17 | protected: 18 | virtual ShaderType getShaderType(void); 19 | 20 | private: 21 | virtual bool drawFrame(void *bufY, void *bufU, void *bufV); 22 | 23 | virtual bool drawFrame(void *bufY, void *bufU, void *bufV, GLfloat *vertices, GLfloat *textureCoords); 24 | 25 | virtual int drawFrameBuffer(void *bufY, void *bufU, void *bufV); 26 | 27 | virtual int drawFrameBuffer(void *bufY, void *bufU, void *bufV, GLfloat *vertices, GLfloat *textureCoords); 28 | }; 29 | 30 | 31 | #endif //EGLNATIVESAMPLE_ABGRIMAGEINPUTFILTER_H 32 | -------------------------------------------------------------------------------- /app/src/main/cpp/cainfilter/input/ARGBImageInputfilter.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by admin on 2018/4/4. 3 | // 4 | 5 | #include "ARGBImageInputfilter.h" 6 | 7 | ARGBImageInputfilter::ARGBImageInputfilter() { 8 | ARGBImageInputfilter(getVertexShader(), getFragmentShader()); 9 | } 10 | 11 | ARGBImageInputfilter::ARGBImageInputfilter(const char *vertexShader, const char *fragmentShader) 12 | : GLImageInputFilter(vertexShader, fragmentShader) { 13 | } 14 | 15 | ShaderType ARGBImageInputfilter::getShaderType(void) { 16 | return FRAGMENT_ARGB; 17 | } 18 | 19 | bool ARGBImageInputfilter::drawFrame(void *bufY, void *bufU, void *bufV) { 20 | return GLImageInputFilter::drawFrame(bufY, bufU, bufV); 21 | } 22 | 23 | bool ARGBImageInputfilter::drawFrame(void *bufY, void *bufU, void *bufV, GLfloat *vertices, 24 | GLfloat *textureCoords) { 25 | return GLImageInputFilter::drawFrame(bufY, bufU, bufV, vertices, textureCoords); 26 | } 27 | 28 | 29 | int ARGBImageInputfilter::drawFrameBuffer(void *bufY, void *bufU, void *bufV, GLfloat *vertices, 30 | GLfloat *textureCoords) { 31 | return GLImageInputFilter::drawFrameBuffer(bufY, bufU, bufV, vertices, textureCoords); 32 | } 33 | 34 | int ARGBImageInputfilter::drawFrameBuffer(void *bufY, void *bufU, void *bufV) { 35 | return GLImageInputFilter::drawFrameBuffer(bufY, bufU, bufV); 36 | } 37 | 38 | -------------------------------------------------------------------------------- /app/src/main/cpp/cainfilter/input/ARGBImageInputfilter.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by admin on 2018/4/4. 3 | // 4 | 5 | #ifndef EGLNATIVESAMPLE_ARGBIMAGEINPUTFILTER_H 6 | #define EGLNATIVESAMPLE_ARGBIMAGEINPUTFILTER_H 7 | 8 | 9 | #include "../GLImageInputFilter.h" 10 | 11 | class ARGBImageInputfilter : public GLImageInputFilter { 12 | 13 | public: 14 | ARGBImageInputfilter(); 15 | 16 | ARGBImageInputfilter(const char *vertexShader, const char *fragmentShader); 17 | 18 | protected: 19 | virtual ShaderType getShaderType(void); 20 | 21 | private: 22 | virtual bool drawFrame(void *bufY, void *bufU, void *bufV); 23 | 24 | virtual bool drawFrame(void *bufY, void *bufU, void *bufV, GLfloat *vertices, GLfloat *textureCoords); 25 | 26 | virtual int drawFrameBuffer(void *bufY, void *bufU, void *bufV); 27 | 28 | virtual int drawFrameBuffer(void *bufY, void *bufU, void *bufV, GLfloat *vertices, GLfloat *textureCoords); 29 | }; 30 | 31 | 32 | #endif //EGLNATIVESAMPLE_ARGBIMAGEINPUTFILTER_H 33 | -------------------------------------------------------------------------------- /app/src/main/cpp/cainfilter/input/BGRImageInputfilter.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by admin on 2018/4/4. 3 | // 4 | 5 | #include "BGRImageInputfilter.h" 6 | 7 | BGRImageInputfilter::BGRImageInputfilter() { 8 | BGRImageInputfilter(getVertexShader(), getFragmentShader()); 9 | } 10 | 11 | BGRImageInputfilter::BGRImageInputfilter(const char *vertexShader, const char *fragmentShader) 12 | : GLImageInputFilter(vertexShader, fragmentShader) { 13 | } 14 | 15 | ShaderType BGRImageInputfilter::getShaderType(void) { 16 | return FRAGMENT_BGR; 17 | } 18 | 19 | bool BGRImageInputfilter::drawFrame(void *bufY, void *bufU, void *bufV) { 20 | return GLImageInputFilter::drawFrame(bufY, bufU, bufV); 21 | } 22 | 23 | bool BGRImageInputfilter::drawFrame(void *bufY, void *bufU, void *bufV, GLfloat *vertices, 24 | GLfloat *textureCoords) { 25 | return GLImageInputFilter::drawFrame(bufY, bufU, bufV, vertices, textureCoords); 26 | } 27 | 28 | int BGRImageInputfilter::drawFrameBuffer(void *bufY, void *bufU, void *bufV) { 29 | return GLImageInputFilter::drawFrameBuffer(bufY, bufU, bufV); 30 | } 31 | 32 | int BGRImageInputfilter::drawFrameBuffer(void *bufY, void *bufU, void *bufV, GLfloat *vertices, 33 | GLfloat *textureCoords) { 34 | return GLImageInputFilter::drawFrameBuffer(bufY, bufU, bufV, vertices, textureCoords); 35 | } 36 | -------------------------------------------------------------------------------- /app/src/main/cpp/cainfilter/input/BGRImageInputfilter.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by admin on 2018/4/4. 3 | // 4 | 5 | #ifndef EGLNATIVESAMPLE_BGRIMAGEINPUTFILTER_H 6 | #define EGLNATIVESAMPLE_BGRIMAGEINPUTFILTER_H 7 | 8 | 9 | #include "../GLImageInputFilter.h" 10 | 11 | class BGRImageInputfilter : public GLImageInputFilter { 12 | 13 | public: 14 | BGRImageInputfilter(); 15 | 16 | BGRImageInputfilter(const char *vertexShader, const char *fragmentShader); 17 | 18 | protected: 19 | virtual ShaderType getShaderType(void); 20 | 21 | private: 22 | virtual bool drawFrame(void *bufY, void *bufU, void *bufV); 23 | 24 | virtual bool drawFrame(void *bufY, void *bufU, void *bufV, GLfloat *vertices, GLfloat *textureCoords); 25 | 26 | virtual int drawFrameBuffer(void *bufY, void *bufU, void *bufV); 27 | 28 | virtual int drawFrameBuffer(void *bufY, void *bufU, void *bufV, GLfloat *vertices, GLfloat *textureCoords); 29 | }; 30 | 31 | 32 | #endif //EGLNATIVESAMPLE_BGRIMAGEINPUTFILTER_H 33 | -------------------------------------------------------------------------------- /app/src/main/cpp/cainfilter/input/I420ImageInputFilter.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by admin on 2018/4/4. 3 | // 4 | 5 | #include "I420ImageInputFilter.h" 6 | 7 | I420ImageInputFilter::I420ImageInputFilter() { 8 | I420ImageInputFilter(getVertexShader(), getFragmentShader()); 9 | } 10 | 11 | I420ImageInputFilter::I420ImageInputFilter(const char *vertexShader, const char *fragmentShader) 12 | : GLImageInputFilter(vertexShader, fragmentShader) { 13 | } 14 | 15 | ShaderType I420ImageInputFilter::getShaderType(void) { 16 | return FRAGMENT_I420; 17 | } 18 | 19 | bool I420ImageInputFilter::drawFrame(void *bufRGB) { 20 | return GLImageInputFilter::drawFrame(bufRGB); 21 | } 22 | 23 | bool I420ImageInputFilter::drawFrame(void *bufRGB, GLfloat *vertices, GLfloat *textureCoords) { 24 | return GLImageInputFilter::drawFrame(bufRGB, vertices, textureCoords); 25 | } 26 | 27 | int I420ImageInputFilter::drawFrameBuffer(void *bufRGB) { 28 | return GLImageInputFilter::drawFrameBuffer(bufRGB); 29 | } 30 | 31 | int 32 | I420ImageInputFilter::drawFrameBuffer(void *bufRGB, GLfloat *vertices, GLfloat *textureCoords) { 33 | return GLImageInputFilter::drawFrameBuffer(bufRGB, vertices, textureCoords); 34 | } 35 | 36 | 37 | -------------------------------------------------------------------------------- /app/src/main/cpp/cainfilter/input/I420ImageInputFilter.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by admin on 2018/4/4. 3 | // 4 | 5 | #ifndef EGLNATIVESAMPLE_YUV420PIMAGEINPUTFILTER_H 6 | #define EGLNATIVESAMPLE_YUV420PIMAGEINPUTFILTER_H 7 | 8 | 9 | #include "../GLImageInputFilter.h" 10 | 11 | class I420ImageInputFilter : public GLImageInputFilter { 12 | protected: 13 | public: 14 | I420ImageInputFilter(); 15 | 16 | I420ImageInputFilter(const char *vertexShader, const char *fragmentShader); 17 | 18 | protected: 19 | virtual ShaderType getShaderType(void); 20 | 21 | private: 22 | virtual bool drawFrame(void *bufRGB); 23 | 24 | virtual bool drawFrame(void *bufRGB, GLfloat *vertices, GLfloat *textureCoords); 25 | 26 | virtual int drawFrameBuffer(void *bufRGB); 27 | 28 | virtual int drawFrameBuffer(void *bufRGB, GLfloat *vertices, GLfloat *textureCoords); 29 | }; 30 | 31 | 32 | #endif //EGLNATIVESAMPLE_YUV420PIMAGEINPUTFILTER_H 33 | -------------------------------------------------------------------------------- /app/src/main/cpp/cainfilter/input/NV12ImageInputFilter.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by admin on 2018/4/4. 3 | // 4 | 5 | #include "NV12ImageInputFilter.h" 6 | 7 | NV12ImageInputFilter::NV12ImageInputFilter() {} 8 | 9 | NV12ImageInputFilter::NV12ImageInputFilter(const char *vertexShader, const char *fragmentShader) 10 | : GLImageInputFilter(vertexShader, fragmentShader) {} 11 | 12 | ShaderType NV12ImageInputFilter::getShaderType(void) { 13 | return FRAGMENT_NV12; 14 | } 15 | 16 | bool NV12ImageInputFilter::drawFrame(void *bufRGB) { 17 | return GLImageInputFilter::drawFrame(bufRGB); 18 | } 19 | 20 | bool NV12ImageInputFilter::drawFrame(void *bufRGB, GLfloat *vertices, GLfloat *textureCoords) { 21 | return GLImageInputFilter::drawFrame(bufRGB, vertices, textureCoords); 22 | } 23 | 24 | int NV12ImageInputFilter::drawFrameBuffer(void *bufRGB) { 25 | return GLImageInputFilter::drawFrameBuffer(bufRGB); 26 | } 27 | 28 | int NV12ImageInputFilter::drawFrameBuffer(void *bufRGB, GLfloat *vertices, GLfloat *textureCoords) { 29 | return GLImageInputFilter::drawFrameBuffer(bufRGB, vertices, textureCoords); 30 | } 31 | -------------------------------------------------------------------------------- /app/src/main/cpp/cainfilter/input/NV12ImageInputFilter.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by admin on 2018/4/4. 3 | // 4 | 5 | #ifndef EGLNATIVESAMPLE_NV12IMAGEINPUTFILTER_H 6 | #define EGLNATIVESAMPLE_NV12IMAGEINPUTFILTER_H 7 | 8 | 9 | #include "../GLImageInputFilter.h" 10 | 11 | class NV12ImageInputFilter : public GLImageInputFilter { 12 | public: 13 | NV12ImageInputFilter(); 14 | 15 | NV12ImageInputFilter(const char *vertexShader, const char *fragmentShader); 16 | 17 | protected: 18 | virtual ShaderType getShaderType(void); 19 | 20 | private: 21 | virtual bool drawFrame(void *bufRGB); 22 | 23 | virtual bool drawFrame(void *bufRGB, GLfloat *vertices, GLfloat *textureCoords); 24 | 25 | virtual int drawFrameBuffer(void *bufRGB); 26 | 27 | virtual int drawFrameBuffer(void *bufRGB, GLfloat *vertices, GLfloat *textureCoords); 28 | }; 29 | 30 | 31 | #endif //EGLNATIVESAMPLE_NV12IMAGEINPUTFILTER_H 32 | -------------------------------------------------------------------------------- /app/src/main/cpp/cainfilter/input/NV21ImageInputFilter.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by admin on 2018/4/4. 3 | // 4 | 5 | #include "NV21ImageInputFilter.h" 6 | 7 | NV21ImageInputFilter::NV21ImageInputFilter() { 8 | NV21ImageInputFilter(getVertexShader(), getFragmentShader()); 9 | } 10 | 11 | NV21ImageInputFilter::NV21ImageInputFilter(const char *vertexShader, const char *fragmentShader) 12 | : GLImageInputFilter(vertexShader, fragmentShader) {} 13 | 14 | ShaderType NV21ImageInputFilter::getShaderType(void) { 15 | return FRAGMENT_NV21; 16 | } 17 | 18 | bool NV21ImageInputFilter::drawFrame(void *bufRGB) { 19 | return GLImageInputFilter::drawFrame(bufRGB); 20 | } 21 | 22 | bool NV21ImageInputFilter::drawFrame(void *bufRGB, GLfloat *vertices, GLfloat *textureCoords) { 23 | return GLImageInputFilter::drawFrame(bufRGB, vertices, textureCoords); 24 | } 25 | 26 | int NV21ImageInputFilter::drawFrameBuffer(void *bufRGB) { 27 | return GLImageInputFilter::drawFrameBuffer(bufRGB); 28 | } 29 | 30 | int NV21ImageInputFilter::drawFrameBuffer(void *bufRGB, GLfloat *vertices, GLfloat *textureCoords) { 31 | return GLImageInputFilter::drawFrameBuffer(bufRGB, vertices, textureCoords); 32 | } 33 | 34 | 35 | -------------------------------------------------------------------------------- /app/src/main/cpp/cainfilter/input/NV21ImageInputFilter.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by admin on 2018/4/4. 3 | // 4 | 5 | #ifndef EGLNATIVESAMPLE_NV21IMAGEINPUTFILTER_H 6 | #define EGLNATIVESAMPLE_NV21IMAGEINPUTFILTER_H 7 | 8 | 9 | #include "../GLImageInputFilter.h" 10 | 11 | class NV21ImageInputFilter : public GLImageInputFilter { 12 | 13 | public: 14 | NV21ImageInputFilter(); 15 | 16 | NV21ImageInputFilter(const char *vertexShader, const char *fragmentShader); 17 | 18 | protected: 19 | virtual ShaderType getShaderType(void); 20 | 21 | private: 22 | virtual bool drawFrame(void *bufRGB); 23 | 24 | virtual bool drawFrame(void *bufRGB, GLfloat *vertices, GLfloat *textureCoords); 25 | 26 | virtual int drawFrameBuffer(void *bufRGB); 27 | 28 | virtual int drawFrameBuffer(void *bufRGB, GLfloat *vertices, GLfloat *textureCoords); 29 | }; 30 | 31 | 32 | #endif //EGLNATIVESAMPLE_NV21IMAGEINPUTFILTER_H 33 | -------------------------------------------------------------------------------- /app/src/main/cpp/cainfilter/input/RGBImageInputFilter.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by admin on 2018/4/4. 3 | // 4 | 5 | #include "RGBImageInputFilter.h" 6 | RGBImageInputFilter::RGBImageInputFilter() { 7 | RGBImageInputFilter(getVertexShader(), getFragmentShader()); 8 | } 9 | 10 | RGBImageInputFilter::RGBImageInputFilter(const char *vertexShader, const char *fragmentShader) 11 | : GLImageInputFilter(vertexShader, fragmentShader) { 12 | } 13 | 14 | 15 | ShaderType RGBImageInputFilter::getShaderType(void) { 16 | return FRAGMENT_RGB; 17 | } 18 | 19 | bool RGBImageInputFilter::drawFrame(void *bufY, void *bufU, void *bufV) { 20 | return GLImageInputFilter::drawFrame(bufY, bufU, bufV); 21 | } 22 | 23 | bool RGBImageInputFilter::drawFrame(void *bufY, void *bufU, void *bufV, GLfloat *vertices, 24 | GLfloat *textureCoords) { 25 | return GLImageInputFilter::drawFrame(bufY, bufU, bufV, vertices, textureCoords); 26 | } 27 | 28 | int RGBImageInputFilter::drawFrameBuffer(void *bufY, void *bufU, void *bufV, GLfloat *vertices, 29 | GLfloat *textureCoords) { 30 | return GLImageInputFilter::drawFrameBuffer(bufY, bufU, bufV, vertices, textureCoords); 31 | } 32 | 33 | int RGBImageInputFilter::drawFrameBuffer(void *bufY, void *bufU, void *bufV) { 34 | return GLImageInputFilter::drawFrameBuffer(bufY, bufU, bufV); 35 | } 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /app/src/main/cpp/cainfilter/input/RGBImageInputFilter.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by admin on 2018/4/4. 3 | // 4 | 5 | #ifndef EGLNATIVESAMPLE_RGBIMAGEINPUTFILTER_H 6 | #define EGLNATIVESAMPLE_RGBIMAGEINPUTFILTER_H 7 | 8 | 9 | #include "../GLImageInputFilter.h" 10 | 11 | class RGBImageInputFilter : public GLImageInputFilter { 12 | public: 13 | RGBImageInputFilter(); 14 | 15 | RGBImageInputFilter(const char *vertexShader, const char *fragmentShader); 16 | 17 | protected: 18 | virtual ShaderType getShaderType(void); 19 | 20 | private: 21 | virtual bool drawFrame(void *bufY, void *bufU, void *bufV); 22 | 23 | virtual bool drawFrame(void *bufY, void *bufU, void *bufV, GLfloat *vertices, GLfloat *textureCoords); 24 | 25 | virtual int drawFrameBuffer(void *bufY, void *bufU, void *bufV); 26 | 27 | virtual int drawFrameBuffer(void *bufY, void *bufU, void *bufV, GLfloat *vertices, GLfloat *textureCoords); 28 | }; 29 | 30 | 31 | #endif //EGLNATIVESAMPLE_RGBIMAGEINPUTFILTER_H 32 | -------------------------------------------------------------------------------- /app/src/main/cpp/caingles/EglCore.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Administrator on 2018/2/10. 3 | // 4 | 5 | #include "../common/native_log.h" 6 | #include "EglCore.h" 7 | #include 8 | 9 | EglCore::EglCore() { 10 | init(NULL, 0); 11 | } 12 | 13 | 14 | EglCore::~EglCore() { 15 | release(); 16 | } 17 | 18 | /** 19 | * 构造方法 20 | * @param sharedContext 21 | * @param flags 22 | */ 23 | EglCore::EglCore(EGLContext sharedContext, int flags) { 24 | init(sharedContext, flags); 25 | } 26 | 27 | /** 28 | * 初始化 29 | * @param sharedContext 30 | * @param flags 31 | * @return 32 | */ 33 | bool EglCore::init(EGLContext sharedContext, int flags) { 34 | assert(mEGLDisplay == EGL_NO_DISPLAY); 35 | if (mEGLDisplay != EGL_NO_DISPLAY) { 36 | ALOGE("EGL already set up"); 37 | return false; 38 | } 39 | if (sharedContext == NULL) { 40 | sharedContext = EGL_NO_CONTEXT; 41 | } 42 | 43 | mEGLDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); 44 | assert(mEGLDisplay != EGL_NO_DISPLAY); 45 | if (mEGLDisplay == EGL_NO_DISPLAY) { 46 | ALOGE("unable to get EGL14 display.\n"); 47 | return false; 48 | } 49 | 50 | if (!eglInitialize(mEGLDisplay, 0, 0)) { 51 | mEGLDisplay = EGL_NO_DISPLAY; 52 | ALOGE("unable to initialize EGL14"); 53 | return false; 54 | } 55 | 56 | // 尝试使用GLES3 57 | if ((flags & FLAG_TRY_GLES3) != 0) { 58 | EGLConfig config = getConfig(flags, 3); 59 | if (config != NULL) { 60 | int attrib3_list[] = { 61 | EGL_CONTEXT_CLIENT_VERSION, 3, 62 | EGL_NONE 63 | }; 64 | EGLContext context = eglCreateContext(mEGLDisplay, config, 65 | sharedContext, attrib3_list); 66 | checkEglError("eglCreateContext"); 67 | if (eglGetError() == EGL_SUCCESS) { 68 | mEGLConfig = config; 69 | mEGLContext = context; 70 | mGlVersion = 3; 71 | } 72 | } 73 | } 74 | // 如果GLES3没有获取到,则尝试使用GLES2 75 | if (mEGLContext == EGL_NO_CONTEXT) { 76 | EGLConfig config = getConfig(flags, 2); 77 | assert(config != NULL); 78 | int attrib2_list[] = { 79 | EGL_CONTEXT_CLIENT_VERSION, 2, 80 | EGL_NONE 81 | }; 82 | EGLContext context = eglCreateContext(mEGLDisplay, config, 83 | sharedContext, attrib2_list); 84 | checkEglError("eglCreateContext"); 85 | if (eglGetError() == EGL_SUCCESS) { 86 | mEGLConfig = config; 87 | mEGLContext = context; 88 | mGlVersion = 2; 89 | } 90 | } 91 | 92 | // 获取eglPresentationTimeANDROID方法的地址 93 | eglPresentationTimeANDROID = (EGL_PRESENTATION_TIME_ANDROIDPROC) 94 | eglGetProcAddress("eglPresentationTimeANDROID"); 95 | if (!eglPresentationTimeANDROID) { 96 | ALOGE("eglPresentationTimeANDROID is not available!"); 97 | } 98 | 99 | int values[1] = {0}; 100 | eglQueryContext(mEGLDisplay, mEGLContext, EGL_CONTEXT_CLIENT_VERSION, values); 101 | ALOGD("EGLContext created, client version %d", values[0]); 102 | 103 | return true; 104 | } 105 | 106 | 107 | /** 108 | * 获取合适的EGLConfig 109 | * @param flags 110 | * @param version 111 | * @return 112 | */ 113 | EGLConfig EglCore::getConfig(int flags, int version) { 114 | int renderableType = EGL_OPENGL_ES2_BIT; 115 | if (version >= 3) { 116 | renderableType |= EGL_OPENGL_ES3_BIT_KHR; 117 | } 118 | int attribList[] = { 119 | EGL_RED_SIZE, 8, 120 | EGL_GREEN_SIZE, 8, 121 | EGL_BLUE_SIZE, 8, 122 | EGL_ALPHA_SIZE, 8, 123 | //EGL_DEPTH_SIZE, 16, 124 | //EGL_STENCIL_SIZE, 8, 125 | EGL_RENDERABLE_TYPE, renderableType, 126 | EGL_NONE, 0, // placeholder for recordable [@-3] 127 | EGL_NONE 128 | }; 129 | int length = sizeof(attribList) / sizeof(attribList[0]); 130 | if ((flags & FLAG_RECORDABLE) != 0) { 131 | attribList[length - 3] = EGL_RECORDABLE_ANDROID; 132 | attribList[length - 2] = 1; 133 | } 134 | EGLConfig configs = NULL; 135 | int numConfigs; 136 | if (!eglChooseConfig(mEGLDisplay, attribList, &configs, 1, &numConfigs)) { 137 | ALOGW("unable to find RGB8888 / %d EGLConfig", version); 138 | return NULL; 139 | } 140 | return configs; 141 | } 142 | 143 | /** 144 | * 释放资源 145 | */ 146 | void EglCore::release() { 147 | if (mEGLDisplay != EGL_NO_DISPLAY) { 148 | eglMakeCurrent(mEGLDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); 149 | eglDestroyContext(mEGLDisplay, mEGLContext); 150 | eglReleaseThread(); 151 | eglTerminate(mEGLDisplay); 152 | } 153 | 154 | mEGLDisplay = EGL_NO_DISPLAY; 155 | mEGLContext = EGL_NO_CONTEXT; 156 | mEGLConfig = NULL; 157 | } 158 | 159 | /** 160 | * 获取EGLContext 161 | * @return 162 | */ 163 | EGLContext EglCore::getEGLContext() { 164 | return mEGLContext; 165 | } 166 | 167 | /** 168 | * 销毁EGLSurface 169 | * @param eglSurface 170 | */ 171 | void EglCore::releaseSurface(EGLSurface eglSurface) { 172 | eglDestroySurface(mEGLDisplay, eglSurface); 173 | } 174 | 175 | /** 176 | * 创建EGLSurface 177 | * @param surface 178 | * @return 179 | */ 180 | EGLSurface EglCore::createWindowSurface(ANativeWindow *surface) { 181 | assert(surface != NULL); 182 | if (surface == NULL) { 183 | ALOGE("ANativeWindow is NULL!"); 184 | return NULL; 185 | } 186 | int surfaceAttribs[] = { 187 | EGL_NONE 188 | }; 189 | ALOGD("eglCreateWindowSurface start"); 190 | EGLSurface eglSurface = eglCreateWindowSurface(mEGLDisplay, mEGLConfig, surface, surfaceAttribs); 191 | checkEglError("eglCreateWindowSurface"); 192 | assert(eglSurface != NULL); 193 | if (eglSurface == NULL) { 194 | ALOGE("EGLSurface is NULL!"); 195 | return NULL; 196 | } 197 | return eglSurface; 198 | } 199 | 200 | /** 201 | * 创建离屏渲染的EGLSurface 202 | * @param width 203 | * @param height 204 | * @return 205 | */ 206 | EGLSurface EglCore::createOffscreenSurface(int width, int height) { 207 | int surfaceAttribs[] = { 208 | EGL_WIDTH, width, 209 | EGL_HEIGHT, height, 210 | EGL_NONE 211 | }; 212 | EGLSurface eglSurface = eglCreatePbufferSurface(mEGLDisplay, mEGLConfig, surfaceAttribs); 213 | assert(eglSurface != NULL); 214 | if (eglSurface == NULL) { 215 | ALOGE("Surface was null"); 216 | return NULL; 217 | } 218 | return eglSurface; 219 | } 220 | 221 | /** 222 | * 切换到当前的上下文 223 | * @param eglSurface 224 | */ 225 | void EglCore::makeCurrent(EGLSurface eglSurface) { 226 | if (mEGLDisplay == EGL_NO_DISPLAY) { 227 | ALOGD("Note: makeCurrent w/o display.\n"); 228 | } 229 | if (!eglMakeCurrent(mEGLDisplay, eglSurface, eglSurface, mEGLContext)) { 230 | // TODO 抛出异常 231 | } 232 | } 233 | 234 | /** 235 | * 切换到某个上下文 236 | * @param drawSurface 237 | * @param readSurface 238 | */ 239 | void EglCore::makeCurrent(EGLSurface drawSurface, EGLSurface readSurface) { 240 | if (mEGLDisplay == EGL_NO_DISPLAY) { 241 | ALOGD("Note: makeCurrent w/o display.\n"); 242 | } 243 | if (!eglMakeCurrent(mEGLDisplay, drawSurface, readSurface, mEGLContext)) { 244 | // TODO 抛出异常 245 | } 246 | } 247 | 248 | /** 249 | * 250 | */ 251 | void EglCore::makeNothingCurrent() { 252 | if (!eglMakeCurrent(mEGLDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT)) { 253 | // TODO 抛出异常 254 | } 255 | } 256 | 257 | /** 258 | * 交换显示 259 | * @param eglSurface 260 | * @return 261 | */ 262 | bool EglCore::swapBuffers(EGLSurface eglSurface) { 263 | return eglSwapBuffers(mEGLDisplay, eglSurface); 264 | } 265 | 266 | /** 267 | * 设置显示时间戳pts 268 | * @param eglSurface 269 | * @param nsecs 270 | */ 271 | void EglCore::setPresentationTime(EGLSurface eglSurface, long nsecs) { 272 | eglPresentationTimeANDROID(mEGLDisplay, eglSurface, nsecs); 273 | } 274 | 275 | /** 276 | * 是否处于当前上下文 277 | * @param eglSurface 278 | * @return 279 | */ 280 | bool EglCore::isCurrent(EGLSurface eglSurface) { 281 | return mEGLContext == eglGetCurrentContext() && 282 | eglSurface == eglGetCurrentSurface(EGL_DRAW); 283 | } 284 | 285 | /** 286 | * 查询surface 287 | * @param eglSurface 288 | * @param what 289 | * @return 290 | */ 291 | int EglCore::querySurface(EGLSurface eglSurface, int what) { 292 | int value; 293 | eglQuerySurface(mEGLContext, eglSurface, what, &value); 294 | return value; 295 | } 296 | 297 | /** 298 | * 查询字符串 299 | * @param what 300 | * @return 301 | */ 302 | const char* EglCore::queryString(int what) { 303 | return eglQueryString(mEGLDisplay, what); 304 | } 305 | 306 | /** 307 | * 获取GLES版本号 308 | * @return 309 | */ 310 | int EglCore::getGlVersion() { 311 | return mGlVersion; 312 | } 313 | 314 | /** 315 | * 检查是否出错 316 | * @param msg 317 | */ 318 | void EglCore::checkEglError(const char *msg) { 319 | int error; 320 | if ((error = eglGetError()) != EGL_SUCCESS) { 321 | // TODO 抛出异常 322 | ALOGE("%s: EGL error: %x", msg, error); 323 | } 324 | } 325 | -------------------------------------------------------------------------------- /app/src/main/cpp/caingles/EglCore.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Administrator on 2018/2/10. 3 | // 4 | 5 | #ifndef CAINCAMERA_EGLCORE_H 6 | #define CAINCAMERA_EGLCORE_H 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | /** 14 | * Constructor flag: surface must be recordable. This discourages EGL from using a 15 | * pixel format that cannot be converted efficiently to something usable by the video 16 | * encoder. 17 | */ 18 | #define FLAG_RECORDABLE 0x01 19 | 20 | /** 21 | * Constructor flag: ask for GLES3, fall back to GLES2 if not available. Without this 22 | * flag, GLES2 is used. 23 | */ 24 | #define FLAG_TRY_GLES3 002 25 | 26 | // Android-specific extension 27 | #define EGL_RECORDABLE_ANDROID 0x3142 28 | 29 | typedef EGLBoolean (EGLAPIENTRYP EGL_PRESENTATION_TIME_ANDROIDPROC)(EGLDisplay display, EGLSurface surface, khronos_stime_nanoseconds_t time); 30 | 31 | class EglCore { 32 | 33 | private: 34 | EGLDisplay mEGLDisplay = EGL_NO_DISPLAY; 35 | EGLConfig mEGLConfig = NULL; 36 | EGLContext mEGLContext = EGL_NO_CONTEXT; 37 | 38 | // 设置时间戳方法 39 | EGL_PRESENTATION_TIME_ANDROIDPROC eglPresentationTimeANDROID = NULL; 40 | 41 | int mGlVersion = -1; 42 | // 查找合适的EGLConfig 43 | EGLConfig getConfig(int flags, int version); 44 | 45 | public: 46 | EglCore(); 47 | ~EglCore(); 48 | EglCore(EGLContext sharedContext, int flags); 49 | bool init(EGLContext sharedContext, int flags); 50 | // 释放资源 51 | void release(); 52 | // 获取EglContext 53 | EGLContext getEGLContext(); 54 | // 销毁Surface 55 | void releaseSurface(EGLSurface eglSurface); 56 | // 创建EGLSurface 57 | EGLSurface createWindowSurface(ANativeWindow *surface); 58 | // 创建离屏EGLSurface 59 | EGLSurface createOffscreenSurface(int width, int height); 60 | // 切换到当前上下文 61 | void makeCurrent(EGLSurface eglSurface); 62 | // 切换到某个上下文 63 | void makeCurrent(EGLSurface drawSurface, EGLSurface readSurface); 64 | // 没有上下文 65 | void makeNothingCurrent(); 66 | // 交换显示 67 | bool swapBuffers(EGLSurface eglSurface); 68 | // 设置pts 69 | void setPresentationTime(EGLSurface eglSurface, long nsecs); 70 | // 判断是否属于当前上下文 71 | bool isCurrent(EGLSurface eglSurface); 72 | // 执行查询 73 | int querySurface(EGLSurface eglSurface, int what); 74 | // 查询字符串 75 | const char *queryString(int what); 76 | // 获取当前的GLES 版本号 77 | int getGlVersion(); 78 | // 检查是否出错 79 | void checkEglError(const char *msg); 80 | }; 81 | 82 | 83 | #endif //CAINCAMERA_EGLCORE_H 84 | -------------------------------------------------------------------------------- /app/src/main/cpp/caingles/EglSurfaceBase.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Administrator on 2018/3/21. 3 | // 4 | 5 | #include 6 | #include 7 | #include "EglSurfaceBase.h" 8 | 9 | 10 | EglSurfaceBase::EglSurfaceBase(EglCore *eglCore) : mEglCore(eglCore) { 11 | mEglSurface = EGL_NO_SURFACE; 12 | } 13 | 14 | /** 15 | * 创建显示的Surface 16 | * @param nativeWindow 17 | */ 18 | void EglSurfaceBase::createWindowSurface(ANativeWindow *nativeWindow) { 19 | assert(mEglSurface == EGL_NO_SURFACE); 20 | if (mEglSurface != EGL_NO_SURFACE) { 21 | ALOGE("surface already created\n"); 22 | return; 23 | } 24 | mEglSurface = mEglCore->createWindowSurface(nativeWindow); 25 | } 26 | 27 | /** 28 | * 创建离屏surface 29 | * @param width 30 | * @param height 31 | */ 32 | void EglSurfaceBase::createOffscreenSurface(int width, int height) { 33 | assert(mEglSurface == EGL_NO_SURFACE); 34 | if (mEglSurface != EGL_NO_SURFACE) { 35 | ALOGE("surface already created\n"); 36 | return; 37 | } 38 | mEglSurface = mEglCore->createOffscreenSurface(width, height); 39 | mWidth = width; 40 | mHeight = height; 41 | } 42 | 43 | /** 44 | * 获取宽度 45 | * @return 46 | */ 47 | int EglSurfaceBase::getWidth() { 48 | if (mWidth < 0) { 49 | return mEglCore->querySurface(mEglSurface, EGL_WIDTH); 50 | } else { 51 | return mWidth; 52 | } 53 | } 54 | 55 | /** 56 | * 获取高度 57 | * @return 58 | */ 59 | int EglSurfaceBase::getHeight() { 60 | if (mHeight < 0) { 61 | return mEglCore->querySurface(mEglSurface, EGL_HEIGHT); 62 | } else { 63 | return mHeight; 64 | } 65 | } 66 | 67 | /** 68 | * 释放EGLSurface 69 | */ 70 | void EglSurfaceBase::releaseEglSurface() { 71 | mEglCore->releaseSurface(mEglSurface); 72 | mEglSurface = EGL_NO_SURFACE; 73 | mWidth = mHeight = -1; 74 | } 75 | 76 | /** 77 | * 切换到当前EGLContext 78 | */ 79 | void EglSurfaceBase::makeCurrent() { 80 | mEglCore->makeCurrent(mEglSurface); 81 | } 82 | 83 | /** 84 | * 交换到前台显示 85 | * @return 86 | */ 87 | bool EglSurfaceBase::swapBuffers() { 88 | bool result = mEglCore->swapBuffers(mEglSurface); 89 | if (!result) { 90 | ALOGD("WARNING: swapBuffers() failed"); 91 | } 92 | return result; 93 | } 94 | 95 | /** 96 | * 设置当前时间戳 97 | * @param nsecs 98 | */ 99 | void EglSurfaceBase::setPresentationTime(long nsecs) { 100 | mEglCore->setPresentationTime(mEglSurface, nsecs); 101 | } 102 | 103 | /** 104 | * 获取当前像素 105 | * @return 106 | */ 107 | char* EglSurfaceBase::getCurrentFrame() { 108 | char *pixels = NULL; 109 | glReadPixels(0, 0, getWidth(), getHeight(), GL_RGBA, GL_UNSIGNED_BYTE, pixels); 110 | return pixels; 111 | } 112 | -------------------------------------------------------------------------------- /app/src/main/cpp/caingles/EglSurfaceBase.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Administrator on 2018/3/21. 3 | // 4 | 5 | #ifndef CAINCAMERA_EGLSURFACEBASE_H 6 | #define CAINCAMERA_EGLSURFACEBASE_H 7 | 8 | #include "EglCore.h" 9 | #include "../common/native_log.h" 10 | 11 | class EglSurfaceBase { 12 | 13 | public: 14 | EglSurfaceBase(EglCore *eglCore); 15 | // 创建窗口Surface 16 | void createWindowSurface(ANativeWindow *nativeWindow); 17 | // 创建离屏Surface 18 | void createOffscreenSurface(int width, int height); 19 | // 获取宽度 20 | int getWidth(); 21 | // 获取高度 22 | int getHeight(); 23 | // 释放EGLSurface 24 | void releaseEglSurface(); 25 | // 切换到当前上下文 26 | void makeCurrent(); 27 | // 交换缓冲区,显示图像 28 | bool swapBuffers(); 29 | // 设置显示时间戳 30 | void setPresentationTime(long nsecs); 31 | // 获取当前帧缓冲 32 | char *getCurrentFrame(); 33 | 34 | protected: 35 | EglCore *mEglCore; 36 | EGLSurface mEglSurface; 37 | int mWidth; 38 | int mHeight; 39 | 40 | }; 41 | 42 | 43 | #endif //CAINCAMERA_EGLSURFACEBASE_H 44 | -------------------------------------------------------------------------------- /app/src/main/cpp/caingles/GlShaders.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by cain on 2018/2/8. 3 | // 4 | 5 | #include "GlShaders.h" 6 | 7 | #ifdef __cplusplus 8 | extern "C" { 9 | #endif 10 | 11 | #include 12 | 13 | // vertex shader 14 | static const char vertex_shader_default[] = SHADER_STRING( 15 | uniform mat4 uMVPMatrix; 16 | attribute vec4 aPosition; 17 | attribute vec4 aTextureCoord; 18 | varying vec2 textureCoordinate; 19 | void main() { 20 | gl_Position = uMVPMatrix * aPosition; 21 | textureCoordinate = vec2(aTextureCoord.x, aTextureCoord.y); 22 | } 23 | ); 24 | 25 | 26 | // vertex shader reverse image 27 | static const char vertex_shader_reverse[] = SHADER_STRING( 28 | uniform mat4 uMVPMatrix; 29 | attribute vec4 aPosition; 30 | attribute vec4 aTextureCoord; 31 | varying vec2 textureCoordinate; 32 | void main() { 33 | gl_Position = uMVPMatrix * aPosition; 34 | textureCoordinate = vec2(aTextureCoord.x, 1.0 - aTextureCoord.y); 35 | } 36 | ); 37 | 38 | // fragment shader solid color 39 | static const char fragment_shader_solid[] = SHADER_STRING( 40 | precision mediump float; 41 | varying highp vec2 textureCoordinate; 42 | uniform vec4 aColor; 43 | void main() { 44 | gl_FragColor = aColor; 45 | } 46 | ); 47 | 48 | // fragment shader(BGR to ABGR conversion) 49 | static const char fragment_shader_bgr[] = SHADER_STRING( 50 | precision highp float; 51 | 52 | varying highp vec2 textureCoordinate; 53 | uniform lowp sampler2D inputTexture; 54 | 55 | void main() 56 | { 57 | gl_FragColor = vec4(texture2D(inputTexture, textureCoordinate).rgb, 1); 58 | } 59 | ); 60 | 61 | // fragment shader(ABGR) 62 | static const char fragment_shader_abgr[] = SHADER_STRING( 63 | precision highp float; 64 | 65 | varying highp vec2 textureCoordinate; 66 | uniform lowp sampler2D inputTexture; 67 | 68 | void main() 69 | { 70 | gl_FragColor = texture2D(inputTexture, textureCoordinate); 71 | } 72 | ); 73 | 74 | // fragment shader ( ARGB to ABGR conversion) 75 | static const char fragment_shader_argb[] = SHADER_STRING( 76 | precision highp float; 77 | 78 | varying highp vec2 textureCoordinate; 79 | uniform lowp sampler2D inputTexture; 80 | 81 | void main() 82 | { 83 | vec4 abgr = texture2D(inputTexture, textureCoordinate); 84 | 85 | gl_FragColor = abgr; 86 | gl_FragColor.r = abgr.b; 87 | gl_FragColor.b = abgr.r; 88 | } 89 | ); 90 | 91 | // fragment shader (RGB to ABGR conversion) 92 | static const char fragment_shader_rgb[] = SHADER_STRING( 93 | precision highp float; 94 | 95 | varying highp vec2 textureCoordinate; 96 | uniform lowp sampler2D inputTexture; 97 | 98 | void main() 99 | { 100 | vec4 abgr = texture2D(inputTexture, textureCoordinate); 101 | 102 | gl_FragColor = abgr; 103 | gl_FragColor.r = abgr.b; 104 | gl_FragColor.b = abgr.r; 105 | gl_FragColor.a = 1.0; 106 | } 107 | ); 108 | 109 | 110 | 111 | // fragment shader (YUV420P/I420 to ARGB conversion) 112 | static const char fragment_shader_i420[] = SHADER_STRING( 113 | precision mediump float; 114 | varying highp vec2 textureCoordinate; 115 | uniform lowp sampler2D inputTextureY; 116 | uniform lowp sampler2D inputTextureU; 117 | uniform lowp sampler2D inputTextureV; 118 | 119 | void main() { 120 | vec3 yuv; 121 | vec3 rgb; 122 | yuv.r = texture2D(inputTextureY, textureCoordinate).r; 123 | yuv.g = texture2D(inputTextureU, textureCoordinate).r - 0.5; 124 | yuv.b = texture2D(inputTextureV, textureCoordinate).r - 0.5; 125 | rgb = mat3(1.0, 1.0, 1.0, 126 | 0.0, -0.39465, 2.03211, 127 | 1.13983, -0.58060, 0.0) * yuv; 128 | gl_FragColor = vec4(rgb, 1.0); 129 | } 130 | ); 131 | 132 | // fragment shader (NV12 to ARGB conversion) 133 | static const char fragment_shader_nv12[] = SHADER_STRING( 134 | precision mediump float; 135 | varying highp vec2 textureCoordinate; 136 | uniform lowp sampler2D inputTextureY; 137 | uniform lowp sampler2D inputTextureUV; 138 | 139 | void main() { 140 | mediump vec3 yuv; 141 | lowp vec3 rgb; 142 | yuv.x = texture2D(inputTextureY, textureCoordinate).r; 143 | yuv.yz = texture2D(inputTextureUV, textureCoordinate).ra - 0.5; 144 | rgb = mat3(1.0, 1.0, 1.0, 145 | 0.0, -0.39465, 2.03211, 146 | 1.13983, -0.58060, 0.0) * yuv; 147 | gl_FragColor = vec4(rgb, 1.0); 148 | } 149 | ); 150 | 151 | // fragment shader (NV21 to ARGB conversion) 152 | static const char fragment_shader_nv21[] = SHADER_STRING( 153 | precision mediump float; 154 | varying highp vec2 textureCoordinate; 155 | uniform lowp sampler2D inputTextureY; 156 | uniform lowp sampler2D inputTextureUV; 157 | 158 | void main() { 159 | mediump vec3 yuv; 160 | lowp vec3 rgb; 161 | yuv.x = texture2D(inputTextureY, textureCoordinate).r; 162 | yuv.yz = texture2D(inputTextureUV, textureCoordinate).ar - 0.5; 163 | rgb = mat3(1.0, 1.0, 1.0, 164 | 0.0, -0.39465, 2.03211, 165 | 1.13983, -0.58060, 0.0) * yuv; 166 | gl_FragColor = vec4(rgb, 1.0); 167 | } 168 | ); 169 | 170 | /** 171 | * 获取shader程序 172 | * @param type 173 | * @return 174 | */ 175 | const char *GlShader_GetShader(ShaderType type) { 176 | switch(type) { 177 | case VERTEX_DEFAULT: 178 | return vertex_shader_default; 179 | case VERTEX_REVERSE: 180 | return vertex_shader_reverse; 181 | case FRAGMENT_SOLID: 182 | return fragment_shader_solid; 183 | case FRAGMENT_ABGR: 184 | return fragment_shader_abgr; 185 | case FRAGMENT_ARGB: 186 | return fragment_shader_argb; 187 | case FRAGMENT_BGR: 188 | return fragment_shader_bgr; 189 | case FRAGMENT_RGB: 190 | return fragment_shader_rgb; 191 | case FRAGMENT_I420: 192 | return fragment_shader_i420; 193 | case FRAGMENT_NV12: 194 | return fragment_shader_nv12; 195 | case FRAGMENT_NV21: 196 | return fragment_shader_nv21; 197 | default: 198 | return NULL; 199 | } 200 | } 201 | 202 | 203 | #ifdef __cplusplus 204 | }; 205 | #endif -------------------------------------------------------------------------------- /app/src/main/cpp/caingles/GlShaders.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Administrator on 2018/2/7. 3 | // 4 | 5 | #ifndef CAINCAMERA_GLSHADERS_H 6 | #define CAINCAMERA_GLSHADERS_H 7 | #ifdef __cplusplus 8 | extern "C" { 9 | #endif 10 | 11 | // 转成字符串 12 | #define SHADER_STRING(s) #s 13 | 14 | typedef enum { 15 | VERTEX_DEFAULT, 16 | VERTEX_REVERSE, 17 | FRAGMENT_SOLID, 18 | FRAGMENT_ABGR, 19 | FRAGMENT_ARGB, 20 | FRAGMENT_BGR, 21 | FRAGMENT_RGB, 22 | FRAGMENT_I420, 23 | FRAGMENT_NV12, 24 | FRAGMENT_NV21 25 | } ShaderType; 26 | 27 | // 获取shader 28 | const char *GlShader_GetShader(ShaderType type); 29 | 30 | #ifdef __cplusplus 31 | }; 32 | #endif 33 | 34 | #endif //CAINCAMERA_GLSHADERS_H 35 | -------------------------------------------------------------------------------- /app/src/main/cpp/caingles/GlUtils.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Administrator on 2018/2/7. 3 | // 4 | 5 | #ifndef CAINCAMERA_GLUTILS_H 6 | #define CAINCAMERA_GLUTILS_H 7 | 8 | #ifdef __cplusplus 9 | extern "C" { 10 | #endif 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #include "GlShaders.h" 19 | #include "../common/native_log.h" 20 | 21 | #define PI 3.1415926535897932384626433832795f 22 | // 矩阵 23 | typedef struct { 24 | GLfloat m[16]; 25 | } ESMatrix; 26 | 27 | 28 | // 创建program 29 | GLuint createProgram(const char *vertexShader, const char *fragShader); 30 | 31 | // 加载shader 32 | GLuint loadShader(GLenum type, const char* shaderSrc); 33 | 34 | // 查询活动的统一变量uniform 35 | void checkActiveUniform(GLuint program); 36 | 37 | // 创建texture 38 | GLuint createTexture(GLenum type); 39 | 40 | // 创建texture 41 | GLuint createTextureWithBytes(unsigned char* bytes, int width, int height); 42 | 43 | // 使用旧的Texture 创建新的Texture 44 | GLuint createTextureWithOldTexture(GLuint texture, unsigned char* bytes, int width, int height); 45 | 46 | // 创建一个FBO和Texture 47 | void createFrameBuffer(GLuint *framebuffer, GLuint* texture, int width, int height); 48 | 49 | // 创建FBO和Texture 50 | void createFrameBuffers(GLuint* frambuffers, GLuint* textures, int width, int height, int size); 51 | 52 | // 检查是否出错 53 | void checkGLError(const char * op); 54 | // -------------------------------------------- matrix部分 ----------------------------------------- 55 | // 缩放 56 | void scaleM(ESMatrix *result, int offset, GLfloat sx, GLfloat sy, GLfloat sz); 57 | 58 | // 平移 59 | void translateM(ESMatrix *result, int offset, GLfloat x, GLfloat y, GLfloat z); 60 | 61 | 62 | // 旋转 63 | void rotateM(ESMatrix *result, GLfloat angle, GLfloat x, GLfloat y, GLfloat z); 64 | 65 | // 正交投影矩阵 66 | int orthoM(ESMatrix *result, int mOffset, float left, float right, 67 | float bottom, float top, float near, float far); 68 | 69 | // 视锥体 70 | int frustumM(ESMatrix *result, int offset, float left, float right, 71 | float bottom, float top, float near, float far); 72 | 73 | // 透视矩阵 74 | int perspectiveM(ESMatrix *result, int offset, 75 | float fovy, float aspect, float zNear, float zFar); 76 | 77 | // 产生一个单位矩阵 78 | void setIdentityM(ESMatrix *result); 79 | 80 | // 矩阵相乘 81 | void multiplyMM(ESMatrix *result, ESMatrix *lhs, ESMatrix * rhs); 82 | 83 | #ifdef __cplusplus 84 | } 85 | #endif 86 | 87 | #endif //CAINCAMERA_GLUTILS_H 88 | -------------------------------------------------------------------------------- /app/src/main/cpp/caingles/OffscreenSurface.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Administrator on 2018/3/21. 3 | // 4 | 5 | #include "OffscreenSurface.h" 6 | 7 | OffscreenSurface::OffscreenSurface(EglCore *eglCore, int width, int height) 8 | : EglSurfaceBase(eglCore) { 9 | createOffscreenSurface(width, height); 10 | } 11 | 12 | void OffscreenSurface::release() { 13 | releaseEglSurface(); 14 | } 15 | 16 | 17 | -------------------------------------------------------------------------------- /app/src/main/cpp/caingles/OffscreenSurface.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Administrator on 2018/3/21. 3 | // 4 | 5 | #ifndef CAINCAMERA_OFFSCREENSURFACE_H 6 | #define CAINCAMERA_OFFSCREENSURFACE_H 7 | 8 | 9 | #include "EglSurfaceBase.h" 10 | 11 | class OffscreenSurface : public EglSurfaceBase { 12 | public: 13 | OffscreenSurface(EglCore *eglCore, int width, int height); 14 | void release(); 15 | }; 16 | 17 | 18 | #endif //CAINCAMERA_OFFSCREENSURFACE_H 19 | -------------------------------------------------------------------------------- /app/src/main/cpp/caingles/WindowSurface.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Administrator on 2018/3/21. 3 | // 4 | 5 | #include 6 | #include "WindowSurface.h" 7 | 8 | WindowSurface::WindowSurface(EglCore *eglCore, ANativeWindow *window, bool releaseSurface) 9 | : EglSurfaceBase(eglCore) { 10 | mSurface = window; 11 | createWindowSurface(mSurface); 12 | mReleaseSurface = releaseSurface; 13 | } 14 | 15 | WindowSurface::WindowSurface(EglCore *eglCore, ANativeWindow *window) 16 | : EglSurfaceBase(eglCore) { 17 | createWindowSurface(window); 18 | mSurface = window; 19 | } 20 | 21 | void WindowSurface::release() { 22 | releaseEglSurface(); 23 | if (mSurface != NULL) { 24 | ANativeWindow_release(mSurface); 25 | mSurface = NULL; 26 | } 27 | 28 | } 29 | 30 | void WindowSurface::recreate(EglCore *eglCore) { 31 | assert(mSurface != NULL); 32 | if (mSurface == NULL) { 33 | ALOGE("not yet implemented ANativeWindow"); 34 | return; 35 | } 36 | mEglCore = eglCore; 37 | createWindowSurface(mSurface); 38 | } -------------------------------------------------------------------------------- /app/src/main/cpp/caingles/WindowSurface.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Administrator on 2018/3/21. 3 | // 4 | 5 | #ifndef CAINCAMERA_WINDOWSURFACE_H 6 | #define CAINCAMERA_WINDOWSURFACE_H 7 | 8 | 9 | #include "EglSurfaceBase.h" 10 | 11 | class WindowSurface : public EglSurfaceBase { 12 | 13 | public: 14 | WindowSurface(EglCore *eglCore, ANativeWindow *window, bool releaseSurface); 15 | WindowSurface(EglCore *eglCore, ANativeWindow *window); 16 | // 释放资源 17 | void release(); 18 | // 重新创建 19 | void recreate(EglCore *eglCore); 20 | 21 | private: 22 | ANativeWindow *mSurface; 23 | bool mReleaseSurface; 24 | }; 25 | 26 | 27 | #endif //CAINCAMERA_WINDOWSURFACE_H 28 | -------------------------------------------------------------------------------- /app/src/main/cpp/cainrender/GLRender.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by admin on 2018/4/3. 3 | // 4 | 5 | #include "GLRender.h" 6 | #include "../caingles/GlUtils.h" 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | GLRender::GLRender() { 14 | mEglCore = NULL; 15 | mWindowSurface = NULL; 16 | } 17 | 18 | GLRender::~GLRender() { 19 | if (mEglCore) { 20 | mEglCore->release(); 21 | delete mEglCore; 22 | mEglCore = NULL; 23 | } 24 | } 25 | 26 | void GLRender::surfaceCreated(ANativeWindow *window) { 27 | 28 | if (mEglCore == NULL) { 29 | mEglCore = new EglCore(NULL, FLAG_RECORDABLE); 30 | } 31 | mWindowSurface = new WindowSurface(mEglCore, window, false); 32 | assert(mWindowSurface != NULL && mEglCore != NULL); 33 | mWindowSurface->makeCurrent(); 34 | mTriangle = new Triangle(); 35 | mTriangle->init(); 36 | } 37 | 38 | void GLRender::surfaceChanged(int width, int height) { 39 | mWindowSurface->makeCurrent(); 40 | mTriangle->onDraw(width, height); 41 | mWindowSurface->swapBuffers(); 42 | } 43 | 44 | void GLRender::surfaceDestroyed() { 45 | if (mTriangle) { 46 | mTriangle->destroy(); 47 | delete mTriangle; 48 | mTriangle = NULL; 49 | } 50 | if (mWindowSurface) { 51 | mWindowSurface->release(); 52 | delete mWindowSurface; 53 | mWindowSurface = NULL; 54 | } 55 | if (mEglCore) { 56 | mEglCore->release(); 57 | delete mEglCore; 58 | mEglCore = NULL; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /app/src/main/cpp/cainrender/GLRender.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by admin on 2018/4/3. 3 | // 4 | 5 | #ifndef EGLNATIVESAMPLE_GLRENDER_H 6 | #define EGLNATIVESAMPLE_GLRENDER_H 7 | 8 | 9 | #include 10 | #include "../caingles/EglCore.h" 11 | #include "../caingles/WindowSurface.h" 12 | #include "Triangle.h" 13 | 14 | class GLRender { 15 | public: 16 | GLRender(); 17 | 18 | virtual ~GLRender(); 19 | 20 | void surfaceCreated(ANativeWindow *window); 21 | 22 | void surfaceChanged(int width, int height); 23 | 24 | void surfaceDestroyed(void); 25 | 26 | private: 27 | EglCore *mEglCore; 28 | WindowSurface *mWindowSurface; 29 | Triangle *mTriangle; 30 | }; 31 | 32 | 33 | #endif //EGLNATIVESAMPLE_GLRENDER_H 34 | -------------------------------------------------------------------------------- /app/src/main/cpp/cainrender/Triangle.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by cain on 2018/4/7. 3 | // 4 | 5 | #include "Triangle.h" 6 | 7 | const GLint COORDS_PER_VERTEX = 3; 8 | const GLint vertexStride = COORDS_PER_VERTEX * 4; 9 | 10 | Triangle::Triangle() {} 11 | 12 | Triangle::~Triangle() { 13 | 14 | } 15 | 16 | int Triangle::init() { 17 | char vertexShader[] = 18 | "#version 300 es\n" 19 | "layout(location = 0) in vec4 a_position;\n" 20 | "layout(location = 1) in vec4 a_color;\n" 21 | "out vec4 v_color;" 22 | "void main()\n" 23 | "{\n" 24 | " gl_Position = a_position;\n" 25 | " v_color = a_color;\n" 26 | "}\n"; 27 | 28 | char fragmentShader[] = 29 | "#version 300 es\n" 30 | "precision mediump float;\n" 31 | "in vec4 v_color;\n" 32 | "out vec4 fragColor;\n" 33 | "void main()\n" 34 | "{\n" 35 | // " fragColor = vec4 ( 1.0, 0.0, 0.0, 1.0 );\n" 36 | " fragColor = v_color;\n" 37 | "}\n"; 38 | programHandle = createProgram(vertexShader, fragmentShader); 39 | if (programHandle <= 0) { 40 | return -1; 41 | } 42 | glClearColor(0.0f, 0.0f, 0.0f, 0.0f); 43 | return 0; 44 | } 45 | 46 | 47 | void Triangle::onDraw(int width, int height) { 48 | ALOGD("hahahah"); 49 | GLfloat vertices[] = { 50 | 0.0f, 0.5f, 0.0f, 51 | -0.5f, -0.5f, 0.0f, 52 | 0.5f, -0.5f, 0.0f 53 | }; 54 | 55 | GLfloat color[] = { 56 | 1.0f, 0.0f, 0.0f, 1.0f 57 | }; 58 | 59 | GLint vertexCount = sizeof(vertices) / (sizeof(vertices[0]) * COORDS_PER_VERTEX); 60 | 61 | glViewport(0, 0, width, height); 62 | 63 | glClear(GL_COLOR_BUFFER_BIT); 64 | 65 | glUseProgram(programHandle); 66 | 67 | GLint positionHandle = glGetAttribLocation(programHandle, "a_position"); 68 | glVertexAttribPointer(positionHandle, COORDS_PER_VERTEX, GL_FLOAT, GL_FALSE, vertexStride, vertices); 69 | glEnableVertexAttribArray(positionHandle); 70 | glVertexAttrib4fv(1, color); 71 | 72 | glDrawArrays(GL_TRIANGLES, 0, vertexCount); 73 | 74 | glDisableVertexAttribArray(positionHandle); 75 | } 76 | 77 | void Triangle::destroy() { 78 | if (programHandle > 0) { 79 | glDeleteProgram(programHandle); 80 | } 81 | programHandle = -1; 82 | } -------------------------------------------------------------------------------- /app/src/main/cpp/cainrender/Triangle.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by cain on 2018/4/7. 3 | // 4 | 5 | #ifndef EGLNATIVERENDER_TRIANGLE_H 6 | #define EGLNATIVERENDER_TRIANGLE_H 7 | 8 | #include "../caingles/GlUtils.h" 9 | #include "../caingles/GlShaders.h" 10 | #include "../common/native_log.h" 11 | 12 | class Triangle { 13 | public: 14 | Triangle(); 15 | 16 | virtual ~Triangle(); 17 | 18 | int init(void); 19 | 20 | void onDraw(int width, int height); 21 | 22 | void destroy(); 23 | 24 | private: 25 | int programHandle; 26 | }; 27 | 28 | 29 | #endif //EGLNATIVERENDER_TRIANGLE_H 30 | -------------------------------------------------------------------------------- /app/src/main/cpp/common/Looper.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by admin on 2018/3/30. 3 | // 4 | 5 | #include "Looper.h" 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include "native_log.h" 16 | 17 | struct LooperMessage; 18 | typedef struct LooperMessage LooperMessage; 19 | 20 | 21 | 22 | /** 23 | * 线程执行句柄 24 | * @param p 25 | * @return 26 | */ 27 | void* Looper::trampoline(void* p) { 28 | ((Looper*)p)->loop(); 29 | return NULL; 30 | } 31 | 32 | 33 | Looper::Looper() { 34 | head = NULL; 35 | 36 | sem_init(&headdataavailable, 0, 0); 37 | sem_init(&headwriteprotect, 0, 1); 38 | pthread_attr_t attr; 39 | pthread_attr_init(&attr); 40 | 41 | pthread_create(&worker, &attr, trampoline, this); 42 | running = true; 43 | } 44 | 45 | Looper::~Looper() { 46 | if (running) { 47 | ALOGD("Looper deleted while still running. Some messages will not be processed"); 48 | quit(); 49 | } 50 | } 51 | 52 | /** 53 | * 入队消息 54 | * @param what 55 | * @param flush 56 | */ 57 | void Looper::postMessage(int what, bool flush) { 58 | postMessage(what, 0, 0, NULL, flush); 59 | } 60 | 61 | /** 62 | * 入队消息 63 | * @param what 64 | * @param obj 65 | * @param flush 66 | */ 67 | void Looper::postMessage(int what, void *obj, bool flush) { 68 | postMessage(what, 0, 0, obj, flush); 69 | } 70 | 71 | /** 72 | * 入队消息 73 | * @param what 74 | * @param arg1 75 | * @param arg2 76 | * @param flush 77 | */ 78 | void Looper::postMessage(int what, int arg1, int arg2, bool flush) { 79 | postMessage(what, arg1, arg2, NULL, flush); 80 | } 81 | 82 | /** 83 | * 84 | * @param what 85 | * @param arg1 86 | * @param arg2 87 | * @param obj 88 | * @param flush 89 | */ 90 | void Looper::postMessage(int what, int arg1, int arg2, void *obj, bool flush) { 91 | LooperMessage *msg = new LooperMessage(); 92 | msg->what = what; 93 | msg->obj = obj; 94 | msg->arg1 = arg1; 95 | msg->arg2 = arg2; 96 | msg->next = NULL; 97 | msg->quit = false; 98 | addMessage(msg, flush); 99 | } 100 | 101 | /** 102 | * 添加消息 103 | * @param msg 104 | * @param flush 105 | */ 106 | void Looper::addMessage(LooperMessage *msg, bool flush) { 107 | sem_wait(&headwriteprotect); 108 | LooperMessage *h = head; 109 | 110 | if (flush) { 111 | while(h) { 112 | LooperMessage *next = h->next; 113 | delete h; 114 | h = next; 115 | } 116 | h = NULL; 117 | } 118 | if (h) { 119 | while (h->next) { 120 | h = h->next; 121 | } 122 | h->next = msg; 123 | } else { 124 | head = msg; 125 | } 126 | ALOGD("post msg %d", msg->what); 127 | sem_post(&headwriteprotect); 128 | sem_post(&headdataavailable); 129 | } 130 | 131 | /** 132 | * 循环体 133 | */ 134 | void Looper::loop() { 135 | while(true) { 136 | // wait for available message 137 | sem_wait(&headdataavailable); 138 | 139 | // get next available message 140 | sem_wait(&headwriteprotect); 141 | LooperMessage *msg = head; 142 | if (msg == NULL) { 143 | ALOGD("no msg"); 144 | sem_post(&headwriteprotect); 145 | continue; 146 | } 147 | head = msg->next; 148 | sem_post(&headwriteprotect); 149 | 150 | if (msg->quit) { 151 | ALOGD("quitting"); 152 | delete msg; 153 | return; 154 | } 155 | ALOGD("processing msg %d", msg->what); 156 | handleMessage(msg); 157 | delete msg; 158 | } 159 | } 160 | 161 | /** 162 | * 退出Looper循环 163 | */ 164 | void Looper::quit() { 165 | ALOGD("quit"); 166 | LooperMessage *msg = new LooperMessage(); 167 | msg->what = 0; 168 | msg->obj = NULL; 169 | msg->next = NULL; 170 | msg->quit = true; 171 | addMessage(msg, false); 172 | void *retval; 173 | pthread_join(worker, &retval); 174 | sem_destroy(&headdataavailable); 175 | sem_destroy(&headwriteprotect); 176 | running = false; 177 | } 178 | 179 | /** 180 | * 处理消息 181 | * @param what 182 | * @param data 183 | */ 184 | void Looper::handleMessage(LooperMessage *msg) { 185 | ALOGD("dropping msg %d %p", msg->what, msg->obj); 186 | } -------------------------------------------------------------------------------- /app/src/main/cpp/common/Looper.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by admin on 2018/3/30. 3 | // 4 | 5 | #ifndef CAINPLAYER_LOOPER_H 6 | #define CAINPLAYER_LOOPER_H 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | struct LooperMessage { 13 | int what; 14 | int arg1; 15 | int arg2; 16 | void *obj; 17 | LooperMessage *next; 18 | bool quit; 19 | }; 20 | 21 | class Looper { 22 | 23 | public: 24 | Looper(); 25 | Looper&operator=(const Looper& ) = delete; 26 | Looper(Looper&) = delete; 27 | virtual ~Looper(); 28 | 29 | // 发送消息 30 | void postMessage(int what, bool flush = false); 31 | void postMessage(int what, void *obj, bool flush = false); 32 | void postMessage(int what, int arg1, int arg2, bool flush = false); 33 | void postMessage(int what, int arg1, int arg2, void *obj, bool flush = false); 34 | 35 | // 退出Looper循环 36 | void quit(); 37 | 38 | // 处理消息 39 | virtual void handleMessage(LooperMessage *msg); 40 | 41 | private: 42 | // 添加消息 43 | void addMessage(LooperMessage *msg, bool flush); 44 | 45 | // 消息线程句柄 46 | static void *trampoline(void *p); 47 | 48 | // 循环体 49 | void loop(void); 50 | 51 | LooperMessage *head; 52 | pthread_t worker; 53 | sem_t headwriteprotect; 54 | sem_t headdataavailable; 55 | bool running; 56 | 57 | }; 58 | 59 | 60 | #endif //CAINPLAYER_LOOPER_H 61 | -------------------------------------------------------------------------------- /app/src/main/cpp/common/MyLooper.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by admin on 2018/4/3. 3 | // 4 | 5 | #include "MyLooper.h" 6 | 7 | MyLooper::MyLooper() { 8 | mRender = new GLRender(); 9 | } 10 | 11 | void MyLooper::handleMessage(LooperMessage *msg) { 12 | switch (msg && msg->what) { 13 | case kMsgSurfaceCreated: 14 | if (mRender) { 15 | mRender->surfaceCreated((ANativeWindow *) msg->obj); 16 | } 17 | break; 18 | 19 | case kMsgSurfaceChanged: 20 | if (mRender) { 21 | mRender->surfaceChanged(msg->arg1, msg->arg2); 22 | } 23 | break; 24 | 25 | case kMsgSurfaceDestroyed: 26 | if (mRender) { 27 | mRender->surfaceDestroyed(); 28 | } 29 | break; 30 | } 31 | } 32 | 33 | MyLooper::~MyLooper() { 34 | delete mRender; 35 | } 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /app/src/main/cpp/common/MyLooper.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by admin on 2018/4/3. 3 | // 4 | 5 | #ifndef EGLNATIVESAMPLE_MYLOOPER_H 6 | #define EGLNATIVESAMPLE_MYLOOPER_H 7 | 8 | #include "Looper.h" 9 | #include "../cainrender/GLRender.h" 10 | 11 | enum { 12 | kMsgSurfaceCreated, 13 | kMsgSurfaceChanged, 14 | kMsgSurfaceDestroyed 15 | }; 16 | 17 | class MyLooper : public Looper { 18 | 19 | public: 20 | MyLooper(); 21 | 22 | virtual ~MyLooper(); 23 | 24 | virtual void handleMessage(LooperMessage *msg); 25 | 26 | private: 27 | GLRender *mRender; 28 | 29 | }; 30 | 31 | 32 | #endif //EGLNATIVESAMPLE_MYLOOPER_H 33 | -------------------------------------------------------------------------------- /app/src/main/cpp/common/native_log.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by cain on 2017/12/28. 3 | // 4 | 5 | #ifndef CAINCAMERA_NATIVE_LOG_H 6 | #define CAINCAMERA_NATIVE_LOG_H 7 | #include 8 | 9 | #define JNI_DEBUG 1 10 | #define JNI_TAG "CainJni_ffmpeg" 11 | 12 | #define ALOGE(format, ...) if (JNI_DEBUG) { __android_log_print(ANDROID_LOG_ERROR, JNI_TAG, format, ##__VA_ARGS__); } 13 | #define ALOGI(format, ...) if (JNI_DEBUG) { __android_log_print(ANDROID_LOG_INFO, JNI_TAG, format, ##__VA_ARGS__); } 14 | #define ALOGD(format, ...) if (JNI_DEBUG) { __android_log_print(ANDROID_LOG_DEBUG, JNI_TAG, format, ##__VA_ARGS__); } 15 | #define ALOGW(format, ...) if (JNI_DEBUG) { __android_log_print(ANDROID_LOG_WARN, JNI_TAG, format, ##__VA_ARGS__); } 16 | #endif //CAINCAMERA_NATIVE_LOG_H 17 | -------------------------------------------------------------------------------- /app/src/main/java/com/cgfay/eglnativerender/EGLRender.java: -------------------------------------------------------------------------------- 1 | package com.cgfay.eglnativerender; 2 | 3 | import android.view.Surface; 4 | 5 | public class EGLRender { 6 | static { 7 | System.loadLibrary("nativeEgl"); 8 | } 9 | private native void nativeInit(); 10 | private native void nativeRelease(); 11 | private native void onSurfaceCreated(Surface surface); 12 | private native void onSurfaceChanged(int width, int height); 13 | private native void onSurfaceDestroyed(); 14 | 15 | public EGLRender() { 16 | } 17 | 18 | public void init() { 19 | nativeInit(); 20 | } 21 | 22 | public void release() { 23 | nativeRelease(); 24 | } 25 | 26 | public void surfaceCreated(Surface surface) { 27 | onSurfaceCreated(surface); 28 | } 29 | 30 | public void surfaceChanged(int width, int height) { 31 | onSurfaceChanged(width, height); 32 | } 33 | 34 | public void surfaceDestroyed() { 35 | onSurfaceDestroyed(); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /app/src/main/java/com/cgfay/eglnativerender/Main2Activity.java: -------------------------------------------------------------------------------- 1 | package com.cgfay.eglnativerender; 2 | 3 | import android.annotation.SuppressLint; 4 | import android.graphics.SurfaceTexture; 5 | import android.os.Handler; 6 | import android.os.Message; 7 | import android.support.v7.app.AppCompatActivity; 8 | import android.os.Bundle; 9 | import android.view.Gravity; 10 | import android.view.Surface; 11 | import android.view.TextureView; 12 | import android.widget.FrameLayout; 13 | 14 | import javax.microedition.khronos.egl.EGL; 15 | 16 | public class Main2Activity extends AppCompatActivity implements TextureView.SurfaceTextureListener { 17 | 18 | private static final int MSG_RENDER_FRAME = 0x01; 19 | private TextureView mTextureView; 20 | private EGLRender mRender; 21 | private Surface mSurface; 22 | private FrameLayout mFrameLayout; 23 | 24 | private Handler mHandler = new MainHandler(); 25 | 26 | @Override 27 | protected void onCreate(Bundle savedInstanceState) { 28 | super.onCreate(savedInstanceState); 29 | setContentView(R.layout.activity_main2); 30 | mFrameLayout = (FrameLayout) findViewById(R.id.frameLayout); 31 | mRender = new EGLRender(); 32 | mRender.init(); 33 | mTextureView = new TextureView(this); 34 | mTextureView.setSurfaceTextureListener(this); 35 | mFrameLayout.addView(mTextureView); 36 | } 37 | 38 | @Override 39 | public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) { 40 | mTextureView.setLayoutParams( 41 | new FrameLayout.LayoutParams(1080, 1920, Gravity.CENTER)); 42 | surface.setDefaultBufferSize(1080, 1920); 43 | mSurface = new Surface(surface); 44 | mRender.surfaceCreated(mSurface); 45 | mRender.surfaceChanged(1080, 1920); 46 | } 47 | 48 | @Override 49 | public void onSurfaceTextureSizeChanged(SurfaceTexture surface, final int width, final int height) { 50 | 51 | } 52 | 53 | @Override 54 | public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) { 55 | mRender.surfaceDestroyed(); 56 | return false; 57 | } 58 | 59 | @Override 60 | public void onSurfaceTextureUpdated(SurfaceTexture surface) { 61 | 62 | } 63 | 64 | @SuppressLint("HandlerLeak") 65 | class MainHandler extends Handler { 66 | @Override 67 | public void handleMessage(Message msg) { 68 | switch (msg.what) { 69 | case MSG_RENDER_FRAME: 70 | mRender.surfaceChanged(msg.arg1, msg.arg2); 71 | mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_RENDER_FRAME, msg.arg1, msg.arg2), 100); 72 | break; 73 | } 74 | } 75 | } 76 | 77 | } 78 | -------------------------------------------------------------------------------- /app/src/main/java/com/cgfay/eglnativerender/Main3Activity.java: -------------------------------------------------------------------------------- 1 | package com.cgfay.eglnativerender; 2 | 3 | import android.graphics.SurfaceTexture; 4 | import android.opengl.GLES30; 5 | import android.os.Handler; 6 | import android.os.HandlerThread; 7 | import android.support.v7.app.AppCompatActivity; 8 | import android.os.Bundle; 9 | import android.util.Log; 10 | import android.view.Surface; 11 | import android.view.SurfaceHolder; 12 | import android.view.SurfaceView; 13 | 14 | import com.cgfay.eglnativerender.filter.OESInputFilter; 15 | import com.cgfay.eglnativerender.gles.EglCore; 16 | import com.cgfay.eglnativerender.gles.WindowSurface; 17 | import com.cgfay.eglnativerender.utils.GlUtil; 18 | 19 | public class Main3Activity extends AppCompatActivity implements SurfaceHolder.Callback, 20 | SurfaceTexture.OnFrameAvailableListener { 21 | 22 | private static final String TAG = "Render"; 23 | 24 | private SurfaceView mSurfaceView; 25 | 26 | private EGLRender mRender; 27 | 28 | private Handler mRenderHandler; 29 | private HandlerThread mRenderThread; 30 | 31 | @Override 32 | protected void onCreate(Bundle savedInstanceState) { 33 | super.onCreate(savedInstanceState); 34 | setContentView(R.layout.activity_main); 35 | mRender = new EGLRender(); 36 | mRender.init(); 37 | mSurfaceView = (SurfaceView) findViewById(R.id.surface_view); 38 | mSurfaceView.getHolder().addCallback(this); 39 | } 40 | 41 | @Override 42 | protected void onDestroy() { 43 | mRender.release(); 44 | mRender = null; 45 | super.onDestroy(); 46 | } 47 | 48 | @Override 49 | public void surfaceCreated(SurfaceHolder holder) { 50 | initRenderThread(); 51 | internalSurfaceCreated(holder); 52 | 53 | } 54 | 55 | @Override 56 | public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { 57 | internalSurfaceChanged(width, height); 58 | 59 | } 60 | 61 | @Override 62 | public void surfaceDestroyed(SurfaceHolder holder) { 63 | internalSurfaceDestroyed(); 64 | } 65 | 66 | @Override 67 | public void onFrameAvailable(SurfaceTexture surfaceTexture) { 68 | requestRender(); 69 | } 70 | 71 | /** 72 | * 初始化渲染线程 73 | */ 74 | private void initRenderThread() { 75 | mRenderThread = new HandlerThread("RenderThread"); 76 | mRenderThread.start(); 77 | mRenderHandler = new Handler(mRenderThread.getLooper()); 78 | } 79 | 80 | /** 81 | * 创建Surface 82 | */ 83 | private void internalSurfaceCreated(final SurfaceHolder holder) { 84 | mRenderHandler.post(new Runnable() { 85 | @Override 86 | public void run() { 87 | onSurfaceCreated(holder); 88 | } 89 | }); 90 | } 91 | 92 | /** 93 | * Surface改变 94 | * @param width 95 | * @param height 96 | */ 97 | private void internalSurfaceChanged(final int width, final int height) { 98 | mRenderHandler.post(new Runnable() { 99 | @Override 100 | public void run() { 101 | onSurfaceChanged(width, height); 102 | } 103 | }); 104 | } 105 | 106 | /** 107 | * 销毁Surface 108 | */ 109 | private void internalSurfaceDestroyed() { 110 | mRenderHandler.post(new Runnable() { 111 | @Override 112 | public void run() { 113 | onSurfaceDestroyed(); 114 | } 115 | }); 116 | } 117 | 118 | /** 119 | * 请求渲染 120 | */ 121 | private void requestRender() { 122 | Log.d(TAG, "requestRender: "); 123 | mRenderHandler.post(new Runnable() { 124 | @Override 125 | public void run() { 126 | 127 | onDrawFrame(); 128 | } 129 | }); 130 | } 131 | 132 | // ------------------ 渲染过程 -------------------------------------------------- 133 | 134 | private EglCore mEglCore; 135 | private WindowSurface mDisplaySurface; 136 | private int mInputTextureId; 137 | private SurfaceTexture mSurfaceTexture; 138 | private Surface mSurface; 139 | 140 | // 矩阵 141 | private final float[] mMatrix = new float[16]; 142 | private OESInputFilter mOESInputFilter; 143 | 144 | private void onSurfaceCreated(SurfaceHolder holder) { 145 | mEglCore = new EglCore(null, EglCore.FLAG_RECORDABLE); 146 | mDisplaySurface = new WindowSurface(mEglCore, holder.getSurface(), false); 147 | mDisplaySurface.makeCurrent(); 148 | mOESInputFilter = new OESInputFilter(Main3Activity.this); 149 | mOESInputFilter.onInputSizeChanged(1080, 1920); 150 | mOESInputFilter.onDisplayChanged(1080, 1920); 151 | 152 | mInputTextureId = GlUtil.createTextureOES(); 153 | mSurfaceTexture = new SurfaceTexture(mInputTextureId); 154 | mSurfaceTexture.setDefaultBufferSize(1090, 1920); 155 | mSurfaceTexture.setOnFrameAvailableListener(this); 156 | mSurface = new Surface(mSurfaceTexture); 157 | mRender.surfaceCreated(mSurface); 158 | } 159 | 160 | private void onSurfaceChanged(int width, int height) { 161 | mOESInputFilter.updateTextureBuffer(); 162 | mRender.surfaceChanged(width, height); 163 | } 164 | 165 | private void onSurfaceDestroyed() { 166 | if (mOESInputFilter != null) { 167 | mOESInputFilter.release(); 168 | mOESInputFilter = null; 169 | } 170 | if (mSurfaceTexture != null) { 171 | mSurfaceTexture.release(); 172 | mSurfaceTexture = null; 173 | } 174 | 175 | if (mDisplaySurface != null) { 176 | mDisplaySurface.release(); 177 | mDisplaySurface = null; 178 | } 179 | 180 | if (mEglCore != null) { 181 | mEglCore.release(); 182 | mEglCore = null; 183 | } 184 | 185 | mRender.surfaceDestroyed(); 186 | } 187 | 188 | private void onDrawFrame() { 189 | if (mSurfaceTexture == null) { 190 | return; 191 | } 192 | mSurfaceTexture.updateTexImage(); 193 | mDisplaySurface.makeCurrent(); 194 | mSurfaceTexture.getTransformMatrix(mMatrix); 195 | if (mOESInputFilter != null) { 196 | mOESInputFilter.setTextureTransformMatirx(mMatrix); 197 | // 绘制渲染 198 | GLES30.glViewport(0, 0, 1080, 1920); 199 | mOESInputFilter.drawFrame(mInputTextureId); 200 | } 201 | mDisplaySurface.swapBuffers(); 202 | } 203 | } 204 | -------------------------------------------------------------------------------- /app/src/main/java/com/cgfay/eglnativerender/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.cgfay.eglnativerender; 2 | 3 | import android.support.v7.app.AppCompatActivity; 4 | import android.os.Bundle; 5 | import android.view.Surface; 6 | import android.view.SurfaceHolder; 7 | import android.view.SurfaceView; 8 | import android.widget.TextView; 9 | 10 | public class MainActivity extends AppCompatActivity implements SurfaceHolder.Callback { 11 | 12 | private SurfaceView mSurfaceView; 13 | 14 | private EGLRender mRender; 15 | 16 | @Override 17 | protected void onCreate(Bundle savedInstanceState) { 18 | super.onCreate(savedInstanceState); 19 | setContentView(R.layout.activity_main); 20 | mRender = new EGLRender(); 21 | mRender.init(); 22 | mSurfaceView = (SurfaceView) findViewById(R.id.surface_view); 23 | mSurfaceView.getHolder().addCallback(this); 24 | } 25 | 26 | 27 | @Override 28 | protected void onDestroy() { 29 | mRender.release(); 30 | mRender = null; 31 | super.onDestroy(); 32 | } 33 | 34 | @Override 35 | public void surfaceCreated(SurfaceHolder holder) { 36 | mRender.surfaceCreated(holder.getSurface()); 37 | } 38 | 39 | @Override 40 | public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { 41 | mRender.surfaceChanged(width, height); 42 | } 43 | 44 | @Override 45 | public void surfaceDestroyed(SurfaceHolder holder) { 46 | mRender.surfaceDestroyed(); 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /app/src/main/java/com/cgfay/eglnativerender/filter/BaseImageFilter.java: -------------------------------------------------------------------------------- 1 | package com.cgfay.eglnativerender.filter; 2 | 3 | import android.content.Context; 4 | import android.graphics.PointF; 5 | import android.opengl.GLES30; 6 | import android.opengl.Matrix; 7 | import android.text.TextUtils; 8 | import android.util.Log; 9 | 10 | import com.cgfay.eglnativerender.utils.GlUtil; 11 | import com.cgfay.eglnativerender.utils.TextureRotationUtils; 12 | 13 | import java.nio.FloatBuffer; 14 | import java.util.Arrays; 15 | import java.util.LinkedList; 16 | 17 | /** 18 | * 基类滤镜 19 | * Created by cain on 2017/7/9. 20 | */ 21 | 22 | public class BaseImageFilter { 23 | 24 | protected final String TAG = getClass().getCanonicalName(); 25 | 26 | protected static final String VERTEX_SHADER = 27 | "uniform mat4 uMVPMatrix; \n" + 28 | "uniform mat4 uTexMatrix; \n" + 29 | "attribute vec4 aPosition; \n" + 30 | "attribute vec4 aTextureCoord; \n" + 31 | "varying vec2 textureCoordinate; \n" + 32 | "void main() { \n" + 33 | " gl_Position = uMVPMatrix * aPosition; \n" + 34 | " textureCoordinate =(uTexMatrix * aTextureCoord).xy; \n" + 35 | "} \n"; 36 | 37 | protected static final String FRAGMENT_SHADER_2D = 38 | "precision mediump float; \n" + 39 | "varying vec2 textureCoordinate; \n" + 40 | "uniform sampler2D inputTexture; \n" + 41 | "void main() { \n" + 42 | " gl_FragColor = texture2D(inputTexture, textureCoordinate); \n" + 43 | "} \n"; 44 | 45 | protected static final int SIZEOF_FLOAT = 4; 46 | 47 | protected static final int CoordsPerTexture = 2; 48 | 49 | private static final FloatBuffer FULL_RECTANGLE_BUF = 50 | GlUtil.createFloatBuffer(TextureRotationUtils.CubeVertices); 51 | 52 | protected FloatBuffer mVertexBuffer = FULL_RECTANGLE_BUF; 53 | protected FloatBuffer mTextureBuffer = GlUtil.createFloatBuffer(TextureRotationUtils.TextureVertices); 54 | protected int mCoordsPerVertex = TextureRotationUtils.CoordsPerVertex; 55 | protected int mVertexStride = mCoordsPerVertex * SIZEOF_FLOAT; 56 | protected int mVertexCount = TextureRotationUtils.CubeVertices.length / mCoordsPerVertex; 57 | protected int mTexCoordStride = CoordsPerTexture * SIZEOF_FLOAT; 58 | 59 | protected int mProgramHandle; 60 | protected int muMVPMatrixLoc; 61 | protected int maPositionLoc; 62 | protected int maTextureCoordLoc; 63 | protected int mInputTextureLoc; 64 | protected int mTexMatrixLoc; 65 | 66 | // 渲染的Image的宽高 67 | protected int mImageWidth; 68 | protected int mImageHeight; 69 | // 显示输出的宽高 70 | protected int mDisplayWidth; 71 | protected int mDisplayHeight; 72 | 73 | // --- 视锥体属性 start --- 74 | // 视图矩阵 75 | protected float[] mViewMatrix = new float[16]; 76 | // 投影矩阵 77 | protected float[] mProjectionMatrix = new float[16]; 78 | // 模型矩阵 79 | protected float[] mModelMatrix = new float[16]; 80 | // 变换矩阵 81 | protected float[] mMVPMatrix = new float[16]; 82 | // 缩放矩阵 83 | protected float[] mTexMatrix = new float[16]; 84 | // 模型矩阵欧拉角的实际角度 85 | protected float mYawAngle = 0.0f; 86 | protected float mPitchAngle = 0.0f; 87 | protected float mRollAngle = 0.0f; 88 | // --- 视锥体属性 end --- 89 | 90 | private final LinkedList mRunOnDraw; 91 | 92 | // 上下文 93 | protected Context mContext; 94 | 95 | // FBO属性 96 | protected int[] mFramebuffers; 97 | protected int[] mFramebufferTextures; 98 | protected int mFrameWidth = -1; 99 | protected int mFrameHeight = -1; 100 | 101 | public BaseImageFilter(Context context) { 102 | this(context, VERTEX_SHADER, FRAGMENT_SHADER_2D); 103 | } 104 | 105 | public BaseImageFilter(Context context, String vertexShader, String fragmentShader) { 106 | mContext = context; 107 | mRunOnDraw = new LinkedList<>(); 108 | // 需要检查vertex/fragment shader是否不为空, 构建滤镜组需要用到这个 109 | if (!TextUtils.isEmpty(vertexShader) && !TextUtils.isEmpty(fragmentShader)) { 110 | mProgramHandle = GlUtil.createProgram(vertexShader, fragmentShader); 111 | maPositionLoc = GLES30.glGetAttribLocation(mProgramHandle, "aPosition"); 112 | maTextureCoordLoc = GLES30.glGetAttribLocation(mProgramHandle, "aTextureCoord"); 113 | muMVPMatrixLoc = GLES30.glGetUniformLocation(mProgramHandle, "uMVPMatrix"); 114 | mInputTextureLoc = GLES30.glGetUniformLocation(mProgramHandle, "inputTexture"); 115 | mTexMatrixLoc = GLES30.glGetUniformLocation(mProgramHandle, "uTexMatrix"); 116 | } else { 117 | mProgramHandle = -1; 118 | maPositionLoc = -1; 119 | maTextureCoordLoc = -1; 120 | muMVPMatrixLoc = -1; 121 | mInputTextureLoc = -1; 122 | mTexMatrixLoc = -1; 123 | } 124 | initIdentityMatrix(); 125 | } 126 | 127 | /** 128 | * Surface发生变化时调用 129 | * @param width 130 | * @param height 131 | */ 132 | public void onInputSizeChanged(int width, int height) { 133 | mImageWidth = width; 134 | mImageHeight = height; 135 | Log.d(TAG, "onInputSizeChanged: width = " + width + ", height = " + height); 136 | } 137 | 138 | /** 139 | * 显示视图发生变化时调用 140 | * @param width 141 | * @param height 142 | */ 143 | public void onDisplayChanged(int width, int height) { 144 | mDisplayWidth = width; 145 | mDisplayHeight = height; 146 | Log.d(TAG, "onDisplayChanged: width = " + width + ", height = " + height); 147 | } 148 | 149 | /** 150 | * 绘制Frame 151 | * @param textureId 152 | */ 153 | public boolean drawFrame(int textureId) { 154 | return drawFrame(textureId, mVertexBuffer, mTextureBuffer); 155 | } 156 | 157 | /** 158 | * 绘制Frame 159 | * @param textureId 160 | * @param vertexBuffer 161 | * @param textureBuffer 162 | */ 163 | public boolean drawFrame(int textureId, FloatBuffer vertexBuffer, 164 | FloatBuffer textureBuffer) { 165 | if (textureId == GlUtil.GL_NOT_INIT) { 166 | return false; 167 | } 168 | 169 | GLES30.glUseProgram(mProgramHandle); 170 | runPendingOnDrawTasks(); 171 | 172 | vertexBuffer.position(0); 173 | GLES30.glVertexAttribPointer(maPositionLoc, mCoordsPerVertex, 174 | GLES30.GL_FLOAT, false, 0, vertexBuffer); 175 | GLES30.glEnableVertexAttribArray(maPositionLoc); 176 | 177 | textureBuffer.position(0); 178 | GLES30.glVertexAttribPointer(maTextureCoordLoc, 2, 179 | GLES30.GL_FLOAT, false, 0, textureBuffer); 180 | GLES30.glEnableVertexAttribArray(maTextureCoordLoc); 181 | 182 | GLES30.glUniformMatrix4fv(muMVPMatrixLoc, 1, false, mMVPMatrix, 0); 183 | GLES30.glUniformMatrix4fv(mTexMatrixLoc, 1, false, mTexMatrix, 0); 184 | 185 | GLES30.glActiveTexture(GLES30.GL_TEXTURE0); 186 | GLES30.glBindTexture(getTextureType(), textureId); 187 | GLES30.glUniform1i(mInputTextureLoc, 0); 188 | 189 | onDrawArraysBegin(); 190 | 191 | GLES30.glDrawArrays(GLES30.GL_TRIANGLE_STRIP, 0, mVertexCount); 192 | 193 | onDrawArraysAfter(); 194 | GLES30.glDisableVertexAttribArray(maPositionLoc); 195 | GLES30.glDisableVertexAttribArray(maTextureCoordLoc); 196 | GLES30.glBindTexture(getTextureType(), 0); 197 | GLES30.glUseProgram(0); 198 | 199 | return true; 200 | } 201 | 202 | /** 203 | * 绘制到FBO 204 | * @param textureId 205 | * @return FBO绑定的Texture 206 | */ 207 | public int drawFrameBuffer(int textureId) { 208 | return drawFrameBuffer(textureId, mVertexBuffer, mTextureBuffer); 209 | } 210 | 211 | /** 212 | * 绘制到FBO 213 | * @param textureId 214 | * @param vertexBuffer 215 | * @param textureBuffer 216 | * @return FBO绑定的Texture 217 | */ 218 | public int drawFrameBuffer(int textureId, FloatBuffer vertexBuffer, FloatBuffer textureBuffer) { 219 | if (mFramebuffers == null) { 220 | return GlUtil.GL_NOT_INIT; 221 | } 222 | runPendingOnDrawTasks(); 223 | GLES30.glViewport(0, 0, mFrameWidth, mFrameHeight); 224 | GLES30.glBindFramebuffer(GLES30.GL_FRAMEBUFFER, mFramebuffers[0]); 225 | GLES30.glUseProgram(mProgramHandle); 226 | vertexBuffer.position(0); 227 | GLES30.glVertexAttribPointer(maPositionLoc, mCoordsPerVertex, 228 | GLES30.GL_FLOAT, false, 0, vertexBuffer); 229 | GLES30.glEnableVertexAttribArray(maPositionLoc); 230 | 231 | textureBuffer.position(0); 232 | GLES30.glVertexAttribPointer(maTextureCoordLoc, 2, 233 | GLES30.GL_FLOAT, false, 0, textureBuffer); 234 | GLES30.glEnableVertexAttribArray(maTextureCoordLoc); 235 | 236 | GLES30.glUniformMatrix4fv(muMVPMatrixLoc, 1, false, mMVPMatrix, 0); 237 | GLES30.glUniformMatrix4fv(mTexMatrixLoc, 1, false, mTexMatrix, 0); 238 | GLES30.glActiveTexture(GLES30.GL_TEXTURE0); 239 | GLES30.glBindTexture(getTextureType(), textureId); 240 | GLES30.glUniform1i(mInputTextureLoc, 0); 241 | onDrawArraysBegin(); 242 | GLES30.glDrawArrays(GLES30.GL_TRIANGLE_STRIP, 0, mVertexCount); 243 | onDrawArraysAfter(); 244 | GLES30.glDisableVertexAttribArray(maPositionLoc); 245 | GLES30.glDisableVertexAttribArray(maTextureCoordLoc); 246 | GLES30.glBindTexture(getTextureType(), 0); 247 | GLES30.glUseProgram(0); 248 | GLES30.glBindFramebuffer(GLES30.GL_FRAMEBUFFER, 0); 249 | GLES30.glViewport(0, 0, mDisplayWidth, mDisplayHeight); 250 | return mFramebufferTextures[0]; 251 | } 252 | 253 | /** 254 | * 获取Texture类型 255 | * GLES30.TEXTURE_2D / GLES11Ext.GL_TEXTURE_EXTERNAL_OES等 256 | */ 257 | public int getTextureType() { 258 | return GLES30.GL_TEXTURE_2D; 259 | } 260 | 261 | /** 262 | * 调用drawArrays之前,方便添加其他属性 263 | */ 264 | public void onDrawArraysBegin() { 265 | 266 | } 267 | 268 | /** 269 | * drawArrays调用之后,方便销毁其他属性 270 | */ 271 | public void onDrawArraysAfter() { 272 | 273 | } 274 | 275 | /** 276 | * 释放资源 277 | */ 278 | public void release() { 279 | GLES30.glDeleteProgram(mProgramHandle); 280 | mProgramHandle = -1; 281 | destroyFramebuffer(); 282 | } 283 | 284 | public void initFramebuffer(int width, int height) { 285 | if (mFramebuffers != null && (mFrameWidth != width || mFrameHeight != height)) { 286 | destroyFramebuffer(); 287 | } 288 | if (mFramebuffers == null) { 289 | mFrameWidth = width; 290 | mFrameHeight = height; 291 | mFramebuffers = new int[1]; 292 | mFramebufferTextures = new int[1]; 293 | GlUtil.createSampler2DFrameBuff(mFramebuffers, mFramebufferTextures, width, height); 294 | } 295 | } 296 | 297 | public void destroyFramebuffer() { 298 | if (mFramebufferTextures != null) { 299 | GLES30.glDeleteTextures(1, mFramebufferTextures, 0); 300 | mFramebufferTextures = null; 301 | } 302 | 303 | if (mFramebuffers != null) { 304 | GLES30.glDeleteFramebuffers(1, mFramebuffers, 0); 305 | mFramebuffers = null; 306 | } 307 | mImageWidth = -1; 308 | mImageHeight = -1; 309 | } 310 | 311 | /** 312 | * 获取当前FBO绑定的结果 313 | * @return 314 | */ 315 | public int getCurrentFrameBufferTexture() { 316 | if (mFramebuffers == null) { 317 | return -1; 318 | } 319 | return mFramebufferTextures[0]; 320 | } 321 | ///---------------------- 计算视锥体矩阵变换 ---------------------------------/// 322 | /** 323 | * 初始化单位矩阵 324 | */ 325 | public void initIdentityMatrix() { 326 | Matrix.setIdentityM(mViewMatrix, 0); 327 | Matrix.setIdentityM(mProjectionMatrix, 0); 328 | Matrix.setIdentityM(mModelMatrix, 0); 329 | Matrix.setIdentityM(mMVPMatrix, 0); 330 | Matrix.setIdentityM(mTexMatrix, 0); 331 | } 332 | 333 | /** 334 | * 计算视锥体变换矩阵(MVPMatrix) 335 | */ 336 | protected void calculateMVPMatrix() { 337 | // 模型矩阵变换 338 | Matrix.setIdentityM(mModelMatrix, 0); // 重置模型矩阵方便计算 339 | Matrix.rotateM(mModelMatrix, 0, mYawAngle, 1.0f, 0, 0); 340 | Matrix.rotateM(mModelMatrix, 0, mPitchAngle, 0, 1.0f, 0); 341 | Matrix.rotateM(mModelMatrix, 0, mRollAngle, 0, 0, 1.0f); 342 | // 综合矩阵变换 343 | Matrix.multiplyMM(mMVPMatrix, 0, mViewMatrix, 0, mModelMatrix, 0); 344 | Matrix.multiplyMM(mMVPMatrix, 0, mProjectionMatrix, 0, mMVPMatrix, 0); 345 | } 346 | 347 | /** 348 | * 设置投影矩阵 349 | * @param matrix 350 | */ 351 | public void setViewMatrix(float[] matrix) { 352 | if (Arrays.equals(mViewMatrix, matrix)) { 353 | mViewMatrix = matrix; 354 | } 355 | } 356 | 357 | /** 358 | * 设置投影矩阵 359 | * @param matrix 360 | */ 361 | public void setProjectionMatrix(float[] matrix) { 362 | if (Arrays.equals(mProjectionMatrix, matrix)) { 363 | mProjectionMatrix = matrix; 364 | } 365 | } 366 | 367 | /** 368 | * 设置模型矩阵 369 | * @param matrix 370 | */ 371 | public void setModelMatrix(float[] matrix) { 372 | if (Arrays.equals(mModelMatrix, matrix)) { 373 | mModelMatrix = matrix; 374 | } 375 | } 376 | 377 | /** 378 | * 设置变换矩阵 379 | * @param matrix 380 | */ 381 | public void setMVPMatrix(float[] matrix) { 382 | if (!Arrays.equals(mMVPMatrix, matrix)) { 383 | mMVPMatrix = matrix; 384 | } 385 | } 386 | 387 | /** 388 | * 设置Texture缩放矩阵 389 | * @param matrix 390 | */ 391 | public void setTexMatrix(float[] matrix) { 392 | 393 | } 394 | 395 | /** 396 | * 模型矩阵 X轴旋转角度(0 ~ 360) 397 | * @param angle 398 | */ 399 | public void setModelYawAngle(float angle) { 400 | if (mYawAngle != angle) { 401 | mYawAngle = angle; 402 | } 403 | } 404 | 405 | /** 406 | * 模型矩阵 Y轴旋转角度(0 ~ 360) 407 | * @param angle 408 | */ 409 | public void setModelPitchAngle(float angle) { 410 | if (mPitchAngle != angle) { 411 | mPitchAngle = angle; 412 | } 413 | } 414 | 415 | /** 416 | * 模型矩阵 Z轴旋转角度(0 ~ 360) 417 | * @param angle 418 | */ 419 | public void setModelRollAngle(float angle) { 420 | if (mRollAngle != angle) { 421 | mRollAngle = angle; 422 | } 423 | } 424 | 425 | ///------------------ 统一变量(uniform)设置 ------------------------/// 426 | protected void setInteger(final int location, final int intValue) { 427 | runOnDraw(new Runnable() { 428 | @Override 429 | public void run() { 430 | GLES30.glUniform1i(location, intValue); 431 | } 432 | }); 433 | } 434 | 435 | protected void setFloat(final int location, final float floatValue) { 436 | runOnDraw(new Runnable() { 437 | @Override 438 | public void run() { 439 | GLES30.glUniform1f(location, floatValue); 440 | } 441 | }); 442 | } 443 | 444 | protected void setFloatVec2(final int location, final float[] arrayValue) { 445 | runOnDraw(new Runnable() { 446 | @Override 447 | public void run() { 448 | GLES30.glUniform2fv(location, 1, FloatBuffer.wrap(arrayValue)); 449 | } 450 | }); 451 | } 452 | 453 | protected void setFloatVec3(final int location, final float[] arrayValue) { 454 | runOnDraw(new Runnable() { 455 | @Override 456 | public void run() { 457 | GLES30.glUniform3fv(location, 1, FloatBuffer.wrap(arrayValue)); 458 | } 459 | }); 460 | } 461 | 462 | protected void setFloatVec4(final int location, final float[] arrayValue) { 463 | runOnDraw(new Runnable() { 464 | @Override 465 | public void run() { 466 | GLES30.glUniform4fv(location, 1, FloatBuffer.wrap(arrayValue)); 467 | } 468 | }); 469 | } 470 | 471 | protected void setFloatArray(final int location, final float[] arrayValue) { 472 | runOnDraw(new Runnable() { 473 | @Override 474 | public void run() { 475 | GLES30.glUniform1fv(location, arrayValue.length, FloatBuffer.wrap(arrayValue)); 476 | } 477 | }); 478 | } 479 | 480 | protected void setPoint(final int location, final PointF point) { 481 | runOnDraw(new Runnable() { 482 | 483 | @Override 484 | public void run() { 485 | float[] vec2 = new float[2]; 486 | vec2[0] = point.x; 487 | vec2[1] = point.y; 488 | GLES30.glUniform2fv(location, 1, vec2, 0); 489 | } 490 | }); 491 | } 492 | 493 | protected void setUniformMatrix3f(final int location, final float[] matrix) { 494 | runOnDraw(new Runnable() { 495 | 496 | @Override 497 | public void run() { 498 | GLES30.glUniformMatrix3fv(location, 1, false, matrix, 0); 499 | } 500 | }); 501 | } 502 | 503 | protected void setUniformMatrix4f(final int location, final float[] matrix) { 504 | runOnDraw(new Runnable() { 505 | 506 | @Override 507 | public void run() { 508 | GLES30.glUniformMatrix4fv(location, 1, false, matrix, 0); 509 | } 510 | }); 511 | } 512 | 513 | protected void runOnDraw(final Runnable runnable) { 514 | synchronized (mRunOnDraw) { 515 | mRunOnDraw.addLast(runnable); 516 | } 517 | } 518 | 519 | protected void runPendingOnDrawTasks() { 520 | while (!mRunOnDraw.isEmpty()) { 521 | mRunOnDraw.removeFirst().run(); 522 | } 523 | } 524 | } 525 | -------------------------------------------------------------------------------- /app/src/main/java/com/cgfay/eglnativerender/filter/DisplayFilter.java: -------------------------------------------------------------------------------- 1 | package com.cgfay.eglnativerender.filter; 2 | 3 | import android.content.Context; 4 | 5 | /** 6 | * 预览的滤镜 7 | * Created by cain.huang on 2017/9/29. 8 | */ 9 | public class DisplayFilter extends BaseImageFilter { 10 | 11 | public DisplayFilter(Context context) { 12 | this(context, VERTEX_SHADER, FRAGMENT_SHADER_2D); 13 | } 14 | 15 | public DisplayFilter(Context context, String vertexShader, String fragmentShader) { 16 | super(context, vertexShader, fragmentShader); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /app/src/main/java/com/cgfay/eglnativerender/filter/OESInputFilter.java: -------------------------------------------------------------------------------- 1 | package com.cgfay.eglnativerender.filter; 2 | 3 | import android.content.Context; 4 | import android.opengl.GLES11Ext; 5 | import android.opengl.GLES30; 6 | import android.opengl.Matrix; 7 | 8 | import com.cgfay.eglnativerender.utils.TextureRotationUtils; 9 | 10 | 11 | /** 12 | * Created by cain on 2017/7/9. 13 | */ 14 | 15 | public class OESInputFilter extends BaseImageFilter { 16 | private static final String VERTEX_SHADER = 17 | "uniform mat4 uMVPMatrix; \n" + 18 | "uniform mat4 uTexMatrix; \n" + 19 | "attribute vec4 aPosition; \n" + 20 | "attribute vec4 aTextureCoord; \n" + 21 | "varying vec2 textureCoordinate; \n" + 22 | "void main() { \n" + 23 | " gl_Position = uMVPMatrix * aPosition; \n" + 24 | " textureCoordinate = (uTexMatrix * aTextureCoord).xy; \n" + 25 | "} \n"; 26 | 27 | // 备注: samplerExternalOES 格式是相机流的数据,跟渲染后的texture格式不一样 28 | // 相机流的数据经过渲染后得到的texture格式是sampler2D的 29 | private static final String FRAGMENT_SHADER_OES = 30 | "#extension GL_OES_EGL_image_external : require \n" + 31 | "precision mediump float; \n" + 32 | "varying vec2 textureCoordinate; \n" + 33 | "uniform samplerExternalOES inputTexture; \n" + 34 | "void main() { \n" + 35 | " gl_FragColor = texture2D(inputTexture, textureCoordinate); \n" + 36 | "} \n"; 37 | 38 | 39 | private int muTexMatrixLoc; 40 | private float[] mTextureMatrix; 41 | 42 | public OESInputFilter(Context context) { 43 | this(context, VERTEX_SHADER, FRAGMENT_SHADER_OES); 44 | } 45 | 46 | public OESInputFilter(Context context, String vertexShader, String fragmentShader) { 47 | super(context, vertexShader, fragmentShader); 48 | muTexMatrixLoc = GLES30.glGetUniformLocation(mProgramHandle, "uTexMatrix"); 49 | // 视图矩阵 50 | Matrix.setLookAtM(mViewMatrix, 0, 0, 0, -1, 0f, 0f, 0f, 0f, 1f, 0f); 51 | } 52 | 53 | @Override 54 | public void onInputSizeChanged(int width, int height) { 55 | super.onInputSizeChanged(width, height); 56 | float aspect = (float) width / height; // 计算宽高比 57 | Matrix.perspectiveM(mProjectionMatrix, 0, 60, aspect, 2, 10); 58 | } 59 | 60 | @Override 61 | public int getTextureType() { 62 | return GLES11Ext.GL_TEXTURE_EXTERNAL_OES; 63 | } 64 | 65 | @Override 66 | public void onDrawArraysBegin() { 67 | GLES30.glUniformMatrix4fv(muTexMatrixLoc, 1, false, mTextureMatrix, 0); 68 | } 69 | 70 | public void updateTextureBuffer() { 71 | mTextureBuffer = TextureRotationUtils.getTextureBuffer(); 72 | } 73 | 74 | /** 75 | * 设置SurfaceTexture的变换矩阵 76 | * @param texMatrix 77 | */ 78 | public void setTextureTransformMatirx(float[] texMatrix) { 79 | mTextureMatrix = texMatrix; 80 | } 81 | 82 | /** 83 | * 镜像翻转 84 | * @param coords 85 | * @param matrix 86 | * @return 87 | */ 88 | private float[] transformTextureCoordinates(float[] coords, float[] matrix) { 89 | float[] result = new float[coords.length]; 90 | float[] vt = new float[4]; 91 | 92 | for (int i = 0; i < coords.length; i += 2) { 93 | float[] v = { coords[i], coords[i + 1], 0, 1 }; 94 | Matrix.multiplyMV(vt, 0, matrix, 0, v, 0); 95 | result[i] = vt[0];// x轴镜像 96 | // result[i + 1] = vt[1];y轴镜像 97 | result[i + 1] = coords[i + 1]; 98 | } 99 | return result; 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /app/src/main/java/com/cgfay/eglnativerender/gles/EglCore.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 Google Inc. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.cgfay.eglnativerender.gles; 18 | 19 | import android.graphics.SurfaceTexture; 20 | import android.opengl.EGL14; 21 | import android.opengl.EGLConfig; 22 | import android.opengl.EGLContext; 23 | import android.opengl.EGLDisplay; 24 | import android.opengl.EGLExt; 25 | import android.opengl.EGLSurface; 26 | import android.util.Log; 27 | import android.view.Surface; 28 | 29 | /** 30 | * Core EGL state (display, context, config). 31 | *

32 | * The EGLContext must only be attached to one thread at a time. This class is not thread-safe. 33 | */ 34 | public final class EglCore { 35 | private static final String TAG = "EGLCore"; 36 | 37 | /** 38 | * Constructor flag: surface must be recordable. This discourages EGL from using a 39 | * pixel format that cannot be converted efficiently to something usable by the video 40 | * encoder. 41 | */ 42 | public static final int FLAG_RECORDABLE = 0x01; 43 | 44 | /** 45 | * Constructor flag: ask for GLES3, fall back to GLES2 if not available. Without this 46 | * flag, GLES2 is used. 47 | */ 48 | public static final int FLAG_TRY_GLES3 = 0x02; 49 | 50 | // Android-specific extension. 51 | private static final int EGL_RECORDABLE_ANDROID = 0x3142; 52 | 53 | private EGLDisplay mEGLDisplay = EGL14.EGL_NO_DISPLAY; 54 | private EGLContext mEGLContext = EGL14.EGL_NO_CONTEXT; 55 | private EGLConfig mEGLConfig = null; 56 | private int mGlVersion = -1; 57 | 58 | 59 | /** 60 | * Prepares EGL display and context. 61 | *

62 | * Equivalent to EglCore(null, 0). 63 | */ 64 | public EglCore() { 65 | this(null, 0); 66 | } 67 | 68 | /** 69 | * Prepares EGL display and context. 70 | *

71 | * @param sharedContext The context to share, or null if sharing is not desired. 72 | * @param flags Configuration bit flags, e.g. FLAG_RECORDABLE. 73 | */ 74 | public EglCore(EGLContext sharedContext, int flags) { 75 | if (mEGLDisplay != EGL14.EGL_NO_DISPLAY) { 76 | throw new RuntimeException("EGL already set up"); 77 | } 78 | 79 | if (sharedContext == null) { 80 | sharedContext = EGL14.EGL_NO_CONTEXT; 81 | } 82 | 83 | mEGLDisplay = EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY); 84 | if (mEGLDisplay == EGL14.EGL_NO_DISPLAY) { 85 | throw new RuntimeException("unable to get EGL14 display"); 86 | } 87 | int[] version = new int[2]; 88 | if (!EGL14.eglInitialize(mEGLDisplay, version, 0, version, 1)) { 89 | mEGLDisplay = null; 90 | throw new RuntimeException("unable to initialize EGL14"); 91 | } 92 | 93 | // Try to get a GLES3 context, if requested. 94 | if ((flags & FLAG_TRY_GLES3) != 0) { 95 | //Log.d(TAG, "Trying GLES 3"); 96 | EGLConfig config = getConfig(flags, 3); 97 | if (config != null) { 98 | int[] attrib3_list = { 99 | EGL14.EGL_CONTEXT_CLIENT_VERSION, 3, 100 | EGL14.EGL_NONE 101 | }; 102 | EGLContext context = EGL14.eglCreateContext(mEGLDisplay, config, sharedContext, 103 | attrib3_list, 0); 104 | 105 | if (EGL14.eglGetError() == EGL14.EGL_SUCCESS) { 106 | //Log.d(TAG, "Got GLES 3 config"); 107 | mEGLConfig = config; 108 | mEGLContext = context; 109 | mGlVersion = 3; 110 | } 111 | } 112 | } 113 | if (mEGLContext == EGL14.EGL_NO_CONTEXT) { // GLES 2 only, or GLES 3 attempt failed 114 | //Log.d(TAG, "Trying GLES 2"); 115 | EGLConfig config = getConfig(flags, 2); 116 | if (config == null) { 117 | throw new RuntimeException("Unable to find a suitable EGLConfig"); 118 | } 119 | int[] attrib2_list = { 120 | EGL14.EGL_CONTEXT_CLIENT_VERSION, 2, 121 | EGL14.EGL_NONE 122 | }; 123 | EGLContext context = EGL14.eglCreateContext(mEGLDisplay, config, sharedContext, 124 | attrib2_list, 0); 125 | checkEglError("eglCreateContext"); 126 | mEGLConfig = config; 127 | mEGLContext = context; 128 | mGlVersion = 2; 129 | } 130 | 131 | // Confirm with query. 132 | int[] values = new int[1]; 133 | EGL14.eglQueryContext(mEGLDisplay, mEGLContext, EGL14.EGL_CONTEXT_CLIENT_VERSION, 134 | values, 0); 135 | Log.d(TAG, "EGLContext created, client version " + values[0]); 136 | } 137 | 138 | /** 139 | * Finds a suitable EGLConfig. 140 | * 141 | * @param flags Bit flags from constructor. 142 | * @param version Must be 2 or 3. 143 | */ 144 | private EGLConfig getConfig(int flags, int version) { 145 | int renderableType = EGL14.EGL_OPENGL_ES2_BIT; 146 | if (version >= 3) { 147 | renderableType |= EGLExt.EGL_OPENGL_ES3_BIT_KHR; 148 | } 149 | 150 | // The actual surface is generally RGBA or RGBX, so situationally omitting alpha 151 | // doesn't really help. It can also lead to a huge performance hit on glReadPixels() 152 | // when reading into a GL_RGBA buffer. 153 | int[] attribList = { 154 | EGL14.EGL_RED_SIZE, 8, 155 | EGL14.EGL_GREEN_SIZE, 8, 156 | EGL14.EGL_BLUE_SIZE, 8, 157 | EGL14.EGL_ALPHA_SIZE, 8, 158 | //EGL14.EGL_DEPTH_SIZE, 16, 159 | //EGL14.EGL_STENCIL_SIZE, 8, 160 | EGL14.EGL_RENDERABLE_TYPE, renderableType, 161 | EGL14.EGL_NONE, 0, // placeholder for recordable [@-3] 162 | EGL14.EGL_NONE 163 | }; 164 | if ((flags & FLAG_RECORDABLE) != 0) { 165 | attribList[attribList.length - 3] = EGL_RECORDABLE_ANDROID; 166 | attribList[attribList.length - 2] = 1; 167 | } 168 | EGLConfig[] configs = new EGLConfig[1]; 169 | int[] numConfigs = new int[1]; 170 | if (!EGL14.eglChooseConfig(mEGLDisplay, attribList, 0, configs, 0, configs.length, 171 | numConfigs, 0)) { 172 | Log.w(TAG, "unable to find RGB8888 / " + version + " EGLConfig"); 173 | return null; 174 | } 175 | return configs[0]; 176 | } 177 | 178 | /** 179 | * Discards all resources held by this class, notably the EGL context. This must be 180 | * called from the thread where the context was created. 181 | *

182 | * On completion, no context will be current. 183 | */ 184 | public void release() { 185 | if (mEGLDisplay != EGL14.EGL_NO_DISPLAY) { 186 | // Android is unusual in that it uses a reference-counted EGLDisplay. So for 187 | // every eglInitialize() we need an eglTerminate(). 188 | EGL14.eglMakeCurrent(mEGLDisplay, EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_SURFACE, 189 | EGL14.EGL_NO_CONTEXT); 190 | EGL14.eglDestroyContext(mEGLDisplay, mEGLContext); 191 | EGL14.eglReleaseThread(); 192 | EGL14.eglTerminate(mEGLDisplay); 193 | } 194 | 195 | mEGLDisplay = EGL14.EGL_NO_DISPLAY; 196 | mEGLContext = EGL14.EGL_NO_CONTEXT; 197 | mEGLConfig = null; 198 | } 199 | 200 | @Override 201 | protected void finalize() throws Throwable { 202 | try { 203 | if (mEGLDisplay != EGL14.EGL_NO_DISPLAY) { 204 | // We're limited here -- finalizers don't run on the thread that holds 205 | // the EGL state, so if a surface or context is still current on another 206 | // thread we can't fully release it here. Exceptions thrown from here 207 | // are quietly discarded. Complain in the log file. 208 | Log.w(TAG, "WARNING: EglCore was not explicitly released -- state may be leaked"); 209 | release(); 210 | } 211 | } finally { 212 | super.finalize(); 213 | } 214 | } 215 | 216 | /** 217 | * Destroys the specified surface. Note the EGLSurface won't actually be destroyed if it's 218 | * still current in a context. 219 | */ 220 | public void releaseSurface(EGLSurface eglSurface) { 221 | EGL14.eglDestroySurface(mEGLDisplay, eglSurface); 222 | } 223 | 224 | /** 225 | * Creates an EGL surface associated with a Surface. 226 | *

227 | * If this is destined for MediaCodec, the EGLConfig should have the "recordable" attribute. 228 | */ 229 | public EGLSurface createWindowSurface(Object surface) { 230 | if (!(surface instanceof Surface) && !(surface instanceof SurfaceTexture)) { 231 | throw new RuntimeException("invalid surface: " + surface); 232 | } 233 | 234 | // Create a window surface, and attach it to the Surface we received. 235 | int[] surfaceAttribs = { 236 | EGL14.EGL_NONE 237 | }; 238 | EGLSurface eglSurface = EGL14.eglCreateWindowSurface(mEGLDisplay, mEGLConfig, surface, 239 | surfaceAttribs, 0); 240 | checkEglError("eglCreateWindowSurface"); 241 | if (eglSurface == null) { 242 | throw new RuntimeException("surface was null"); 243 | } 244 | return eglSurface; 245 | } 246 | 247 | /** 248 | * Creates an EGL surface associated with an offscreen buffer. 249 | */ 250 | public EGLSurface createOffscreenSurface(int width, int height) { 251 | int[] surfaceAttribs = { 252 | EGL14.EGL_WIDTH, width, 253 | EGL14.EGL_HEIGHT, height, 254 | EGL14.EGL_NONE 255 | }; 256 | EGLSurface eglSurface = EGL14.eglCreatePbufferSurface(mEGLDisplay, mEGLConfig, 257 | surfaceAttribs, 0); 258 | checkEglError("eglCreatePbufferSurface"); 259 | if (eglSurface == null) { 260 | throw new RuntimeException("surface was null"); 261 | } 262 | return eglSurface; 263 | } 264 | 265 | /** 266 | * Makes our EGL context current, using the supplied surface for both "draw" and "read". 267 | */ 268 | public void makeCurrent(EGLSurface eglSurface) { 269 | if (mEGLDisplay == EGL14.EGL_NO_DISPLAY) { 270 | // called makeCurrent() before create? 271 | Log.d(TAG, "NOTE: makeCurrent w/o display"); 272 | } 273 | if (!EGL14.eglMakeCurrent(mEGLDisplay, eglSurface, eglSurface, mEGLContext)) { 274 | throw new RuntimeException("eglMakeCurrent failed"); 275 | } 276 | } 277 | 278 | /** 279 | * Makes our EGL context current, using the supplied "draw" and "read" surfaces. 280 | */ 281 | public void makeCurrent(EGLSurface drawSurface, EGLSurface readSurface) { 282 | if (mEGLDisplay == EGL14.EGL_NO_DISPLAY) { 283 | // called makeCurrent() before create? 284 | Log.d(TAG, "NOTE: makeCurrent w/o display"); 285 | } 286 | if (!EGL14.eglMakeCurrent(mEGLDisplay, drawSurface, readSurface, mEGLContext)) { 287 | throw new RuntimeException("eglMakeCurrent(draw,read) failed"); 288 | } 289 | } 290 | 291 | /** 292 | * Makes no context current. 293 | */ 294 | public void makeNothingCurrent() { 295 | if (!EGL14.eglMakeCurrent(mEGLDisplay, EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_SURFACE, 296 | EGL14.EGL_NO_CONTEXT)) { 297 | throw new RuntimeException("eglMakeCurrent failed"); 298 | } 299 | } 300 | 301 | /** 302 | * Calls eglSwapBuffers. Use this to "publish" the current frame. 303 | * 304 | * @return false on failure 305 | */ 306 | public boolean swapBuffers(EGLSurface eglSurface) { 307 | return EGL14.eglSwapBuffers(mEGLDisplay, eglSurface); 308 | } 309 | 310 | /** 311 | * Sends the presentation time stamp to EGL. Time is expressed in nanoseconds. 312 | */ 313 | public void setPresentationTime(EGLSurface eglSurface, long nsecs) { 314 | EGLExt.eglPresentationTimeANDROID(mEGLDisplay, eglSurface, nsecs); 315 | } 316 | 317 | /** 318 | * Returns true if our context and the specified surface are current. 319 | */ 320 | public boolean isCurrent(EGLSurface eglSurface) { 321 | return mEGLContext.equals(EGL14.eglGetCurrentContext()) && 322 | eglSurface.equals(EGL14.eglGetCurrentSurface(EGL14.EGL_DRAW)); 323 | } 324 | 325 | /** 326 | * Performs a simple surface query. 327 | */ 328 | public int querySurface(EGLSurface eglSurface, int what) { 329 | int[] value = new int[1]; 330 | EGL14.eglQuerySurface(mEGLDisplay, eglSurface, what, value, 0); 331 | return value[0]; 332 | } 333 | 334 | /** 335 | * Queries a string value. 336 | */ 337 | public String queryString(int what) { 338 | return EGL14.eglQueryString(mEGLDisplay, what); 339 | } 340 | 341 | /** 342 | * Returns the GLES version this context is configured for (currently 2 or 3). 343 | */ 344 | public int getGlVersion() { 345 | return mGlVersion; 346 | } 347 | 348 | /** 349 | * Writes the current display, context, and surface to the log. 350 | */ 351 | public static void logCurrent(String msg) { 352 | EGLDisplay display; 353 | EGLContext context; 354 | EGLSurface surface; 355 | 356 | display = EGL14.eglGetCurrentDisplay(); 357 | context = EGL14.eglGetCurrentContext(); 358 | surface = EGL14.eglGetCurrentSurface(EGL14.EGL_DRAW); 359 | Log.i(TAG, "Current EGL (" + msg + "): display=" + display + ", context=" + context + 360 | ", surface=" + surface); 361 | } 362 | 363 | /** 364 | * Checks for EGL errors. Throws an exception if an error has been raised. 365 | */ 366 | private void checkEglError(String msg) { 367 | int error; 368 | if ((error = EGL14.eglGetError()) != EGL14.EGL_SUCCESS) { 369 | throw new RuntimeException(msg + ": EGL error: 0x" + Integer.toHexString(error)); 370 | } 371 | } 372 | } 373 | -------------------------------------------------------------------------------- /app/src/main/java/com/cgfay/eglnativerender/gles/EglSurfaceBase.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 Google Inc. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.cgfay.eglnativerender.gles; 18 | 19 | import android.graphics.Bitmap; 20 | import android.opengl.EGL14; 21 | import android.opengl.EGLSurface; 22 | import android.opengl.GLES30; 23 | import android.util.Log; 24 | 25 | 26 | import com.cgfay.eglnativerender.utils.BitmapUtils; 27 | import com.cgfay.eglnativerender.utils.GlUtil; 28 | 29 | import java.io.BufferedOutputStream; 30 | import java.io.File; 31 | import java.io.FileOutputStream; 32 | import java.io.IOException; 33 | import java.nio.ByteBuffer; 34 | import java.nio.ByteOrder; 35 | 36 | /** 37 | * Common base class for EGL surfaces. 38 | *

39 | * There can be multiple surfaces associated with a single context. 40 | */ 41 | public class EglSurfaceBase { 42 | protected static final String TAG = "EglSurfaceBase"; 43 | 44 | // EglCore object we're associated with. It may be associated with multiple surfaces. 45 | protected EglCore mEglCore; 46 | 47 | private EGLSurface mEGLSurface = EGL14.EGL_NO_SURFACE; 48 | private int mWidth = -1; 49 | private int mHeight = -1; 50 | 51 | protected EglSurfaceBase(EglCore eglCore) { 52 | mEglCore = eglCore; 53 | } 54 | 55 | /** 56 | * Creates a window surface. 57 | *

58 | * @param surface May be a Surface or SurfaceTexture. 59 | */ 60 | public void createWindowSurface(Object surface) { 61 | if (mEGLSurface != EGL14.EGL_NO_SURFACE) { 62 | throw new IllegalStateException("surface already created"); 63 | } 64 | mEGLSurface = mEglCore.createWindowSurface(surface); 65 | 66 | // Don't cache width/height here, because the size of the underlying surface can change 67 | // out from under us (see e.g. HardwareScalerActivity). 68 | //mWidth = mEglCore.querySurface(mEGLSurface, EGL14.EGL_WIDTH); 69 | //mHeight = mEglCore.querySurface(mEGLSurface, EGL14.EGL_HEIGHT); 70 | } 71 | 72 | /** 73 | * Creates an off-screen surface. 74 | */ 75 | public void createOffscreenSurface(int width, int height) { 76 | if (mEGLSurface != EGL14.EGL_NO_SURFACE) { 77 | throw new IllegalStateException("surface already created"); 78 | } 79 | mEGLSurface = mEglCore.createOffscreenSurface(width, height); 80 | mWidth = width; 81 | mHeight = height; 82 | } 83 | 84 | /** 85 | * Returns the surface's width, in pixels. 86 | *

87 | * If this is called on a window surface, and the underlying surface is in the process 88 | * of changing size, we may not see the new size right away (e.g. in the "surfaceChanged" 89 | * callback). The size should match after the next buffer swap. 90 | */ 91 | public int getWidth() { 92 | if (mWidth < 0) { 93 | return mEglCore.querySurface(mEGLSurface, EGL14.EGL_WIDTH); 94 | } else { 95 | return mWidth; 96 | } 97 | } 98 | 99 | /** 100 | * Returns the surface's height, in pixels. 101 | */ 102 | public int getHeight() { 103 | if (mHeight < 0) { 104 | return mEglCore.querySurface(mEGLSurface, EGL14.EGL_HEIGHT); 105 | } else { 106 | return mHeight; 107 | } 108 | } 109 | 110 | /** 111 | * Release the EGL surface. 112 | */ 113 | public void releaseEglSurface() { 114 | mEglCore.releaseSurface(mEGLSurface); 115 | mEGLSurface = EGL14.EGL_NO_SURFACE; 116 | mWidth = mHeight = -1; 117 | } 118 | 119 | /** 120 | * Makes our EGL context and surface current. 121 | */ 122 | public void makeCurrent() { 123 | mEglCore.makeCurrent(mEGLSurface); 124 | } 125 | 126 | /** 127 | * Makes our EGL context and surface current for drawing, using the supplied surface 128 | * for reading. 129 | */ 130 | public void makeCurrentReadFrom(EglSurfaceBase readSurface) { 131 | mEglCore.makeCurrent(mEGLSurface, readSurface.mEGLSurface); 132 | } 133 | 134 | /** 135 | * Calls eglSwapBuffers. Use this to "publish" the current frame. 136 | * 137 | * @return false on failure 138 | */ 139 | public boolean swapBuffers() { 140 | boolean result = mEglCore.swapBuffers(mEGLSurface); 141 | if (!result) { 142 | Log.d(TAG, "WARNING: swapBuffers() failed"); 143 | } 144 | return result; 145 | } 146 | 147 | /** 148 | * Sends the presentation time stamp to EGL. 149 | * 150 | * @param nsecs Timestamp, in nanoseconds. 151 | */ 152 | public void setPresentationTime(long nsecs) { 153 | mEglCore.setPresentationTime(mEGLSurface, nsecs); 154 | } 155 | 156 | /** 157 | * Saves the EGL surface to a file. 158 | *

159 | * Expects that this object's EGL surface is current. 160 | */ 161 | public void saveFrame(File file) throws IOException { 162 | if (!mEglCore.isCurrent(mEGLSurface)) { 163 | throw new RuntimeException("Expected EGL context/surface is not current"); 164 | } 165 | 166 | // glReadPixels fills in a "direct" ByteBuffer with what is essentially big-endian RGBA 167 | // data (i.e. a byte of red, followed by a byte of green...). While the Bitmap 168 | // constructor that takes an int[] wants little-endian ARGB (blue/red swapped), the 169 | // Bitmap "copy pixels" method wants the same format GL provides. 170 | // 171 | // Ideally we'd have some way to re-use the ByteBuffer, especially if we're calling 172 | // here often. 173 | // 174 | // Making this even more interesting is the upside-down nature of GL, which means 175 | // our output will look upside down relative to what appears on screen if the 176 | // typical GL conventions are used. 177 | 178 | String filename = file.toString(); 179 | 180 | int width = getWidth(); 181 | int height = getHeight(); 182 | ByteBuffer buf = ByteBuffer.allocateDirect(width * height * 4); 183 | buf.order(ByteOrder.LITTLE_ENDIAN); 184 | GLES30.glReadPixels(0, 0, width, height, 185 | GLES30.GL_RGBA, GLES30.GL_UNSIGNED_BYTE, buf); 186 | GlUtil.checkGlError("glReadPixels"); 187 | buf.rewind(); 188 | 189 | BufferedOutputStream bos = null; 190 | try { 191 | bos = new BufferedOutputStream(new FileOutputStream(filename)); 192 | Bitmap bmp = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); 193 | bmp.copyPixelsFromBuffer(buf); 194 | bmp = BitmapUtils.getRotatedBitmap(bmp, 180); 195 | bmp = BitmapUtils.flipBitmap(bmp); 196 | bmp.compress(Bitmap.CompressFormat.JPEG, 90, bos); 197 | bmp.recycle(); 198 | } finally { 199 | if (bos != null) bos.close(); 200 | } 201 | } 202 | 203 | /** 204 | * 获取帧 205 | * @return 206 | */ 207 | public Bitmap getFrameBitmap() { 208 | int width = getWidth(); 209 | int height = getHeight(); 210 | ByteBuffer buf = ByteBuffer.allocateDirect(width * height * 4); 211 | buf.order(ByteOrder.LITTLE_ENDIAN); 212 | GLES30.glReadPixels(0, 0, width, height, 213 | GLES30.GL_RGBA, GLES30.GL_UNSIGNED_BYTE, buf); 214 | GlUtil.checkGlError("glReadPixels"); 215 | buf.rewind(); 216 | Bitmap bmp = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); 217 | bmp.copyPixelsFromBuffer(buf); 218 | return BitmapUtils.getRotatedBitmap(bmp, 180); 219 | } 220 | 221 | /** 222 | * 获取当前帧的缓冲 223 | * @return 224 | */ 225 | public ByteBuffer getCurrentFrame() { 226 | int width = getWidth(); 227 | int height = getHeight(); 228 | ByteBuffer buf = ByteBuffer.allocateDirect(width * height * 4); 229 | buf.order(ByteOrder.LITTLE_ENDIAN); 230 | GLES30.glReadPixels(0, 0, width, height, 231 | GLES30.GL_RGBA, GLES30.GL_UNSIGNED_BYTE, buf); 232 | GlUtil.checkGlError("glReadPixels"); 233 | buf.rewind(); 234 | return buf; 235 | } 236 | 237 | } 238 | -------------------------------------------------------------------------------- /app/src/main/java/com/cgfay/eglnativerender/gles/OffscreenSurface.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 Google Inc. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.cgfay.eglnativerender.gles; 18 | 19 | /** 20 | * Off-screen EGL surface (pbuffer). 21 | *

22 | * It's good practice to explicitly release() the surface, preferably from a "finally" block. 23 | */ 24 | public class OffscreenSurface extends EglSurfaceBase { 25 | /** 26 | * Creates an off-screen surface with the specified width and height. 27 | */ 28 | public OffscreenSurface(EglCore eglCore, int width, int height) { 29 | super(eglCore); 30 | createOffscreenSurface(width, height); 31 | } 32 | 33 | /** 34 | * Releases any resources associated with the surface. 35 | */ 36 | public void release() { 37 | releaseEglSurface(); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /app/src/main/java/com/cgfay/eglnativerender/gles/WindowSurface.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 Google Inc. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.cgfay.eglnativerender.gles; 18 | 19 | import android.graphics.SurfaceTexture; 20 | import android.view.Surface; 21 | 22 | /** 23 | * Recordable EGL window surface. 24 | *

25 | * It's good practice to explicitly release() the surface, preferably from a "finally" block. 26 | */ 27 | public class WindowSurface extends EglSurfaceBase { 28 | private Surface mSurface; 29 | private boolean mReleaseSurface; 30 | 31 | /** 32 | * Associates an EGL surface with the native window surface. 33 | *

34 | * Set releaseSurface to true if you want the Surface to be released when release() is 35 | * called. This is convenient, but can interfere with framework classes that expect to 36 | * manage the Surface themselves (e.g. if you release a SurfaceView's Surface, the 37 | * surfaceDestroyed() callback won't fire). 38 | */ 39 | public WindowSurface(EglCore eglCore, Surface surface, boolean releaseSurface) { 40 | super(eglCore); 41 | createWindowSurface(surface); 42 | mSurface = surface; 43 | mReleaseSurface = releaseSurface; 44 | } 45 | 46 | /** 47 | * Associates an EGL surface with the SurfaceTexture. 48 | */ 49 | public WindowSurface(EglCore eglCore, SurfaceTexture surfaceTexture) { 50 | super(eglCore); 51 | createWindowSurface(surfaceTexture); 52 | } 53 | 54 | /** 55 | * Releases any resources associated with the EGL surface (and, if configured to do so, 56 | * with the Surface as well). 57 | *

58 | * Does not require that the surface's EGL context be current. 59 | */ 60 | public void release() { 61 | releaseEglSurface(); 62 | if (mSurface != null) { 63 | if (mReleaseSurface) { 64 | mSurface.release(); 65 | } 66 | mSurface = null; 67 | } 68 | } 69 | 70 | /** 71 | * Recreate the EGLSurface, using the new EglBase. The caller should have already 72 | * freed the old EGLSurface with releaseEglSurface(). 73 | *

74 | * This is useful when we want to update the EGLSurface associated with a Surface. 75 | * For example, if we want to share with a different EGLContext, which can only 76 | * be done by tearing down and recreating the context. (That's handled by the caller; 77 | * this just creates a new EGLSurface for the Surface we were handed earlier.) 78 | *

79 | * If the previous EGLSurface isn't fully destroyed, e.g. it's still current on a 80 | * context somewhere, the create call will fail with complaints from the Surface 81 | * about already being connected. 82 | */ 83 | public void recreate(EglCore newEglCore) { 84 | if (mSurface == null) { 85 | throw new RuntimeException("not yet implemented for SurfaceTexture"); 86 | } 87 | mEglCore = newEglCore; // switch to new context 88 | createWindowSurface(mSurface); // create new surface 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /app/src/main/java/com/cgfay/eglnativerender/utils/BitmapUtils.java: -------------------------------------------------------------------------------- 1 | package com.cgfay.eglnativerender.utils; 2 | 3 | import android.content.ContentProviderClient; 4 | import android.content.ContentResolver; 5 | import android.content.ContentValues; 6 | import android.content.Context; 7 | import android.content.res.AssetManager; 8 | import android.database.Cursor; 9 | import android.graphics.Bitmap; 10 | import android.graphics.BitmapFactory; 11 | import android.graphics.Matrix; 12 | import android.media.ExifInterface; 13 | import android.net.Uri; 14 | import android.os.Bundle; 15 | import android.os.RemoteException; 16 | import android.provider.MediaStore; 17 | 18 | import java.io.File; 19 | import java.io.FileOutputStream; 20 | import java.io.IOException; 21 | import java.io.InputStream; 22 | 23 | /** 24 | * Created by cain on 2017/7/9. 25 | */ 26 | 27 | public class BitmapUtils { 28 | 29 | public static final String[] EXIF_TAGS = { 30 | "FNumber", 31 | ExifInterface.TAG_DATETIME, 32 | "ExposureTime", 33 | ExifInterface.TAG_FLASH, 34 | ExifInterface.TAG_FOCAL_LENGTH, 35 | "GPSAltitude", "GPSAltitudeRef", 36 | ExifInterface.TAG_GPS_DATESTAMP, 37 | ExifInterface.TAG_GPS_LATITUDE, 38 | ExifInterface.TAG_GPS_LATITUDE_REF, 39 | ExifInterface.TAG_GPS_LONGITUDE, 40 | ExifInterface.TAG_GPS_LONGITUDE_REF, 41 | ExifInterface.TAG_GPS_PROCESSING_METHOD, 42 | ExifInterface.TAG_GPS_TIMESTAMP, 43 | ExifInterface.TAG_IMAGE_LENGTH, 44 | ExifInterface.TAG_IMAGE_WIDTH, "ISOSpeedRatings", 45 | ExifInterface.TAG_MAKE, ExifInterface.TAG_MODEL, 46 | ExifInterface.TAG_WHITE_BALANCE, 47 | }; 48 | 49 | /** 50 | * 旋转图片 51 | * @param bitmap 52 | * @param rotation 53 | * @return 54 | */ 55 | public static Bitmap getRotatedBitmap(Bitmap bitmap, int rotation) { 56 | Matrix matrix = new Matrix(); 57 | matrix.postRotate(rotation); 58 | return Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), 59 | bitmap.getHeight(), matrix, false); 60 | } 61 | 62 | /** 63 | * 镜像翻转图片 64 | * @param bitmap 65 | * @return 66 | */ 67 | public static Bitmap flipBitmap(Bitmap bitmap) { 68 | return flipBitmap(bitmap, true, false); 69 | } 70 | 71 | /** 72 | * 翻转图片 73 | * @param bitmap 74 | * @param flipX 75 | * @param flipY 76 | * @return 77 | */ 78 | public static Bitmap flipBitmap(Bitmap bitmap, boolean flipX, boolean flipY) { 79 | Matrix matrix = new Matrix(); 80 | matrix.setScale(flipX ? -1 : 1, flipY ? -1 : 1); 81 | matrix.postTranslate(bitmap.getWidth(), 0); 82 | return Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), 83 | bitmap.getHeight(), matrix, false); 84 | } 85 | 86 | 87 | /** 88 | * 加载Assets文件夹下的图片 89 | * @param context 90 | * @param fileName 91 | * @return 92 | */ 93 | public static Bitmap getImageFromAssetsFile(Context context, String fileName) { 94 | Bitmap bitmap = null; 95 | AssetManager manager = context.getResources().getAssets(); 96 | try { 97 | InputStream is = manager.open(fileName); 98 | bitmap = BitmapFactory.decodeStream(is); 99 | is.close(); 100 | } catch (IOException e) { 101 | e.printStackTrace(); 102 | } 103 | return bitmap; 104 | } 105 | 106 | /** 107 | * 加载Assets文件夹下的图片 108 | * @param context 109 | * @param fileName 110 | * @return 111 | */ 112 | public static Bitmap getImageFromAssetsFile(Context context, String fileName, Bitmap inBitmap) { 113 | Bitmap bitmap = null; 114 | AssetManager manager = context.getResources().getAssets(); 115 | try { 116 | InputStream is = manager.open(fileName); 117 | if (inBitmap != null && !inBitmap.isRecycled()) { 118 | BitmapFactory.Options options = new BitmapFactory.Options(); 119 | // 使用inBitmap时,inSampleSize得设置为1 120 | options.inSampleSize = 1; 121 | // 这个属性一定要在inBitmap之前使用,否则会弹出一下异常 122 | // BitmapFactory: Unable to reuse an immutable bitmap as an image decoder target. 123 | options.inMutable = true; 124 | options.inBitmap = inBitmap; 125 | bitmap = BitmapFactory.decodeStream(is, null, options); 126 | } else { 127 | bitmap = BitmapFactory.decodeStream(is); 128 | } 129 | is.close(); 130 | } catch (IOException e) { 131 | e.printStackTrace(); 132 | } 133 | return bitmap; 134 | } 135 | 136 | /** 137 | * 138 | * @param options 139 | * @param reqWidth 140 | * @param reqHeight 141 | * @return 142 | */ 143 | private static int calculateInSampleSize(BitmapFactory.Options options, 144 | int reqWidth, int reqHeight) { 145 | // 计算原始图像的高度和宽度 146 | final int height = options.outHeight; 147 | final int width = options.outWidth; 148 | int inSampleSize = 1; 149 | 150 | // 当原始图像的高和宽大于所需高度和宽度时 151 | if (height > reqHeight || width > reqWidth) { 152 | final int heightRatio = Math.round((float) height / (float) reqHeight); 153 | final int widthRatio = Math.round((float) width / (float) reqWidth); 154 | 155 | // 算出长宽比后去比例小的作为inSamplesize,保证最后imageview的dimension比request的大 156 | inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio; 157 | 158 | // 计算总像素是否大于请求的宽高积的2倍 159 | final float totalPixels = width * height; 160 | final float totalReqPixelsCap = reqWidth * reqHeight * 2; 161 | while (totalPixels / (inSampleSize * inSampleSize) > totalReqPixelsCap) { 162 | inSampleSize++; 163 | } 164 | } 165 | return inSampleSize; 166 | } 167 | 168 | 169 | /** 170 | * 从文件读取Bitmap 171 | * @param dst 172 | * @param width 173 | * @param height 174 | * @return 175 | */ 176 | public static Bitmap getBitmapFromFile(File dst, int width, int height) { 177 | if (null != dst && dst.exists()) { 178 | BitmapFactory.Options opts = null; 179 | if (width > 0 && height > 0) { 180 | opts = new BitmapFactory.Options(); 181 | opts.inJustDecodeBounds = true; 182 | BitmapFactory.decodeFile(dst.getPath(), opts); 183 | // 计算图片缩放比例 184 | opts.inSampleSize = calculateInSampleSize(opts, width, height); 185 | opts.inJustDecodeBounds = false; 186 | opts.inInputShareable = true; 187 | opts.inPurgeable = true; 188 | } 189 | try { 190 | return BitmapFactory.decodeFile(dst.getPath(), opts); 191 | } catch (OutOfMemoryError e) { 192 | e.printStackTrace(); 193 | } 194 | } 195 | return null; 196 | } 197 | 198 | /** 199 | * 保存图片 200 | * @param context 201 | * @param path 202 | * @param bitmap 203 | */ 204 | public static void saveBitmap(Context context, String path, Bitmap bitmap) { 205 | saveBitmap(context, path, bitmap, true); 206 | } 207 | 208 | /** 209 | * 保存图片 210 | * @param context 211 | * @param path 212 | * @param bitmap 213 | * @param addToMediaStore 214 | */ 215 | public static void saveBitmap(Context context, String path, Bitmap bitmap, 216 | boolean addToMediaStore) { 217 | final File file = new File(path); 218 | if (!file.getParentFile().exists()) { 219 | file.getParentFile().mkdirs(); 220 | } 221 | 222 | FileOutputStream fOut = null; 223 | try { 224 | fOut = new FileOutputStream(file); 225 | } catch (IOException e) { 226 | e.printStackTrace(); 227 | } 228 | bitmap.compress(Bitmap.CompressFormat.PNG, 100, fOut); 229 | try { 230 | fOut.flush(); 231 | fOut.close(); 232 | } catch (IOException e) { 233 | e.printStackTrace(); 234 | } 235 | // 添加到媒体库 236 | if (addToMediaStore) { 237 | ContentValues values = new ContentValues(); 238 | values.put(MediaStore.Images.Media.DATA, path); 239 | values.put(MediaStore.Images.Media.DISPLAY_NAME, file.getName()); 240 | context.getContentResolver().insert( 241 | MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values); 242 | } 243 | } 244 | 245 | /** 246 | * 获取图片旋转角度 247 | * @param path 248 | * @return 249 | */ 250 | public static int getOrientation(final String path) { 251 | int rotation = 0; 252 | try { 253 | File file = new File(path); 254 | ExifInterface exif = new ExifInterface(file.getAbsolutePath()); 255 | int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, 256 | ExifInterface.ORIENTATION_NORMAL); 257 | switch (orientation) { 258 | case ExifInterface.ORIENTATION_ROTATE_90: 259 | rotation = 90; 260 | break; 261 | 262 | case ExifInterface.ORIENTATION_ROTATE_180: 263 | rotation = 180; 264 | break; 265 | 266 | case ExifInterface.ORIENTATION_ROTATE_270: 267 | rotation = 270; 268 | break; 269 | 270 | default: 271 | rotation = 0; 272 | break; 273 | } 274 | } catch (IOException e) { 275 | e.printStackTrace(); 276 | } 277 | return rotation; 278 | } 279 | 280 | /** 281 | * 获取Uri路径图片的旋转角度 282 | * @param context 283 | * @param uri 284 | * @return 285 | */ 286 | public static int getOrientation(Context context, Uri uri) { 287 | final String scheme = uri.getScheme(); 288 | ContentProviderClient provider = null; 289 | if (scheme == null || ContentResolver.SCHEME_FILE.equals(scheme)) { 290 | return getOrientation(uri.getPath()); 291 | } else if (scheme.equals(ContentResolver.SCHEME_CONTENT)) { 292 | try { 293 | provider = context.getContentResolver().acquireContentProviderClient(uri); 294 | } catch (SecurityException e) { 295 | return 0; 296 | } 297 | if (provider != null) { 298 | Cursor cursor; 299 | try { 300 | cursor = provider.query(uri, new String[] { 301 | MediaStore.Images.ImageColumns.ORIENTATION, 302 | MediaStore.Images.ImageColumns.DATA}, 303 | null, null, null); 304 | } catch (RemoteException e) { 305 | e.printStackTrace(); 306 | return 0; 307 | } 308 | if (cursor == null) { 309 | return 0; 310 | } 311 | 312 | int orientationIndex = cursor 313 | .getColumnIndex(MediaStore.Images.ImageColumns.ORIENTATION); 314 | int dataIndex = cursor.getColumnIndex(MediaStore.Images.ImageColumns.DATA); 315 | 316 | try { 317 | if (cursor.getCount() > 0) { 318 | cursor.moveToFirst(); 319 | 320 | int rotation = 0; 321 | 322 | if (orientationIndex > -1) { 323 | rotation = cursor.getInt(orientationIndex); 324 | } 325 | 326 | if (dataIndex > -1) { 327 | String path = cursor.getString(dataIndex); 328 | rotation |= getOrientation(path); 329 | } 330 | return rotation; 331 | } 332 | } finally { 333 | cursor.close(); 334 | } 335 | } 336 | } 337 | return 0; 338 | } 339 | 340 | /** 341 | * 获取图片大小 342 | * @param path 343 | * @return 344 | */ 345 | public static Size getBitmapSize(String path) { 346 | BitmapFactory.Options options = new BitmapFactory.Options(); 347 | options.inJustDecodeBounds = true; 348 | BitmapFactory.decodeFile(path, options); 349 | return new Size(options.outWidth, options.outHeight); 350 | } 351 | 352 | /** 353 | * 将Bitmap图片旋转90度 354 | * @param data 355 | * @return 356 | */ 357 | public static Bitmap rotateBitmap(byte[] data) { 358 | return rotateBitmap(data, 90); 359 | } 360 | 361 | /** 362 | * 将Bitmap图片旋转一定角度 363 | * @param data 364 | * @param rotate 365 | * @return 366 | */ 367 | public static Bitmap rotateBitmap(byte[] data, int rotate) { 368 | Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length); 369 | Matrix matrix = new Matrix(); 370 | matrix.reset(); 371 | matrix.postRotate(rotate); 372 | Bitmap rotatedBitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), 373 | bitmap.getHeight(), matrix, true); 374 | bitmap.recycle(); 375 | System.gc(); 376 | return rotatedBitmap; 377 | } 378 | 379 | /** 380 | * 将Bitmap图片旋转90度 381 | * @param bitmap 382 | * @return 383 | */ 384 | public static Bitmap rotateBitmap(Bitmap bitmap) { 385 | return rotateBitmap(bitmap, 90); 386 | } 387 | 388 | /** 389 | * 将Bitmap图片旋转一定角度 390 | * @param bitmap 391 | * @param rotate 392 | * @return 393 | */ 394 | public static Bitmap rotateBitmap(Bitmap bitmap, int rotate) { 395 | Matrix matrix = new Matrix(); 396 | matrix.reset(); 397 | matrix.postRotate(rotate); 398 | Bitmap rotatedBitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), 399 | bitmap.getHeight(), matrix, true); 400 | return rotatedBitmap; 401 | } 402 | 403 | /** 404 | * 获取Exif参数 405 | * @param path 406 | * @param bundle 407 | * @return 408 | */ 409 | public static boolean loadExifAttributes(String path, Bundle bundle) { 410 | ExifInterface exifInterface; 411 | try { 412 | exifInterface = new ExifInterface(path); 413 | } catch (IOException e) { 414 | e.printStackTrace(); 415 | return false; 416 | } 417 | for (String tag : EXIF_TAGS) { 418 | bundle.putString(tag, exifInterface.getAttribute(tag)); 419 | } 420 | return true; 421 | } 422 | 423 | /** 424 | * 保存Exif属性 425 | * @param path 426 | * @param bundle 427 | * @return 428 | */ 429 | public static boolean saveExifAttributes(String path, Bundle bundle) { 430 | ExifInterface exif; 431 | try { 432 | exif = new ExifInterface(path); 433 | } catch (IOException e) { 434 | e.printStackTrace(); 435 | return false; 436 | } 437 | 438 | for (String tag : EXIF_TAGS) { 439 | if (bundle.containsKey(tag)) { 440 | exif.setAttribute(tag, bundle.getString(tag)); 441 | } 442 | } 443 | try { 444 | exif.saveAttributes(); 445 | } catch (IOException e) { 446 | e.printStackTrace(); 447 | return false; 448 | } 449 | 450 | return true; 451 | } 452 | } 453 | -------------------------------------------------------------------------------- /app/src/main/java/com/cgfay/eglnativerender/utils/Size.java: -------------------------------------------------------------------------------- 1 | package com.cgfay.eglnativerender.utils; 2 | 3 | /** 4 | * Created by cain.huang on 2017/7/27. 5 | */ 6 | 7 | public class Size { 8 | int mWidth; 9 | int mHeight; 10 | 11 | public Size() { 12 | } 13 | 14 | public Size(int width, int height) { 15 | mWidth = width; 16 | mHeight = height; 17 | } 18 | 19 | public int getWidth() { 20 | return mWidth; 21 | } 22 | 23 | public void setWidth(int width) { 24 | mWidth = width; 25 | } 26 | 27 | public int getHeight() { 28 | return mHeight; 29 | } 30 | 31 | public void setHeight(int height) { 32 | this.mHeight = height; 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /app/src/main/java/com/cgfay/eglnativerender/utils/TextureRotationUtils.java: -------------------------------------------------------------------------------- 1 | package com.cgfay.eglnativerender.utils; 2 | 3 | import android.hardware.Camera; 4 | 5 | import java.nio.FloatBuffer; 6 | 7 | /** 8 | * Created by cain on 17-7-26. 9 | */ 10 | 11 | public class TextureRotationUtils { 12 | 13 | // 摄像头是否倒置,主要是应对Nexus 5X (bullhead) 的后置摄像头图像倒置的问题 14 | private static boolean mBackReverse = false; 15 | 16 | public static final int CoordsPerVertex = 3; 17 | 18 | public static final float CubeVertices[] = { 19 | -1.0f, -1.0f, 0.0f, // 0 bottom left 20 | 1.0f, -1.0f, 0.0f, // 1 bottom right 21 | -1.0f, 1.0f, 0.0f, // 2 top left 22 | 1.0f, 1.0f, 0.0f, // 3 top right 23 | }; 24 | 25 | public static final float TextureVertices[] = { 26 | 0.0f, 0.0f, // 0 bottom left 27 | 1.0f, 0.0f, // 1 bottom right 28 | 0.0f, 1.0f, // 2 top left 29 | 1.0f, 1.0f // 3 top right 30 | }; 31 | 32 | public static final float TextureVertices_90[] = { 33 | 1.0f, 0.0f, 34 | 1.0f, 1.0f, 35 | 0.0f, 0.0f, 36 | 0.0f, 1.0f, 37 | }; 38 | 39 | public static final float TextureVertices_180[] = { 40 | 1.0f, 1.0f, 41 | 0.0f, 1.0f, 42 | 1.0f, 0.0f, 43 | 0.0f, 0.0f, 44 | }; 45 | 46 | public static final float TextureVertices_270[] = { 47 | 0.0f, 1.0f, 48 | 0.0f, 0.0f, 49 | 1.0f, 1.0f, 50 | 0.0f, 0.0f, 51 | }; 52 | 53 | public static float[] getTextureVertices() { 54 | return TextureVertices; 55 | } 56 | 57 | public static FloatBuffer getTextureBuffer() { 58 | return GlUtil.createFloatBuffer(TextureRotationUtils.TextureVertices); 59 | } 60 | 61 | public static void setBackReverse(boolean reverse) { 62 | mBackReverse = reverse; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 12 | 13 | 19 | 22 | 25 | 26 | 27 | 28 | 34 | 35 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | 15 | 20 | 25 | 30 | 35 | 40 | 45 | 50 | 55 | 60 | 65 | 70 | 75 | 80 | 85 | 90 | 95 | 100 | 105 | 110 | 115 | 120 | 125 | 130 | 135 | 140 | 145 | 150 | 155 | 160 | 165 | 170 | 171 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main2.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 13 | 14 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main3.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CainKernel/EGLNativeRender/6caaa26175b73446e008cf21b50d7e1649b80d4f/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CainKernel/EGLNativeRender/6caaa26175b73446e008cf21b50d7e1649b80d4f/app/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CainKernel/EGLNativeRender/6caaa26175b73446e008cf21b50d7e1649b80d4f/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CainKernel/EGLNativeRender/6caaa26175b73446e008cf21b50d7e1649b80d4f/app/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CainKernel/EGLNativeRender/6caaa26175b73446e008cf21b50d7e1649b80d4f/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CainKernel/EGLNativeRender/6caaa26175b73446e008cf21b50d7e1649b80d4f/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CainKernel/EGLNativeRender/6caaa26175b73446e008cf21b50d7e1649b80d4f/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CainKernel/EGLNativeRender/6caaa26175b73446e008cf21b50d7e1649b80d4f/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CainKernel/EGLNativeRender/6caaa26175b73446e008cf21b50d7e1649b80d4f/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CainKernel/EGLNativeRender/6caaa26175b73446e008cf21b50d7e1649b80d4f/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #3F51B5 4 | #303F9F 5 | #FF4081 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | EglNativeRender 3 | 4 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/test/java/com/cgfay/eglnativerender/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package com.cgfay.eglnativerender; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.*; 6 | 7 | /** 8 | * Example local unit test, which will execute on the development machine (host). 9 | * 10 | * @see Testing documentation 11 | */ 12 | public class ExampleUnitTest { 13 | @Test 14 | public void addition_isCorrect() throws Exception { 15 | assertEquals(4, 2 + 2); 16 | } 17 | } -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | 5 | repositories { 6 | google() 7 | jcenter() 8 | } 9 | dependencies { 10 | classpath 'com.android.tools.build:gradle:3.0.1' 11 | 12 | 13 | // NOTE: Do not place your application dependencies here; they belong 14 | // in the individual module build.gradle files 15 | } 16 | } 17 | 18 | allprojects { 19 | repositories { 20 | google() 21 | jcenter() 22 | } 23 | } 24 | 25 | task clean(type: Delete) { 26 | delete rootProject.buildDir 27 | } 28 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | org.gradle.jvmargs=-Xmx1536m 13 | 14 | # When configured, Gradle will run in incubating parallel mode. 15 | # This option should only be used with decoupled projects. More details, visit 16 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 17 | # org.gradle.parallel=true 18 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CainKernel/EGLNativeRender/6caaa26175b73446e008cf21b50d7e1649b80d4f/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Tue Apr 03 17:14:30 CST 2018 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # Attempt to set APP_HOME 46 | # Resolve links: $0 may be a link 47 | PRG="$0" 48 | # Need this for relative symlinks. 49 | while [ -h "$PRG" ] ; do 50 | ls=`ls -ld "$PRG"` 51 | link=`expr "$ls" : '.*-> \(.*\)$'` 52 | if expr "$link" : '/.*' > /dev/null; then 53 | PRG="$link" 54 | else 55 | PRG=`dirname "$PRG"`"/$link" 56 | fi 57 | done 58 | SAVED="`pwd`" 59 | cd "`dirname \"$PRG\"`/" >/dev/null 60 | APP_HOME="`pwd -P`" 61 | cd "$SAVED" >/dev/null 62 | 63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 64 | 65 | # Determine the Java command to use to start the JVM. 66 | if [ -n "$JAVA_HOME" ] ; then 67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 68 | # IBM's JDK on AIX uses strange locations for the executables 69 | JAVACMD="$JAVA_HOME/jre/sh/java" 70 | else 71 | JAVACMD="$JAVA_HOME/bin/java" 72 | fi 73 | if [ ! -x "$JAVACMD" ] ; then 74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 75 | 76 | Please set the JAVA_HOME variable in your environment to match the 77 | location of your Java installation." 78 | fi 79 | else 80 | JAVACMD="java" 81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 82 | 83 | Please set the JAVA_HOME variable in your environment to match the 84 | location of your Java installation." 85 | fi 86 | 87 | # Increase the maximum file descriptors if we can. 88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 89 | MAX_FD_LIMIT=`ulimit -H -n` 90 | if [ $? -eq 0 ] ; then 91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 92 | MAX_FD="$MAX_FD_LIMIT" 93 | fi 94 | ulimit -n $MAX_FD 95 | if [ $? -ne 0 ] ; then 96 | warn "Could not set maximum file descriptor limit: $MAX_FD" 97 | fi 98 | else 99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 100 | fi 101 | fi 102 | 103 | # For Darwin, add options to specify how the application appears in the dock 104 | if $darwin; then 105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 106 | fi 107 | 108 | # For Cygwin, switch paths to Windows format before running java 109 | if $cygwin ; then 110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 112 | JAVACMD=`cygpath --unix "$JAVACMD"` 113 | 114 | # We build the pattern for arguments to be converted via cygpath 115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 116 | SEP="" 117 | for dir in $ROOTDIRSRAW ; do 118 | ROOTDIRS="$ROOTDIRS$SEP$dir" 119 | SEP="|" 120 | done 121 | OURCYGPATTERN="(^($ROOTDIRS))" 122 | # Add a user-defined pattern to the cygpath arguments 123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 125 | fi 126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 127 | i=0 128 | for arg in "$@" ; do 129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 131 | 132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 134 | else 135 | eval `echo args$i`="\"$arg\"" 136 | fi 137 | i=$((i+1)) 138 | done 139 | case $i in 140 | (0) set -- ;; 141 | (1) set -- "$args0" ;; 142 | (2) set -- "$args0" "$args1" ;; 143 | (3) set -- "$args0" "$args1" "$args2" ;; 144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 150 | esac 151 | fi 152 | 153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 154 | function splitJvmOpts() { 155 | JVM_OPTS=("$@") 156 | } 157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 159 | 160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 161 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | --------------------------------------------------------------------------------