├── .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 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/.idea/runConfigurations.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
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 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 | generateDebugAndroidTestSources
19 | generateDebugSources
20 |
21 |
22 |
23 |
24 |
25 |
26 |
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 |
21 |
22 |
31 |
32 |
39 |
40 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/menu_main.xml:
--------------------------------------------------------------------------------
1 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ChouRay/PlayVideo-OpenGL/543c10f449571ba4106ac2dcd029404e880f4415/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ChouRay/PlayVideo-OpenGL/543c10f449571ba4106ac2dcd029404e880f4415/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ChouRay/PlayVideo-OpenGL/543c10f449571ba4106ac2dcd029404e880f4415/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ChouRay/PlayVideo-OpenGL/543c10f449571ba4106ac2dcd029404e880f4415/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/raw/fragment_sharder.glsl:
--------------------------------------------------------------------------------
1 | #extension GL_OES_EGL_image_external : require
2 | precision mediump float;
3 | uniform samplerExternalOES texture;
4 | varying vec2 v_TexCoordinate;
5 |
6 | void main () {
7 | vec4 color = texture2D(texture, v_TexCoordinate);
8 | gl_FragColor = color;
9 | }
--------------------------------------------------------------------------------
/app/src/main/res/raw/vetext_sharder.glsl:
--------------------------------------------------------------------------------
1 | attribute vec4 vPosition;
2 | attribute vec4 vTexCoordinate;
3 | uniform mat4 textureTransform;
4 | varying vec2 v_TexCoordinate;
5 |
6 | void main () {
7 | v_TexCoordinate = (textureTransform * vTexCoordinate).xy;
8 | gl_Position = vPosition;
9 | }
--------------------------------------------------------------------------------
/app/src/main/res/values-w820dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 64dp
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 16dp
4 | 16dp
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | PlayVideo-Texuture
3 |
4 | Hello world!
5 | Settings
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | import org.gradle.internal.os.OperatingSystem
2 |
3 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
4 |
5 | buildscript {
6 | repositories {
7 | google()
8 | jcenter()
9 | }
10 | dependencies {
11 | classpath 'com.android.tools.build:gradle:3.0.1'
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 | jcenter()
21 | }
22 | }
23 |
24 | def existNdk() {
25 | def ndkDir = System.getenv('ANDROID_NDK_HOME')
26 | if( ndkDir == null )
27 | {
28 | ndkDir = System.getenv('ANDROID_NDK')
29 | }
30 | if( ndkDir == null )
31 | {
32 | ndkDir = System.getenv('NDKROOT')
33 | }
34 | if( ndkDir == null )
35 | {
36 | Properties properties = new Properties()
37 | properties.load(project.rootProject.file('local.properties').newDataInputStream())
38 | ndkDir = properties.getProperty('ndk.dir')
39 | }
40 | // if( ndkDir == null )
41 | // {
42 | // throw new GradleException('NDK not found! Check your environment for ANDROID_NDK or your local.properties contains ndk.dir')
43 | // } else {
44 | // return ndkdir;
45 | // }
46 | return ndkDir;
47 | }
48 |
49 | def GetNDKBuildCmd() {
50 |
51 | def ndkDir = System.getenv('ANDROID_NDK_HOME')
52 | if( ndkDir == null )
53 | {
54 | ndkDir = System.getenv('ANDROID_NDK')
55 | }
56 | if( ndkDir == null )
57 | {
58 | ndkDir = System.getenv('NDKROOT')
59 | }
60 | if( ndkDir == null )
61 | {
62 | Properties properties = new Properties()
63 | properties.load(project.rootProject.file('local.properties').newDataInputStream())
64 | ndkDir = properties.getProperty('ndk.dir')
65 | }
66 | // if( ndkDir == null )
67 | // {
68 | // throw new GradleException('NDK not found! Check your environment for ANDROID_NDK or your local.properties contains ndk.dir')
69 | // }
70 |
71 | if (ndkDir == null) {
72 | printf("NDK not found! Check your environment for ANDROID_NDK or your local.properties contains ndk.dir")
73 | return null;
74 | }
75 | if ( OperatingSystem.current().isWindows() ) {
76 | return ndkDir + '/ndk-build.cmd'
77 | } else {
78 | return ndkDir + '/ndk-build'
79 | }
80 | }
81 |
82 |
83 | subprojects {
84 |
85 | if (GetNDKBuildCmd() == null) {
86 | return ;
87 | }
88 |
89 | task printProjectName << {
90 | println rootProject.name
91 | }
92 |
93 | task NDKBuildDebug(type: Exec) {
94 | commandLine GetNDKBuildCmd(), 'V=1', 'NDK_DEBUG=1'
95 | }
96 |
97 | task NDKBuildRelease(type: Exec) {
98 | commandLine GetNDKBuildCmd(), 'V=1', 'NDK_DEBUG=0'
99 | }
100 |
101 | task NDKBuildClean(type: Exec) {
102 | commandLine GetNDKBuildCmd(), 'clean'
103 | }
104 |
105 | }
106 |
--------------------------------------------------------------------------------
/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 | # Default value: -Xmx10248m -XX:MaxPermSize=256m
13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
14 |
15 | # When configured, Gradle will run in incubating parallel mode.
16 | # This option should only be used with decoupled projects. More details, visit
17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
18 | # org.gradle.parallel=true
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ChouRay/PlayVideo-OpenGL/543c10f449571ba4106ac2dcd029404e880f4415/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Wed Oct 21 11:34:03 PDT 2015
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 | # For Cygwin, ensure paths are in UNIX format before anything is touched.
46 | if $cygwin ; then
47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
48 | fi
49 |
50 | # Attempt to set APP_HOME
51 | # Resolve links: $0 may be a link
52 | PRG="$0"
53 | # Need this for relative symlinks.
54 | while [ -h "$PRG" ] ; do
55 | ls=`ls -ld "$PRG"`
56 | link=`expr "$ls" : '.*-> \(.*\)$'`
57 | if expr "$link" : '/.*' > /dev/null; then
58 | PRG="$link"
59 | else
60 | PRG=`dirname "$PRG"`"/$link"
61 | fi
62 | done
63 | SAVED="`pwd`"
64 | cd "`dirname \"$PRG\"`/" >&-
65 | APP_HOME="`pwd -P`"
66 | cd "$SAVED" >&-
67 |
68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
69 |
70 | # Determine the Java command to use to start the JVM.
71 | if [ -n "$JAVA_HOME" ] ; then
72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
73 | # IBM's JDK on AIX uses strange locations for the executables
74 | JAVACMD="$JAVA_HOME/jre/sh/java"
75 | else
76 | JAVACMD="$JAVA_HOME/bin/java"
77 | fi
78 | if [ ! -x "$JAVACMD" ] ; then
79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
80 |
81 | Please set the JAVA_HOME variable in your environment to match the
82 | location of your Java installation."
83 | fi
84 | else
85 | JAVACMD="java"
86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
87 |
88 | Please set the JAVA_HOME variable in your environment to match the
89 | location of your Java installation."
90 | fi
91 |
92 | # Increase the maximum file descriptors if we can.
93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
94 | MAX_FD_LIMIT=`ulimit -H -n`
95 | if [ $? -eq 0 ] ; then
96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
97 | MAX_FD="$MAX_FD_LIMIT"
98 | fi
99 | ulimit -n $MAX_FD
100 | if [ $? -ne 0 ] ; then
101 | warn "Could not set maximum file descriptor limit: $MAX_FD"
102 | fi
103 | else
104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
105 | fi
106 | fi
107 |
108 | # For Darwin, add options to specify how the application appears in the dock
109 | if $darwin; then
110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
111 | fi
112 |
113 | # For Cygwin, switch paths to Windows format before running java
114 | if $cygwin ; then
115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
158 | function splitJvmOpts() {
159 | JVM_OPTS=("$@")
160 | }
161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
163 |
164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
165 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------