├── .gitignore ├── .idea ├── .name ├── compiler.xml ├── copyright │ └── profiles_settings.xml ├── gradle.xml ├── misc.xml ├── modules.xml ├── runConfigurations.xml └── vcs.xml ├── README.md ├── app ├── .gitignore ├── app.iml ├── build.gradle ├── jni │ ├── Android.mk │ ├── Application.mk │ ├── NativeMedia.cpp │ └── NativeMedia.h ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── example │ │ └── jarry │ │ └── playvideo_texuture │ │ └── ApplicationTest.java │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── example │ │ └── jarry │ │ ├── GLViewMediaActivity.java │ │ ├── NativeMediaActivity.java │ │ ├── NativeMediaWrapper.java │ │ ├── NavigatorActivity.java │ │ ├── playvideo_texuture │ │ ├── TextureSurfaceRenderer.java │ │ ├── TextureViewMediaActivity.java │ │ └── VideoTextureSurfaceRenderer.java │ │ └── utils │ │ ├── RawResourceReader.java │ │ ├── ShaderHelper.java │ │ └── TextureHelper.java │ └── res │ ├── layout │ ├── activity_main.xml │ └── activity_navigator.xml │ ├── menu │ └── menu_main.xml │ ├── mipmap-hdpi │ └── ic_launcher.png │ ├── mipmap-mdpi │ └── ic_launcher.png │ ├── mipmap-xhdpi │ └── ic_launcher.png │ ├── mipmap-xxhdpi │ └── ic_launcher.png │ ├── raw │ ├── fragment_sharder.glsl │ └── vetext_sharder.glsl │ ├── values-w820dp │ └── dimens.xml │ └── values │ ├── dimens.xml │ ├── strings.xml │ └── styles.xml ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | .gradle 2 | /local.properties 3 | /.idea/workspace.xml 4 | /.idea/libraries 5 | .DS_Store 6 | /build 7 | /captures 8 | -------------------------------------------------------------------------------- /.idea/.name: -------------------------------------------------------------------------------- 1 | PlayVideo-Texuture -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /.idea/copyright/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 18 | 19 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 19 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 46 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PlayVideo-OpenGL 2 | 3 | 通过Opengl ES去绘制视频的demo 4 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/app.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 8 | 9 | 10 | 11 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 26 5 | buildToolsVersion '25.0.1' 6 | 7 | defaultConfig { 8 | applicationId "com.example.jarry.playvideo_texuture" 9 | minSdkVersion 15 10 | targetSdkVersion 23 11 | versionCode 1 12 | versionName "1.0" 13 | } 14 | buildTypes { 15 | release { 16 | minifyEnabled false 17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 18 | } 19 | } 20 | 21 | sourceSets { 22 | main { 23 | jniLibs.srcDirs = ['libs'] 24 | } 25 | } 26 | } 27 | 28 | project.afterEvaluate { 29 | printf("===============start ndk build======================\n") 30 | if (GetNDKBuildCmd() == null) { 31 | return; 32 | } 33 | 34 | compileDebugNdk.dependsOn 'NDKBuildDebug' 35 | compileReleaseNdk.dependsOn 'NDKBuildRelease' 36 | clean.dependsOn 'NDKBuildClean' 37 | } 38 | 39 | dependencies { 40 | compile fileTree(dir: 'libs', include: ['*.jar']) 41 | compile 'com.android.support:appcompat-v7:23.2.0' 42 | } 43 | -------------------------------------------------------------------------------- /app/jni/Android.mk: -------------------------------------------------------------------------------- 1 | 2 | LOCAL_PATH := $(call my-dir) 3 | 4 | include $(CLEAR_VARS) 5 | 6 | LOCAL_MODULE := native_media 7 | 8 | LOCAL_LDLIBS := -llog -landroid -lEGL -lGLESv2 -lGLESv3 9 | 10 | LOCAL_SRC_FILES := NativeMedia.cpp 11 | 12 | include $(BUILD_SHARED_LIBRARY) 13 | 14 | 15 | -------------------------------------------------------------------------------- /app/jni/Application.mk: -------------------------------------------------------------------------------- 1 | # MAKEFILE_LIST specifies the current used Makefiles, of which this is the last 2 | # one. I use that to obtain the Application.mk dir then import the root 3 | # Application.mk. 4 | # This needs to be defined to get the right header directories for egl / etc 5 | APP_PLATFORM := android-23 6 | 7 | # This needs to be defined to avoid compile errors like: 8 | # Error: selected processor does not support ARM mode `ldrex r0,[r3]' 9 | APP_ABI := armeabi-v7a 10 | 11 | # Statically link the GNU STL. This may not be safe for multi-so libraries but 12 | # we don't know of any problems yet. 13 | APP_STL := gnustl_static 14 | 15 | # Make sure every shared lib includes a .note.gnu.build-id header, for crash reporting 16 | APP_LDFLAGS := -Wl,--build-id 17 | 18 | # Explicitly use GCC 4.8 as our toolchain. This is the 32-bit default as of 19 | # r10d but versions as far back as r9d have 4.8. The previous default, 4.6, is 20 | # deprecated as of r10c. 21 | NDK_TOOLCHAIN_VERSION := 4.8 22 | 23 | # Define the directories for $(import-module, ...) to look in 24 | ROOT_DIR := $(patsubst %/,%,$(dir $(lastword $(MAKEFILE_LIST)))) 25 | NDK_MODULE_PATH := $(ROOT_DIR) -------------------------------------------------------------------------------- /app/jni/NativeMedia.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Administrator on 2016/4/10 0010. 3 | // 4 | 5 | #include "NativeMedia.h" 6 | 7 | #define LOG_TAG "NativeVideo" 8 | 9 | #define LOG_INFO(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__) 10 | #define LOG_ERROR(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__) 11 | #define LOG(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__) 12 | 13 | JavaVM *gJavaVM; 14 | NativeMedia *gNativeMedia; 15 | 16 | pthread_mutex_t gMutex; 17 | 18 | static void checkGlError(const char *op) { 19 | for (GLint error = glGetError(); error; error = glGetError()) { 20 | LOG("after %s() glError (0x%x)\n", op, error); 21 | } 22 | } 23 | 24 | static const char gVertexShader[] = 25 | "attribute vec4 aPosition;\n" 26 | "attribute vec4 aTexCoordinate;\n" 27 | "uniform mat4 texTransform;\n" 28 | "varying vec2 v_TexCoordinate;\n" 29 | "void main() {\n" 30 | "v_TexCoordinate = (texTransform * aTexCoordinate).xy;\n" 31 | "gl_Position = aPosition;\n" 32 | "}\n"; 33 | 34 | static const char gFragmentShader[] = 35 | "#extension GL_OES_EGL_image_external : require\n" 36 | "precision mediump float;\n" 37 | "uniform samplerExternalOES texture;\n" 38 | "varying vec2 v_TexCoordinate;\n" 39 | "void main() {\n" 40 | "vec4 color = texture2D(texture,v_TexCoordinate);\n" 41 | "gl_FragColor = color;\n" 42 | "}\n"; 43 | 44 | GLuint loadShader(GLenum shaderType, const char *pSource) { 45 | GLuint shader = glCreateShader(shaderType); 46 | if (shader) { 47 | glShaderSource(shader, 1, &pSource, NULL); 48 | glCompileShader(shader); 49 | GLint compiled = 0; 50 | glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled); 51 | if (!compiled) { 52 | GLint infoLen = 0; 53 | glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen); 54 | if (infoLen) { 55 | char *buf = (char *) malloc(infoLen); 56 | if (buf) { 57 | glGetShaderInfoLog(shader, infoLen, NULL, buf); 58 | LOG("Could not compile shader %d:\n%s\n", 59 | shaderType, buf); 60 | free(buf); 61 | } 62 | glDeleteShader(shader); 63 | shader = 0; 64 | } 65 | } 66 | } 67 | return shader; 68 | } 69 | 70 | GLuint createProgram(const char *pVertexSource, const char *pFragmentSource) { 71 | GLuint vertexShader = loadShader(GL_VERTEX_SHADER, pVertexSource); 72 | if (!vertexShader) { 73 | return 0; 74 | } 75 | 76 | GLuint pixelShader = loadShader(GL_FRAGMENT_SHADER, pFragmentSource); 77 | if (!pixelShader) { 78 | return 0; 79 | } 80 | 81 | GLuint program = glCreateProgram(); 82 | if (program) { 83 | glAttachShader(program, vertexShader); 84 | checkGlError("glAttachShader"); 85 | glAttachShader(program, pixelShader); 86 | checkGlError("glAttachShader"); 87 | glLinkProgram(program); 88 | GLint linkStatus = GL_FALSE; 89 | glGetProgramiv(program, GL_LINK_STATUS, &linkStatus); 90 | if (linkStatus != GL_TRUE) { 91 | GLint bufLength = 0; 92 | glGetProgramiv(program, GL_INFO_LOG_LENGTH, &bufLength); 93 | if (bufLength) { 94 | char *buf = (char *) malloc(bufLength); 95 | if (buf) { 96 | glGetProgramInfoLog(program, bufLength, NULL, buf); 97 | LOG("Could not link program:\n%s\n", buf); 98 | free(buf); 99 | } 100 | } 101 | glDeleteProgram(program); 102 | program = 0; 103 | } 104 | } 105 | return program; 106 | } 107 | 108 | NativeMedia::NativeMedia(): 109 | jni(NULL), 110 | javaVM(NULL), 111 | javaSurfaceTextureObj(NULL), 112 | nanoTimeStamp(0), 113 | updateTexImageMethodId(NULL), 114 | getTimestampMethodId(NULL), 115 | setDefaultBufferSizeMethodId(NULL), 116 | getTransformMtxId(NULL) 117 | { 118 | pthread_mutex_init(&gMutex, 0); 119 | } 120 | 121 | NativeMedia::~NativeMedia() { 122 | 123 | pthread_mutex_destroy(&gMutex); 124 | 125 | if (javaSurfaceTextureObj) { 126 | jni->DeleteGlobalRef( javaSurfaceTextureObj ); 127 | javaSurfaceTextureObj = 0; 128 | } 129 | } 130 | 131 | jobject NativeMedia::getSurfaceTextureObject() { 132 | if (javaSurfaceTextureObj == NULL) { 133 | LOG_ERROR("SurfaceTexture not be NULL"); 134 | return NULL; 135 | } 136 | 137 | return javaSurfaceTextureObj; 138 | } 139 | 140 | static const GLfloat texTransform[16] = { 141 | 1.0f, 0.0f, 0.0f, 0.0f, 142 | 0.0f, -1.0f, 0.0f, 0.0f, 143 | 0.0f, 0.0f, 1.0f, 0.0f, 144 | 0.0f, 1.0f, 0.0f, 1.0f 145 | }; 146 | 147 | 148 | GLuint texId; 149 | GLuint shaderProgram; 150 | GLuint positionHandle; 151 | GLint textureParamHandle; 152 | GLuint textureCoordHandle; 153 | GLuint textureTranformHandle; 154 | 155 | int width, height; 156 | 157 | unsigned int vao; 158 | 159 | unsigned int vb; 160 | unsigned int ib; 161 | 162 | void NativeMedia::setupGraphics(int w, int h) { 163 | width = w; 164 | height = h; 165 | 166 | LOG_INFO("set meidia graphics w: %d, h: %d", w, h); 167 | 168 | shaderProgram = createProgram(gVertexShader, gFragmentShader); 169 | LOG("setupGraphics: %d \n", shaderProgram); 170 | 171 | if (!shaderProgram) { 172 | LOG_ERROR("gProgram: %d (%s)\n", shaderProgram, "createProgram error"); 173 | return; 174 | } 175 | 176 | textureParamHandle = glGetUniformLocation(shaderProgram, "texture"); 177 | checkGlError("glGetUniformLocation"); 178 | LOG("glGetUniformLocation(\"texturen\") = %d\n", textureParamHandle); 179 | 180 | positionHandle = glGetAttribLocation(shaderProgram, "aPosition"); 181 | checkGlError("glGetAttribLocation"); 182 | LOG("glGetAttribLocation(\"positionHandle\") = %d\n", positionHandle); 183 | 184 | textureCoordHandle = glGetAttribLocation(shaderProgram, "aTexCoordinate"); 185 | checkGlError("glGetAttribLocation"); 186 | LOG("glGetAttribLocation(\"aTexCoordinater\") = %d\n", textureCoordHandle); 187 | 188 | textureTranformHandle = glGetUniformLocation(shaderProgram, "texTransform"); 189 | checkGlError("glGetAttribLocation"); 190 | LOG("glGetUniformLocation(\"texTransform\") = %d\n", textureTranformHandle); 191 | 192 | 193 | struct Vertices 194 | { 195 | float positions[4][4]; 196 | float texCoords[4][4]; 197 | }; 198 | 199 | const float x = 0.5f; 200 | const float y = 0.5f; 201 | const float z = -1.0f; 202 | 203 | static const Vertices vertices = 204 | { 205 | // positions 206 | { 207 | -x, y, z, 208 | -x, -y, z, 209 | x, -y, z, 210 | x, y, z 211 | }, 212 | // texCoords 213 | { 214 | 0.0f, 1.0f, 0.0f, 1.0f, 215 | 0.0f, 0.0f, 0.0f, 1.0f, 216 | 1.0f, 0.0f, 0.0f, 1.0f, 217 | 1.0f, 1.0f, 0.0f, 1.0f 218 | }, 219 | }; 220 | 221 | static const unsigned short indices[] = { 222 | 0, 1, 2, 0, 2 ,3 223 | }; 224 | 225 | glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, ib ); 226 | glBindVertexArray( 0 ) ; 227 | 228 | glGenVertexArrays( 1, &vao ); 229 | glBindVertexArray( vao ); 230 | 231 | glGenBuffers( 1, &vb ); 232 | glBindBuffer( GL_ARRAY_BUFFER, vb ); 233 | glBufferData( GL_ARRAY_BUFFER, sizeof( vertices ), &vertices, GL_STATIC_DRAW ); 234 | 235 | glGenBuffers( 1, &ib ) ; 236 | glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, ib ); 237 | glBufferData( GL_ELEMENT_ARRAY_BUFFER, sizeof( indices ), indices, GL_STATIC_DRAW ); 238 | 239 | 240 | glEnableVertexAttribArray ( positionHandle ); 241 | glVertexAttribPointer ( positionHandle, 3, GL_FLOAT, false, 0, (const GLvoid *)offsetof( Vertices, positions )); 242 | 243 | glEnableVertexAttribArray ( textureCoordHandle ); 244 | glVertexAttribPointer ( textureCoordHandle, 4, GL_FLOAT, false, 0, (const GLvoid *)offsetof( Vertices, texCoords )); 245 | 246 | 247 | glBindVertexArray( 0 ); 248 | 249 | glDisableVertexAttribArray( positionHandle ) ; 250 | glDisableVertexAttribArray( textureCoordHandle ); 251 | } 252 | 253 | 254 | void NativeMedia::setFrameAvailable(bool const available) { 255 | pthread_mutex_lock(&gMutex); 256 | fameAvailable = available; 257 | pthread_mutex_unlock(&gMutex); 258 | } 259 | 260 | void NativeMedia::renderFrame() { 261 | 262 | pthread_mutex_lock(&gMutex); 263 | 264 | if (fameAvailable) { 265 | Update(); 266 | } 267 | 268 | pthread_mutex_unlock(&gMutex); 269 | 270 | 271 | glViewport(0, 0, width, height); 272 | glClearColor(0.0f, 0.0f, 1.0f, 1.0f); 273 | checkGlError("glClearColor"); 274 | 275 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 276 | checkGlError("glClear"); 277 | 278 | glUseProgram(shaderProgram); 279 | checkGlError("glUseProgram"); 280 | 281 | glActiveTexture(GL_TEXTURE0) ; 282 | glBindTexture(GL_TEXTURE_EXTERNAL_OES, texId) ; 283 | 284 | glUniform1i(textureParamHandle, 0); 285 | 286 | glUniformMatrix4fv(textureTranformHandle, 1, GL_FALSE, texTransform); 287 | checkGlError("texTransform, glUniformMatrix4fv"); 288 | 289 | glBindVertexArray( vao ); 290 | glDrawElements( GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, (void *)0); 291 | checkGlError("glDrawElements"); 292 | 293 | glBindVertexArray( 0 ); 294 | glUseProgram(0); 295 | } 296 | 297 | 298 | void NativeMedia::destroy() { 299 | LOG_INFO("native destroy"); 300 | glDeleteVertexArrays( 1, &vao); 301 | glDeleteBuffers( 1, &vb ); 302 | glDeleteBuffers( 1, &ib ); 303 | glDeleteProgram(shaderProgram); 304 | } 305 | 306 | JNIEnv *AttachJava() 307 | { 308 | JavaVMAttachArgs args = {JNI_VERSION_1_4, 0, 0}; 309 | JNIEnv* jni; 310 | int status = gJavaVM->AttachCurrentThread( &jni, &args); 311 | if (status < 0) { 312 | LOG_ERROR(" faild to attach current thread!"); 313 | return NULL; 314 | } 315 | return jni; 316 | } 317 | 318 | void NativeMedia::setupSurfaceTexture() { 319 | 320 | glGenTextures(1, &texId); 321 | checkGlError("glGenTextures"); 322 | 323 | glBindTexture(GL_TEXTURE_EXTERNAL_OES, texId); 324 | checkGlError("glBindTexture"); 325 | 326 | glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 327 | glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 328 | glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 329 | glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 330 | 331 | jni = AttachJava(); 332 | 333 | if ( jni == NULL){ 334 | LOG_ERROR("AttachJava"); 335 | return; 336 | } 337 | 338 | const char *stClassPath = "android/graphics/SurfaceTexture"; 339 | const jclass surfaceTextureClass = jni->FindClass(stClassPath); 340 | if (surfaceTextureClass == 0) { 341 | LOG_ERROR("FindClass (%s) failed", stClassPath); 342 | } 343 | 344 | // // find the constructor that takes an int 345 | const jmethodID constructor = jni->GetMethodID( surfaceTextureClass, "", "(I)V" ); 346 | if (constructor == 0) { 347 | LOG_ERROR("GetMethonID() failed"); 348 | } 349 | 350 | jobject obj = jni->NewObject(surfaceTextureClass, constructor, texId); 351 | if (obj == 0) { 352 | LOG_ERROR("NewObject() failed"); 353 | } 354 | 355 | javaSurfaceTextureObj = jni->NewGlobalRef(obj); 356 | if (javaSurfaceTextureObj == 0) { 357 | LOG_ERROR("NewGlobalRef() failed"); 358 | } 359 | 360 | //Now that we have a globalRef, we can free the localRef 361 | jni->DeleteLocalRef(obj); 362 | 363 | updateTexImageMethodId = jni->GetMethodID( surfaceTextureClass, "updateTexImage", "()V"); 364 | if ( !updateTexImageMethodId ) { 365 | LOG_ERROR("couldn't get updateTexImageMethonId"); 366 | } 367 | 368 | getTimestampMethodId = jni->GetMethodID(surfaceTextureClass, "getTimestamp", "()J"); 369 | if (!getTimestampMethodId) { 370 | LOG_ERROR("couldn't get TimestampMethodId"); 371 | } 372 | 373 | getTransformMtxId = jni->GetMethodID(surfaceTextureClass, "getTransformMatrix", "([F)V"); 374 | if (!getTransformMtxId) { 375 | LOG_ERROR("couldn't get getTransformMtxId"); 376 | } 377 | 378 | // jclass objects are loacalRefs that need to be free; 379 | jni->DeleteLocalRef( surfaceTextureClass ); 380 | 381 | LOG_INFO("setupSurfaceTexture success: texId: %d", texId); 382 | } 383 | 384 | 385 | void NativeMedia::SetDefaultBufferSizse(const int width, const int height) { 386 | jni->CallVoidMethod(javaSurfaceTextureObj, setDefaultBufferSizeMethodId, width, height); 387 | } 388 | 389 | 390 | 391 | void NativeMedia::Update() { 392 | //latch the latest movie frame to the texture 393 | if (!javaSurfaceTextureObj) { 394 | return; 395 | } 396 | jni->CallVoidMethod(javaSurfaceTextureObj, updateTexImageMethodId); 397 | nanoTimeStamp = jni->CallLongMethod( javaSurfaceTextureObj, getTimestampMethodId); 398 | LOG("+++++updateTexImage++++++textureId: %p w:%d, h: %d ", &texId,width, height); 399 | 400 | } 401 | 402 | 403 | extern "C" { 404 | 405 | ////////////////////////////////////////////////////////////////////////////////////////// 406 | // java activity interface 407 | ////////////////////////////////////////////////////////////////////////////////////////// 408 | JNIEXPORT void JNICALL Java_com_example_jarry_NativeMediaWrapper_nativeOnCreate(JNIEnv *env, jobject obj) { 409 | LOG_INFO("nativeOnCreate"); 410 | gNativeMedia = new NativeMedia(); 411 | env->GetJavaVM(&gJavaVM); 412 | } 413 | 414 | JNIEXPORT void JNICALL Java_com_example_jarry_NativeMediaWrapper_nativeOnDestroy(JNIEnv *env, jobject obj) { 415 | LOG_INFO("nativeOnCreate"); 416 | gNativeMedia->destroy(); 417 | } 418 | 419 | /////////////////////////////////////////////////////////////////////////////////////////////////// 420 | // java gl_surface_view renderer interface 421 | ////////////////////////////////////////////////////////////////////////////////////////////////// 422 | JNIEXPORT void JNICALL Java_com_example_jarry_NativeMediaWrapper_nativeSurfaceCreated(JNIEnv *env, jobject obj) { 423 | LOG_INFO("nativeSurfaceCreated"); 424 | gNativeMedia->setupSurfaceTexture(); 425 | } 426 | JNIEXPORT void JNICALL Java_com_example_jarry_NativeMediaWrapper_nativeSurfaceChanged(JNIEnv *env, jobject obj, jint width, jint height) { 427 | LOG_INFO("nativeSurfaceChanged"); 428 | 429 | gNativeMedia->setupGraphics(width, height); 430 | } 431 | JNIEXPORT void JNICALL Java_com_example_jarry_NativeMediaWrapper_nativeDrawFrame(JNIEnv *env, jobject obj) { 432 | // LOG_INFO("nativeDrawFrame"); 433 | gNativeMedia->renderFrame(); 434 | } 435 | 436 | //////////////////////////////////////////////////////////////////////////////////////////////////// 437 | // java SurfaceTexture interface 438 | //////////////////////////////////////////////////////////////////////////////////////////////////// 439 | JNIEXPORT void JNICALL Java_com_example_jarry_NativeMediaWrapper_nativeFrameAailable(JNIEnv *env, jobject obj) { 440 | LOG_INFO("nativeFrameAailable"); 441 | gNativeMedia->setFrameAvailable(true); 442 | } 443 | 444 | JNIEXPORT jobject JNICALL Java_com_example_jarry_NativeMediaWrapper_nativeGetSurfaceTexture(JNIEnv *env, jobject obj) { 445 | LOG_INFO("nativeGetSurfaceTexture"); 446 | jobject surfaceTextureObj; 447 | surfaceTextureObj = gNativeMedia->getSurfaceTextureObject(); 448 | 449 | return surfaceTextureObj; 450 | } 451 | 452 | } // end extern ""C 453 | 454 | 455 | 456 | 457 | -------------------------------------------------------------------------------- /app/jni/NativeMedia.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Jarry on 2016/4/10 0010. 3 | // 4 | #ifndef PLAYVIDEO_TEXUTURE_NATIVEVIDEO_H 5 | #define PLAYVIDEO_TEXUTURE_NATIVEVIDEO_H 6 | 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | class NativeMedia { 16 | 17 | public: 18 | NativeMedia(); 19 | virtual ~NativeMedia(); 20 | 21 | 22 | void setupSurfaceTexture(); 23 | 24 | // For some java-side uses, you can set the size 25 | // of the buffer before it is used to control how 26 | // large it is. Video decompression and camera preview 27 | // always override the size automatically. 28 | void SetDefaultBufferSizse(const int width, const int height); 29 | 30 | // This can only be called with an active GL context. 31 | // As a side effect, the textureId will be bound to the 32 | // GL_TEXTURE_EXTERNAL_OES target of the currently active 33 | // texture unit. 34 | void Update(); 35 | 36 | void renderFrame(); 37 | void setupGraphics(int w, int h); 38 | void setFrameAvailable(bool const available); 39 | 40 | jobject getSurfaceTextureObject(); 41 | 42 | void destroy(); 43 | 44 | private: 45 | JNIEnv *jni; 46 | JavaVM *javaVM; 47 | 48 | bool running; 49 | bool fameAvailable; 50 | 51 | /**about---surfaceTexture*/ 52 | jobject javaSurfaceTextureObj; 53 | 54 | // Updated when Update() is called, can be used to 55 | // check if a new frame is available and ready 56 | // to be processed / mipmapped by other code. 57 | long long nanoTimeStamp; 58 | 59 | jmethodID updateTexImageMethodId; 60 | jmethodID getTimestampMethodId; 61 | jmethodID setDefaultBufferSizeMethodId; 62 | jmethodID getTransformMtxId; 63 | }; 64 | 65 | #endif //PLAYVIDEO_TEXUTURE_NATIVEVIDEO_H 66 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /root/Android/Sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/example/jarry/playvideo_texuture/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | package com.example.jarry.playvideo_texuture; 2 | 3 | import android.app.Application; 4 | import android.test.ApplicationTestCase; 5 | 6 | /** 7 | * Testing Fundamentals 8 | */ 9 | public class ApplicationTest extends ApplicationTestCase { 10 | public ApplicationTest() { 11 | super(Application.class); 12 | } 13 | } -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 15 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 29 | 30 | 34 | 35 | 39 | 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/jarry/GLViewMediaActivity.java: -------------------------------------------------------------------------------- 1 | package com.example.jarry; 2 | 3 | import android.content.Context; 4 | import android.graphics.SurfaceTexture; 5 | import android.media.MediaPlayer; 6 | import android.opengl.GLES11Ext; 7 | import android.opengl.GLES20; 8 | import android.opengl.GLSurfaceView; 9 | import android.opengl.GLUtils; 10 | import android.os.Environment; 11 | import android.support.v7.app.AppCompatActivity; 12 | import android.os.Bundle; 13 | import android.util.Log; 14 | import android.view.Surface; 15 | 16 | import com.example.jarry.playvideo_texuture.R; 17 | import com.example.jarry.utils.RawResourceReader; 18 | import com.example.jarry.utils.ShaderHelper; 19 | 20 | import java.io.IOException; 21 | import java.nio.ByteBuffer; 22 | import java.nio.ByteOrder; 23 | import java.nio.FloatBuffer; 24 | import java.nio.ShortBuffer; 25 | 26 | import javax.microedition.khronos.egl.EGLConfig; 27 | import javax.microedition.khronos.opengles.GL10; 28 | 29 | public class GLViewMediaActivity extends AppCompatActivity implements GLSurfaceView.Renderer, SurfaceTexture.OnFrameAvailableListener { 30 | 31 | public static final String videoPath = Environment.getExternalStorageDirectory().getPath()+"/Movies/不将就.mp4"; 32 | 33 | private boolean frameAvailable = false; 34 | int textureParamHandle; 35 | int textureCoordinateHandle; 36 | int positionHandle; 37 | int textureTranformHandle; 38 | 39 | /** 40 | * 41 | */ 42 | private static float squareSize = 1.0f; 43 | private static float squareCoords[] = { 44 | -squareSize, squareSize, // top left 45 | -squareSize, -squareSize, // bottom left 46 | squareSize, -squareSize, // bottom right 47 | squareSize, squareSize}; // top right 48 | 49 | private static short drawOrder[] = {0, 1, 2, 0, 2, 3}; 50 | 51 | private Context context; 52 | 53 | // Texture to be shown in backgrund 54 | private FloatBuffer textureBuffer; 55 | private float textureCoords[] = { 56 | 0.0f, 1.0f, 0.0f, 1.0f, 57 | 0.0f, 0.0f, 0.0f, 1.0f, 58 | 1.0f, 0.0f, 0.0f, 1.0f, 59 | 1.0f, 1.0f, 0.0f, 1.0f}; 60 | private int[] textures = new int[1]; 61 | 62 | private int width, height; 63 | 64 | private int shaderProgram; 65 | private FloatBuffer vertexBuffer; 66 | private ShortBuffer drawListBuffer; 67 | private float[] videoTextureTransform = new float[16]; 68 | private SurfaceTexture videoTexture; 69 | private GLSurfaceView glView; 70 | private MediaPlayer mediaPlayer; 71 | 72 | 73 | @Override 74 | protected void onCreate(Bundle savedInstanceState) { 75 | super.onCreate(savedInstanceState); 76 | // setContentView(R.layout.activity_main); 77 | context = this; 78 | glView = new GLSurfaceView(this); 79 | setContentView(glView); 80 | glView.setEGLContextClientVersion(2); 81 | glView.setRenderer(this); 82 | } 83 | 84 | private void playVideo() { 85 | if (mediaPlayer == null) { 86 | mediaPlayer = new MediaPlayer(); 87 | mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() { 88 | @Override 89 | public void onPrepared(MediaPlayer mp) { 90 | mp.start(); 91 | } 92 | }); 93 | Surface surface = new Surface(videoTexture); 94 | mediaPlayer.setSurface(surface); 95 | surface.release(); 96 | try { 97 | mediaPlayer.setDataSource(videoPath); 98 | mediaPlayer.prepareAsync(); 99 | } catch (IOException e) { 100 | e.printStackTrace(); 101 | } 102 | } else { 103 | mediaPlayer.start(); 104 | } 105 | } 106 | 107 | @Override 108 | protected void onPause() { 109 | super.onPause(); 110 | if (mediaPlayer != null) { 111 | mediaPlayer.pause(); 112 | } 113 | } 114 | @Override 115 | protected void onDestroy() { 116 | super.onDestroy(); 117 | if (mediaPlayer != null) { 118 | mediaPlayer.stop(); 119 | mediaPlayer.release(); 120 | mediaPlayer = null; 121 | } 122 | } 123 | 124 | @Override 125 | public void onSurfaceCreated(GL10 gl, EGLConfig config) { 126 | setupGraphics(); 127 | setupVertexBuffer(); 128 | setupTexture(); 129 | } 130 | 131 | @Override 132 | public void onSurfaceChanged(GL10 gl, int width, int height) { 133 | this.width = width; 134 | this.height = height; 135 | playVideo(); 136 | } 137 | 138 | @Override 139 | public void onDrawFrame(GL10 gl) { 140 | synchronized (this) { 141 | if (frameAvailable) { 142 | videoTexture.updateTexImage(); 143 | videoTexture.getTransformMatrix(videoTextureTransform); 144 | frameAvailable = false; 145 | } 146 | } 147 | GLES20.glClearColor(0.0f, 0.0f, 0.0f, 0.0f); 148 | GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT); 149 | 150 | GLES20.glViewport(0, 0, width, height); 151 | this.drawTexture(); 152 | 153 | } 154 | 155 | @Override 156 | public void onFrameAvailable(SurfaceTexture surfaceTexture) { 157 | synchronized (this) { 158 | frameAvailable = true; 159 | } 160 | } 161 | 162 | private void setupGraphics() { 163 | final String vertexShader = RawResourceReader.readTextFileFromRawResource(context, R.raw.vetext_sharder); 164 | final String fragmentShader = RawResourceReader.readTextFileFromRawResource(context, R.raw.fragment_sharder); 165 | 166 | final int vertexShaderHandle = ShaderHelper.compileShader(GLES20.GL_VERTEX_SHADER, vertexShader); 167 | final int fragmentShaderHandle = ShaderHelper.compileShader(GLES20.GL_FRAGMENT_SHADER, fragmentShader); 168 | shaderProgram = ShaderHelper.createAndLinkProgram(vertexShaderHandle, fragmentShaderHandle, 169 | new String[]{"texture", "vPosition", "vTexCoordinate", "textureTransform"}); 170 | 171 | GLES20.glUseProgram(shaderProgram); 172 | textureParamHandle = GLES20.glGetUniformLocation(shaderProgram, "texture"); 173 | textureCoordinateHandle = GLES20.glGetAttribLocation(shaderProgram, "vTexCoordinate"); 174 | positionHandle = GLES20.glGetAttribLocation(shaderProgram, "vPosition"); 175 | textureTranformHandle = GLES20.glGetUniformLocation(shaderProgram, "textureTransform"); 176 | } 177 | 178 | private void setupVertexBuffer() { 179 | // Draw list buffer 180 | ByteBuffer dlb = ByteBuffer.allocateDirect(drawOrder.length * 2); 181 | dlb.order(ByteOrder.nativeOrder()); 182 | drawListBuffer = dlb.asShortBuffer(); 183 | drawListBuffer.put(drawOrder); 184 | drawListBuffer.position(0); 185 | 186 | // Initialize the texture holder 187 | ByteBuffer bb = ByteBuffer.allocateDirect(squareCoords.length * 4); 188 | bb.order(ByteOrder.nativeOrder()); 189 | 190 | vertexBuffer = bb.asFloatBuffer(); 191 | vertexBuffer.put(squareCoords); 192 | vertexBuffer.position(0); 193 | } 194 | 195 | private void setupTexture() { 196 | ByteBuffer texturebb = ByteBuffer.allocateDirect(textureCoords.length * 4); 197 | texturebb.order(ByteOrder.nativeOrder()); 198 | 199 | textureBuffer = texturebb.asFloatBuffer(); 200 | textureBuffer.put(textureCoords); 201 | textureBuffer.position(0); 202 | 203 | // Generate the actual texture 204 | GLES20.glActiveTexture(GLES20.GL_TEXTURE0); 205 | GLES20.glGenTextures(1, textures, 0); 206 | checkGlError("Texture generate"); 207 | 208 | GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, textures[0]); 209 | checkGlError("Texture bind"); 210 | 211 | videoTexture = new SurfaceTexture(textures[0]); 212 | videoTexture.setOnFrameAvailableListener(this); 213 | } 214 | 215 | private void drawTexture() { 216 | // Draw texture 217 | 218 | GLES20.glEnableVertexAttribArray(positionHandle); 219 | GLES20.glVertexAttribPointer(positionHandle, 2, GLES20.GL_FLOAT, false, 0, vertexBuffer); 220 | 221 | GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, textures[0]); 222 | GLES20.glActiveTexture(GLES20.GL_TEXTURE0); 223 | GLES20.glUniform1i(textureParamHandle, 0); 224 | 225 | GLES20.glEnableVertexAttribArray(textureCoordinateHandle); 226 | GLES20.glVertexAttribPointer(textureCoordinateHandle, 4, GLES20.GL_FLOAT, false, 0, textureBuffer); 227 | 228 | GLES20.glUniformMatrix4fv(textureTranformHandle, 1, false, videoTextureTransform, 0); 229 | 230 | GLES20.glDrawElements(GLES20.GL_TRIANGLE_STRIP, drawOrder.length, GLES20.GL_UNSIGNED_SHORT, drawListBuffer); 231 | GLES20.glDisableVertexAttribArray(positionHandle); 232 | GLES20.glDisableVertexAttribArray(textureCoordinateHandle); 233 | } 234 | 235 | public void checkGlError(String op) { 236 | int error; 237 | while ((error = GLES20.glGetError()) != GLES20.GL_NO_ERROR) { 238 | Log.e("SurfaceTest", op + ": glError " + GLUtils.getEGLErrorString(error)); 239 | } 240 | } 241 | 242 | } 243 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/jarry/NativeMediaActivity.java: -------------------------------------------------------------------------------- 1 | package com.example.jarry; 2 | 3 | import android.graphics.SurfaceTexture; 4 | import android.media.MediaPlayer; 5 | import android.opengl.GLSurfaceView; 6 | import android.os.Environment; 7 | import android.support.v7.app.AppCompatActivity; 8 | import android.os.Bundle; 9 | import android.view.Surface; 10 | 11 | import java.io.IOException; 12 | 13 | import javax.microedition.khronos.egl.EGLConfig; 14 | import javax.microedition.khronos.opengles.GL10; 15 | 16 | /** 17 | * NativeMediaActivity 18 | * 19 | * if you want to render movie rightly on this activity, 20 | * you should set your environment for ANDROID_NDK or your local.properties contains ndk.dir 21 | */ 22 | public class NativeMediaActivity extends AppCompatActivity implements GLSurfaceView.Renderer, SurfaceTexture.OnFrameAvailableListener{ 23 | // public static final String videoPath = Environment.getExternalStorageDirectory().getPath()+"/Movies/不将就.mp4"; 24 | public static final String videoPath = "http://www.w3school.com.cn/example/html5/mov_bbb.mp4"; 25 | 26 | private SurfaceTexture videoTexture; 27 | private GLSurfaceView glView; 28 | private MediaPlayer mediaPlayer; 29 | 30 | @Override 31 | protected void onCreate(Bundle savedInstanceState) { 32 | super.onCreate(savedInstanceState); 33 | NativeMediaWrapper.nativeOnCreate(); 34 | 35 | glView = new GLSurfaceView(this); 36 | setContentView(glView); 37 | glView.setEGLContextClientVersion(2); 38 | glView.setRenderer(this); 39 | 40 | } 41 | 42 | @Override 43 | public void onSurfaceCreated(GL10 gl, EGLConfig config) { 44 | NativeMediaWrapper.nativeSurfaceCreated(); 45 | videoTexture = NativeMediaWrapper.nativeGetSurfaceTexture(); 46 | if (videoTexture != null) { 47 | videoTexture.setOnFrameAvailableListener(this); 48 | } 49 | } 50 | 51 | @Override 52 | public void onSurfaceChanged(GL10 gl, int width, int height) { 53 | NativeMediaWrapper.nativeSurfaceChanged(width, height); 54 | 55 | playVideo(); 56 | } 57 | 58 | @Override 59 | public void onDrawFrame(GL10 gl) { 60 | NativeMediaWrapper.nativeDrawFrame(); 61 | } 62 | 63 | 64 | @Override 65 | public void onFrameAvailable(SurfaceTexture surfaceTexture) { 66 | NativeMediaWrapper.nativeFrameAailable(); 67 | } 68 | 69 | 70 | private void playVideo() { 71 | if (mediaPlayer == null) { 72 | mediaPlayer = new MediaPlayer(); 73 | mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() { 74 | @Override 75 | public void onPrepared(MediaPlayer mp) { 76 | mp.start(); 77 | } 78 | }); 79 | if (videoTexture == null) { 80 | return; 81 | } 82 | Surface surface = new Surface(videoTexture); 83 | mediaPlayer.setSurface(surface); 84 | surface.release(); 85 | try { 86 | mediaPlayer.setDataSource(videoPath); 87 | mediaPlayer.prepareAsync(); 88 | } catch (IOException e) { 89 | e.printStackTrace(); 90 | } 91 | } else { 92 | mediaPlayer.start(); 93 | } 94 | } 95 | 96 | @Override 97 | protected void onPause() { 98 | super.onPause(); 99 | if (mediaPlayer != null) { 100 | mediaPlayer.pause(); 101 | } 102 | } 103 | @Override 104 | protected void onDestroy() { 105 | super.onDestroy(); 106 | NativeMediaWrapper.nativeOnDestroy(); 107 | 108 | if (mediaPlayer != null) { 109 | mediaPlayer.stop(); 110 | mediaPlayer.release(); 111 | mediaPlayer = null; 112 | } 113 | } 114 | 115 | } 116 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/jarry/NativeMediaWrapper.java: -------------------------------------------------------------------------------- 1 | package com.example.jarry; 2 | 3 | import android.graphics.SurfaceTexture; 4 | 5 | /** 6 | * Created by Administrator on 2016/4/17 0017. 7 | */ 8 | public class NativeMediaWrapper { 9 | static { 10 | System.loadLibrary("native_media"); 11 | } 12 | 13 | public static native void nativeOnCreate(); 14 | public static native void nativeOnDestroy(); 15 | public static native void nativeSurfaceCreated(); 16 | public static native void nativeSurfaceChanged(int width, int height); 17 | public static native void nativeDrawFrame(); 18 | public static native void nativeFrameAailable(); 19 | public static native SurfaceTexture nativeGetSurfaceTexture(); 20 | } 21 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/jarry/NavigatorActivity.java: -------------------------------------------------------------------------------- 1 | package com.example.jarry; 2 | 3 | import android.content.Intent; 4 | import android.support.v7.app.AppCompatActivity; 5 | import android.os.Bundle; 6 | import android.view.View; 7 | import android.widget.Toast; 8 | 9 | import com.example.jarry.playvideo_texuture.R; 10 | import com.example.jarry.playvideo_texuture.TextureViewMediaActivity; 11 | 12 | public class NavigatorActivity extends AppCompatActivity implements View.OnClickListener{ 13 | 14 | Intent mIntent; 15 | @Override 16 | protected void onCreate(Bundle savedInstanceState) { 17 | super.onCreate(savedInstanceState); 18 | setContentView(R.layout.activity_navigator); 19 | mIntent = new Intent(); 20 | findViewById(R.id.button_texture_view).setOnClickListener(this); 21 | findViewById(R.id.button_glsurfaceview).setOnClickListener(this); 22 | findViewById(R.id.button_glsurface_view_native).setOnClickListener(this); 23 | } 24 | 25 | 26 | @Override 27 | public void onClick(View v) { 28 | switch (v.getId()) { 29 | case R.id.button_texture_view: 30 | mIntent.setClass(this, TextureViewMediaActivity.class); 31 | startActivity(mIntent); 32 | Toast.makeText(this, "Play Video on TextureView", Toast.LENGTH_SHORT).show(); 33 | break; 34 | case R.id.button_glsurfaceview: 35 | mIntent.setClass(this, GLViewMediaActivity.class); 36 | startActivity(mIntent); 37 | Toast.makeText(this, "Play Video on GLSurfaceView", Toast.LENGTH_SHORT).show(); 38 | break; 39 | case R.id.button_glsurface_view_native: 40 | Toast.makeText(this, "prompt: this activity need to config ndk", Toast.LENGTH_SHORT).show(); 41 | Toast.makeText(this, "Play Video on Native", Toast.LENGTH_SHORT).show(); 42 | mIntent.setClass(this, NativeMediaActivity.class); 43 | startActivity(mIntent); 44 | break; 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/jarry/playvideo_texuture/TextureSurfaceRenderer.java: -------------------------------------------------------------------------------- 1 | package com.example.jarry.playvideo_texuture; 2 | 3 | import android.graphics.SurfaceTexture; 4 | import android.opengl.EGL14; 5 | import android.opengl.GLUtils; 6 | import android.util.Log; 7 | 8 | import javax.microedition.khronos.egl.EGL10; 9 | import javax.microedition.khronos.egl.EGLConfig; 10 | import javax.microedition.khronos.egl.EGLContext; 11 | import javax.microedition.khronos.egl.EGLDisplay; 12 | import javax.microedition.khronos.egl.EGLSurface; 13 | 14 | 15 | /** 16 | * 绘制前,renderer的配置,初始化EGL,开始一个绘制线程. 17 | * 这个类需要子类去实现相应的绘制工作. 18 | * 19 | * 具体流程可以参考http://www.cnblogs.com/kiffa/archive/2013/02/21/2921123.html 20 | * 相应的函数可以查看: https://www.khronos.org/registry/egl/sdk/docs/man/ 21 | */ 22 | public abstract class TextureSurfaceRenderer implements Runnable{ 23 | public static String LOG_TAG = TextureSurfaceRenderer.class.getSimpleName(); 24 | 25 | protected final SurfaceTexture surfaceTexture; 26 | protected int width; 27 | protected int height; 28 | 29 | private EGL10 egl; 30 | private EGLContext eglContext; 31 | private EGLDisplay eglDisplay; 32 | private EGLSurface eglSurface; 33 | 34 | 35 | /*** 36 | * 是否正在绘制(draw) 37 | */ 38 | private boolean running = false; 39 | 40 | public TextureSurfaceRenderer(SurfaceTexture surfaceTexture, int width, int height) { 41 | this.surfaceTexture = surfaceTexture; 42 | Log.e("TAG", "surfaceTexture obj="+ surfaceTexture.toString()); 43 | this.width = width; 44 | this.height = height; 45 | this.running = true; 46 | Thread thread = new Thread(this); 47 | thread.start(); 48 | } 49 | 50 | @Override 51 | public void run() { 52 | initEGL(); 53 | initGLComponents(); 54 | Log.d(LOG_TAG, "OpenGL init OK. start draw..."); 55 | 56 | while (running) { 57 | if (draw()) { 58 | egl.eglSwapBuffers(eglDisplay, eglSurface); 59 | } 60 | } 61 | 62 | deinitGLComponents(); 63 | deinitEGL(); 64 | } 65 | 66 | private void initEGL() { 67 | egl = (EGL10)EGLContext.getEGL(); 68 | //获取显示设备 69 | eglDisplay = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY); 70 | //version中存放EGL 版本号,int[0]为主版本号,int[1]为子版本号 71 | int version[] = new int[2]; 72 | egl.eglInitialize(eglDisplay, version); 73 | 74 | EGLConfig eglConfig = chooseEglConfig(); 75 | //创建EGL 的window surface 并且返回它的handles(eslSurface) 76 | eglSurface = egl.eglCreateWindowSurface(eglDisplay, eglConfig, surfaceTexture, null); 77 | 78 | eglContext = createContext(egl, eglDisplay, eglConfig); 79 | 80 | //设置当前的渲染环境 81 | try { 82 | if (eglSurface == null || eglSurface == EGL10.EGL_NO_SURFACE) { 83 | throw new RuntimeException("GL error:" + GLUtils.getEGLErrorString(egl.eglGetError())); 84 | } 85 | if (!egl.eglMakeCurrent(eglDisplay, eglSurface, eglSurface, eglContext)) { 86 | throw new RuntimeException("GL Make current Error"+ GLUtils.getEGLErrorString(egl.eglGetError())); 87 | } 88 | }catch (Exception e) { 89 | e.printStackTrace(); 90 | } 91 | } 92 | 93 | private void deinitEGL() { 94 | egl.eglMakeCurrent(eglDisplay, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT); 95 | egl.eglDestroySurface(eglDisplay, eglSurface); 96 | egl.eglDestroyContext(eglDisplay, eglContext); 97 | egl.eglTerminate(eglDisplay); 98 | Log.d(LOG_TAG, "OpenGL deinit OK."); 99 | } 100 | 101 | /** 102 | * 主要的绘制函数, 需在子类中去实现绘制 103 | */ 104 | protected abstract boolean draw(); 105 | 106 | /*** 107 | * 初始化opengl的一些组件比如vertextBuffer,sharders,textures等, 108 | * 通常在Opengl context 初始化以后被调用,需要子类去实现 109 | */ 110 | protected abstract void initGLComponents(); 111 | protected abstract void deinitGLComponents(); 112 | 113 | public abstract SurfaceTexture getVideoTexture(); 114 | 115 | /** 116 | * 为当前渲染的API创建一个渲染上下文 117 | * @return a handle to the context 118 | */ 119 | private EGLContext createContext(EGL10 egl, EGLDisplay eglDisplay, EGLConfig eglConfig) { 120 | int[] attrs = { 121 | EGL14.EGL_CONTEXT_CLIENT_VERSION, 2, 122 | EGL10.EGL_NONE 123 | }; 124 | return egl.eglCreateContext(eglDisplay, eglConfig, EGL10.EGL_NO_CONTEXT, attrs); 125 | } 126 | 127 | /*** 128 | * refer to https://www.khronos.org/registry/egl/sdk/docs/man/ 129 | * @return a EGL frame buffer configurations that match specified attributes 130 | */ 131 | private EGLConfig chooseEglConfig() { 132 | int[] configsCount = new int[1]; 133 | EGLConfig[] configs = new EGLConfig[1]; 134 | int[] attributes = getAttributes(); 135 | int confSize = 1; 136 | 137 | if (!egl.eglChooseConfig(eglDisplay, attributes, configs, confSize, configsCount)) { //获取满足attributes的config个数 138 | throw new IllegalArgumentException("Failed to choose config:"+ GLUtils.getEGLErrorString(egl.eglGetError())); 139 | } 140 | else if (configsCount[0] > 0) { 141 | return configs[0]; 142 | } 143 | 144 | return null; 145 | } 146 | 147 | /** 148 | * 构造绘制需要的特性列表,ARGB,DEPTH... 149 | */ 150 | private int[] getAttributes() 151 | { 152 | return new int[] { 153 | EGL10.EGL_RENDERABLE_TYPE, EGL14.EGL_OPENGL_ES2_BIT, //指定渲染api类别 154 | EGL10.EGL_RED_SIZE, 8, 155 | EGL10.EGL_GREEN_SIZE, 8, 156 | EGL10.EGL_BLUE_SIZE, 8, 157 | EGL10.EGL_ALPHA_SIZE, 8, 158 | EGL10.EGL_DEPTH_SIZE, 16, /*default depth buffer 16 choose a RGB_888 surface */ 159 | EGL10.EGL_STENCIL_SIZE, 0, 160 | EGL10.EGL_NONE //总是以EGL10.EGL_NONE结尾 161 | }; 162 | } 163 | 164 | /** 165 | * Call when activity pauses. This stops the rendering thread and deinitializes OpenGL. 166 | */ 167 | public void onPause() 168 | { 169 | running = false; 170 | } 171 | 172 | @Override 173 | protected void finalize() throws Throwable { 174 | super.finalize(); 175 | running = false; 176 | } 177 | } 178 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/jarry/playvideo_texuture/TextureViewMediaActivity.java: -------------------------------------------------------------------------------- 1 | package com.example.jarry.playvideo_texuture; 2 | 3 | import android.app.Activity; 4 | import android.graphics.SurfaceTexture; 5 | import android.media.MediaPlayer; 6 | import android.os.Environment; 7 | import android.os.Bundle; 8 | import android.util.Log; 9 | import android.view.Surface; 10 | import android.view.SurfaceHolder; 11 | import android.view.TextureView; 12 | 13 | 14 | import java.io.IOException; 15 | 16 | public class TextureViewMediaActivity extends Activity implements TextureView.SurfaceTextureListener, 17 | MediaPlayer.OnPreparedListener, SurfaceHolder.Callback{ 18 | private static final String TAG = "GLViewMediaActivity"; 19 | 20 | 21 | public static final String videoPath = Environment.getExternalStorageDirectory().getPath()+"/Movies/不将就.mp4"; 22 | private TextureView textureView; 23 | private MediaPlayer mediaPlayer; 24 | 25 | private TextureSurfaceRenderer videoRenderer; 26 | private int surfaceWidth; 27 | private int surfaceHeight; 28 | 29 | @Override 30 | protected void onCreate(Bundle savedInstanceState) { 31 | super.onCreate(savedInstanceState); 32 | 33 | setContentView(R.layout.activity_main); 34 | 35 | textureView = (TextureView) findViewById(R.id.id_textureview); 36 | textureView.setSurfaceTextureListener(this); 37 | 38 | } 39 | 40 | private void playVideo(SurfaceTexture surfaceTexture) { 41 | videoRenderer = new VideoTextureSurfaceRenderer(this, surfaceTexture, surfaceWidth, surfaceHeight); 42 | initMediaPlayer(); 43 | } 44 | 45 | private void initMediaPlayer() { 46 | try { 47 | this.mediaPlayer = new MediaPlayer(); 48 | 49 | while (videoRenderer.getVideoTexture() == null) { 50 | try { 51 | Thread.sleep(100); 52 | } catch (InterruptedException e) { 53 | e.printStackTrace(); 54 | } 55 | } 56 | 57 | Surface surface = new Surface(videoRenderer.getVideoTexture()); 58 | mediaPlayer.setDataSource(videoPath); 59 | mediaPlayer.setSurface(surface); 60 | 61 | surface.release(); 62 | 63 | mediaPlayer.prepareAsync(); 64 | mediaPlayer.setOnPreparedListener(this); 65 | mediaPlayer.setLooping(true); 66 | } catch (IllegalArgumentException e1) { 67 | // TODO Auto-generated catch block 68 | e1.printStackTrace(); 69 | } catch (SecurityException e1) { 70 | // TODO Auto-generated catch block 71 | e1.printStackTrace(); 72 | } catch (IllegalStateException e1) { 73 | // TODO Auto-generated catch block 74 | e1.printStackTrace(); 75 | } catch (IOException e1) { 76 | // TODO Auto-generated catch block 77 | e1.printStackTrace(); 78 | } 79 | } 80 | @Override 81 | public void onPrepared(MediaPlayer mp) { 82 | try { 83 | if (mp != null) { 84 | mp.start(); 85 | } 86 | } catch (IllegalStateException e) { 87 | e.printStackTrace(); 88 | } 89 | } 90 | 91 | 92 | @Override 93 | protected void onResume() { 94 | super.onResume(); 95 | 96 | Log.v(TAG, "GLViewMediaActivity::onResume()"); 97 | super.onResume(); 98 | } 99 | 100 | 101 | @Override protected void onStart() 102 | { 103 | Log.v(TAG, "GLViewMediaActivity::onStart()"); 104 | super.onStart(); 105 | } 106 | 107 | @Override 108 | protected void onPause() { 109 | Log.v(TAG, "GLViewMediaActivity::onPause()"); 110 | super.onPause(); 111 | if (videoRenderer != null) { 112 | videoRenderer.onPause(); 113 | videoRenderer = null; 114 | } 115 | if (mediaPlayer != null) { 116 | mediaPlayer.release(); 117 | mediaPlayer =null; 118 | } 119 | } 120 | 121 | @Override protected void onStop() 122 | { 123 | Log.v(TAG, "GLViewMediaActivity::onStop()"); 124 | super.onStop(); 125 | } 126 | 127 | @Override protected void onDestroy() 128 | { 129 | Log.v(TAG, "GLViewMediaActivity::onDestroy()"); 130 | super.onDestroy(); 131 | } 132 | 133 | 134 | @Override 135 | public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) { 136 | Log.v( TAG, "GLViewMediaActivity::onSurfaceTextureAvailable()"+ " tName:" + Thread.currentThread().getName() + " tid:"); 137 | 138 | surfaceWidth = width; 139 | surfaceHeight = height; 140 | playVideo(surface); 141 | } 142 | 143 | @Override 144 | public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) { 145 | } 146 | 147 | @Override 148 | public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) { 149 | return false; 150 | } 151 | 152 | @Override 153 | public void onSurfaceTextureUpdated(SurfaceTexture surface) { 154 | 155 | } 156 | 157 | 158 | /****************************************************************************************/ 159 | 160 | @Override 161 | public void surfaceCreated(SurfaceHolder holder) { 162 | Log.v( TAG, "GLViewMediaActivity::surfaceCreated()" ); 163 | } 164 | 165 | @Override 166 | public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { 167 | Log.v( TAG, "GLViewMediaActivity::surfaceChanged()" ); 168 | } 169 | 170 | @Override 171 | public void surfaceDestroyed(SurfaceHolder holder) { 172 | Log.v( TAG, "GLViewMediaActivity::surfaceDestroyed()" ); 173 | } 174 | } 175 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/jarry/playvideo_texuture/VideoTextureSurfaceRenderer.java: -------------------------------------------------------------------------------- 1 | package com.example.jarry.playvideo_texuture; 2 | 3 | 4 | import android.content.Context; 5 | import android.graphics.*; 6 | import android.opengl.GLES11Ext; 7 | import android.opengl.GLES20; 8 | import android.opengl.GLUtils; 9 | import android.util.Log; 10 | 11 | import com.example.jarry.utils.RawResourceReader; 12 | import com.example.jarry.utils.ShaderHelper; 13 | 14 | import java.nio.ByteBuffer; 15 | import java.nio.ByteOrder; 16 | import java.nio.FloatBuffer; 17 | import java.nio.ShortBuffer; 18 | 19 | public class VideoTextureSurfaceRenderer extends TextureSurfaceRenderer implements 20 | SurfaceTexture.OnFrameAvailableListener 21 | { 22 | 23 | public static final String TAG = VideoTextureSurfaceRenderer.class.getSimpleName(); 24 | 25 | /** 26 | * 27 | */ 28 | private static float squareSize = 1.0f; 29 | private static float squareCoords[] = { 30 | -squareSize, squareSize, // top left 31 | -squareSize, -squareSize, // bottom left 32 | squareSize, -squareSize, // bottom right 33 | squareSize, squareSize }; // top right 34 | 35 | private static short drawOrder[] = { 0, 1, 2, 0, 2, 3}; 36 | 37 | private Context context; 38 | 39 | // Texture to be shown in backgrund 40 | private FloatBuffer textureBuffer; 41 | private float textureCoords[] = { 42 | 0.0f, 1.0f, 0.0f, 1.0f, 43 | 0.0f, 0.0f, 0.0f, 1.0f, 44 | 1.0f, 0.0f, 0.0f, 1.0f, 45 | 1.0f, 1.0f, 0.0f, 1.0f }; 46 | private int[] textures = new int[1]; 47 | 48 | private int shaderProgram; 49 | private FloatBuffer vertexBuffer; 50 | private ShortBuffer drawListBuffer; 51 | 52 | private SurfaceTexture videoTexture; 53 | private float[] videoTextureTransform; 54 | private boolean frameAvailable = false; 55 | 56 | int textureParamHandle; 57 | int textureCoordinateHandle; 58 | int positionHandle; 59 | int textureTranformHandle; 60 | 61 | 62 | public VideoTextureSurfaceRenderer(Context context, SurfaceTexture texture, int width, int height) 63 | { 64 | super(texture, width, height); 65 | this.context = context; 66 | videoTextureTransform = new float[16]; 67 | } 68 | 69 | private void setupGraphics() 70 | { 71 | final String vertexShader = RawResourceReader.readTextFileFromRawResource(context, R.raw.vetext_sharder); 72 | final String fragmentShader = RawResourceReader.readTextFileFromRawResource(context, R.raw.fragment_sharder); 73 | 74 | final int vertexShaderHandle = ShaderHelper.compileShader(GLES20.GL_VERTEX_SHADER, vertexShader); 75 | final int fragmentShaderHandle = ShaderHelper.compileShader(GLES20.GL_FRAGMENT_SHADER, fragmentShader); 76 | shaderProgram = ShaderHelper.createAndLinkProgram(vertexShaderHandle, fragmentShaderHandle, 77 | new String[]{"texture","vPosition","vTexCoordinate","textureTransform"}); 78 | 79 | GLES20.glUseProgram(shaderProgram); 80 | textureParamHandle = GLES20.glGetUniformLocation(shaderProgram, "texture"); 81 | textureCoordinateHandle = GLES20.glGetAttribLocation(shaderProgram, "vTexCoordinate"); 82 | positionHandle = GLES20.glGetAttribLocation(shaderProgram, "vPosition"); 83 | textureTranformHandle = GLES20.glGetUniformLocation(shaderProgram, "textureTransform"); 84 | } 85 | 86 | private void setupVertexBuffer() 87 | { 88 | // Draw list buffer 89 | ByteBuffer dlb = ByteBuffer.allocateDirect(drawOrder. length * 2); 90 | dlb.order(ByteOrder.nativeOrder()); 91 | drawListBuffer = dlb.asShortBuffer(); 92 | drawListBuffer.put(drawOrder); 93 | drawListBuffer.position(0); 94 | 95 | // Initialize the texture holder 96 | ByteBuffer bb = ByteBuffer.allocateDirect(squareCoords.length * 4); 97 | bb.order(ByteOrder.nativeOrder()); 98 | 99 | vertexBuffer = bb.asFloatBuffer(); 100 | vertexBuffer.put(squareCoords); 101 | vertexBuffer.position(0); 102 | } 103 | 104 | private void setupTexture() 105 | { 106 | ByteBuffer texturebb = ByteBuffer.allocateDirect(textureCoords.length * 4); 107 | texturebb.order(ByteOrder.nativeOrder()); 108 | 109 | textureBuffer = texturebb.asFloatBuffer(); 110 | textureBuffer.put(textureCoords); 111 | textureBuffer.position(0); 112 | 113 | // Generate the actual texture 114 | GLES20.glActiveTexture(GLES20.GL_TEXTURE0); 115 | GLES20.glGenTextures(1, textures, 0); 116 | checkGlError("Texture generate"); 117 | 118 | GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, textures[0]); 119 | checkGlError("Texture bind"); 120 | 121 | videoTexture = new SurfaceTexture(textures[0]); 122 | videoTexture.setOnFrameAvailableListener(this); 123 | } 124 | 125 | @Override 126 | protected boolean draw() 127 | { 128 | synchronized (this) 129 | { 130 | if (frameAvailable) 131 | { 132 | videoTexture.updateTexImage(); 133 | videoTexture.getTransformMatrix(videoTextureTransform); 134 | frameAvailable = false; 135 | } 136 | else 137 | { 138 | return false; 139 | } 140 | 141 | } 142 | GLES20.glClearColor(0.0f, 0.0f, 0.0f, 0.0f); 143 | GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT); 144 | 145 | GLES20.glViewport(0, 0, width, height); 146 | this.drawTexture(); 147 | 148 | return true; 149 | } 150 | 151 | private void drawTexture() { 152 | // Draw texture 153 | 154 | GLES20.glEnableVertexAttribArray(positionHandle); 155 | GLES20.glVertexAttribPointer(positionHandle, 2, GLES20.GL_FLOAT, false, 0, vertexBuffer); 156 | 157 | GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, textures[0]); 158 | GLES20.glActiveTexture(GLES20.GL_TEXTURE0); 159 | GLES20.glUniform1i(textureParamHandle, 0); 160 | 161 | GLES20.glEnableVertexAttribArray(textureCoordinateHandle); 162 | GLES20.glVertexAttribPointer(textureCoordinateHandle, 4, GLES20.GL_FLOAT, false, 0, textureBuffer); 163 | 164 | GLES20.glUniformMatrix4fv(textureTranformHandle, 1, false, videoTextureTransform, 0); 165 | 166 | GLES20.glDrawElements(GLES20.GL_TRIANGLE_STRIP, drawOrder.length, GLES20.GL_UNSIGNED_SHORT, drawListBuffer); 167 | GLES20.glDisableVertexAttribArray(positionHandle); 168 | GLES20.glDisableVertexAttribArray(textureCoordinateHandle); 169 | } 170 | 171 | 172 | @Override 173 | protected void initGLComponents() 174 | { 175 | setupVertexBuffer(); 176 | setupTexture(); 177 | setupGraphics(); 178 | } 179 | 180 | @Override 181 | protected void deinitGLComponents() 182 | { 183 | GLES20.glDeleteTextures(1, textures, 0); 184 | GLES20.glDeleteProgram(shaderProgram); 185 | videoTexture.release(); 186 | videoTexture.setOnFrameAvailableListener(null); 187 | } 188 | 189 | 190 | public void checkGlError(String op) 191 | { 192 | int error; 193 | while ((error = GLES20.glGetError()) != GLES20.GL_NO_ERROR) { 194 | Log.e("SurfaceTest", op + ": glError " + GLUtils.getEGLErrorString(error)); 195 | } 196 | } 197 | 198 | @Override 199 | public SurfaceTexture getVideoTexture() 200 | { 201 | return videoTexture; 202 | } 203 | 204 | @Override 205 | public void onFrameAvailable(SurfaceTexture surfaceTexture) 206 | { 207 | synchronized (this) 208 | { 209 | frameAvailable = true; 210 | } 211 | } 212 | } 213 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/jarry/utils/RawResourceReader.java: -------------------------------------------------------------------------------- 1 | package com.example.jarry.utils; 2 | 3 | import android.content.Context; 4 | 5 | import java.io.BufferedReader; 6 | import java.io.IOException; 7 | import java.io.InputStream; 8 | import java.io.InputStreamReader; 9 | 10 | public class RawResourceReader 11 | { 12 | public static String readTextFileFromRawResource(final Context context, 13 | final int resourceId) 14 | { 15 | final InputStream inputStream = context.getResources().openRawResource( 16 | resourceId); 17 | final InputStreamReader inputStreamReader = new InputStreamReader( 18 | inputStream); 19 | final BufferedReader bufferedReader = new BufferedReader( 20 | inputStreamReader); 21 | 22 | String nextLine; 23 | final StringBuilder body = new StringBuilder(); 24 | 25 | try 26 | { 27 | while ((nextLine = bufferedReader.readLine()) != null) 28 | { 29 | body.append(nextLine); 30 | body.append('\n'); 31 | } 32 | } 33 | catch (IOException e) 34 | { 35 | return null; 36 | } 37 | 38 | return body.toString(); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/jarry/utils/ShaderHelper.java: -------------------------------------------------------------------------------- 1 | package com.example.jarry.utils; 2 | 3 | import android.opengl.GLES20; 4 | import android.util.Log; 5 | 6 | public class ShaderHelper 7 | { 8 | private static final String TAG = "ShaderHelper"; 9 | 10 | /** 11 | * Helper function to compile a shader. 12 | * 13 | * @param shaderType The shader type. 14 | * @param shaderSource The shader source code. 15 | * @return An OpenGL handle to the shader. 16 | */ 17 | public static int compileShader(final int shaderType, final String shaderSource) 18 | { 19 | int shaderHandle = GLES20.glCreateShader(shaderType); 20 | 21 | if (shaderHandle != 0) 22 | { 23 | // Pass in the shader source. 24 | GLES20.glShaderSource(shaderHandle, shaderSource); 25 | 26 | // Compile the shader. 27 | GLES20.glCompileShader(shaderHandle); 28 | 29 | // Get the compilation status. 30 | final int[] compileStatus = new int[1]; 31 | GLES20.glGetShaderiv(shaderHandle, GLES20.GL_COMPILE_STATUS, compileStatus, 0); 32 | 33 | // If the compilation failed, delete the shader. 34 | if (compileStatus[0] == 0) 35 | { 36 | Log.e(TAG, "Error compiling shader: " + GLES20.glGetShaderInfoLog(shaderHandle)); 37 | GLES20.glDeleteShader(shaderHandle); 38 | shaderHandle = 0; 39 | } 40 | } 41 | 42 | if (shaderHandle == 0) 43 | { 44 | throw new RuntimeException("Error creating shader."); 45 | } 46 | 47 | return shaderHandle; 48 | } 49 | 50 | /** 51 | * Helper function to compile and link a program. 52 | * 53 | * @param vertexShaderHandle An OpenGL handle to an already-compiled vertex shader. 54 | * @param fragmentShaderHandle An OpenGL handle to an already-compiled fragment shader. 55 | * @param attributes Attributes that need to be bound to the program. 56 | * @return An OpenGL handle to the program. 57 | */ 58 | public static int createAndLinkProgram(final int vertexShaderHandle, final int fragmentShaderHandle, final String[] attributes) 59 | { 60 | int programHandle = GLES20.glCreateProgram(); 61 | 62 | if (programHandle != 0) 63 | { 64 | // Bind the vertex shader to the program. 65 | GLES20.glAttachShader(programHandle, vertexShaderHandle); 66 | 67 | // Bind the fragment shader to the program. 68 | GLES20.glAttachShader(programHandle, fragmentShaderHandle); 69 | 70 | // Bind attributes 71 | if (attributes != null) 72 | { 73 | final int size = attributes.length; 74 | for (int i = 0; i < size; i++) 75 | { 76 | GLES20.glBindAttribLocation(programHandle, i, attributes[i]); 77 | } 78 | } 79 | 80 | // Link the two shaders together into a program. 81 | GLES20.glLinkProgram(programHandle); 82 | 83 | // Get the link status. 84 | final int[] linkStatus = new int[1]; 85 | GLES20.glGetProgramiv(programHandle, GLES20.GL_LINK_STATUS, linkStatus, 0); 86 | 87 | // If the link failed, delete the program. 88 | if (linkStatus[0] == 0) 89 | { 90 | Log.e(TAG, "Error compiling program: " + GLES20.glGetProgramInfoLog(programHandle)); 91 | GLES20.glDeleteProgram(programHandle); 92 | programHandle = 0; 93 | } 94 | } 95 | 96 | if (programHandle == 0) 97 | { 98 | throw new RuntimeException("Error creating program."); 99 | } 100 | 101 | return programHandle; 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/jarry/utils/TextureHelper.java: -------------------------------------------------------------------------------- 1 | package com.example.jarry.utils; 2 | 3 | import android.content.Context; 4 | import android.graphics.Bitmap; 5 | import android.graphics.BitmapFactory; 6 | import android.opengl.GLES20; 7 | import android.opengl.GLUtils; 8 | 9 | public class TextureHelper { 10 | public static int loadTexture(final Context context, final int resourceId) { 11 | final int[] textureHandle = new int[1]; 12 | 13 | GLES20.glGenTextures(1, textureHandle, 0); 14 | 15 | if (textureHandle[0] != 0) { 16 | final BitmapFactory.Options options = new BitmapFactory.Options(); 17 | options.inScaled = false; // No pre-scaling 18 | 19 | // Read in the resource 20 | final Bitmap bitmap = BitmapFactory.decodeResource( 21 | context.getResources(), resourceId, options); 22 | 23 | // Bind to the texture in OpenGL 24 | GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureHandle[0]); 25 | 26 | // Set filtering 27 | GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, 28 | GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST); 29 | GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, 30 | GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_NEAREST); 31 | 32 | // Load the bitmap into the bound texture. 33 | GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0); 34 | 35 | // Recycle the bitmap, since its data has been loaded into OpenGL. 36 | bitmap.recycle(); 37 | } 38 | 39 | if (textureHandle[0] == 0) { 40 | throw new RuntimeException("Error loading texture."); 41 | } 42 | 43 | return textureHandle[0]; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 7 | 8 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_navigator.xml: -------------------------------------------------------------------------------- 1 | 2 | 12 | 13 |