Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(90)

Side by Side Diff: talk/app/webrtc/java/android/org/webrtc/SurfaceTextureHelper.java

Issue 1460703002: Implement AndroidTextureBuffer::NativeToI420. (Closed) Base URL: https://chromium.googlesource.com/external/webrtc.git@master
Patch Set: Get a shared ref to the java SurfaceTectureHelper. Created 5 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 /* 1 /*
2 * libjingle 2 * libjingle
3 * Copyright 2015 Google Inc. 3 * Copyright 2015 Google Inc.
4 * 4 *
5 * Redistribution and use in source and binary forms, with or without 5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met: 6 * modification, are permitted provided that the following conditions are met:
7 * 7 *
8 * 1. Redistributions of source code must retain the above copyright notice, 8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer. 9 * this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright notice, 10 * 2. Redistributions in binary form must reproduce the above copyright notice,
(...skipping 17 matching lines...) Expand all
28 package org.webrtc; 28 package org.webrtc;
29 29
30 import android.graphics.SurfaceTexture; 30 import android.graphics.SurfaceTexture;
31 import android.opengl.GLES11Ext; 31 import android.opengl.GLES11Ext;
32 import android.opengl.GLES20; 32 import android.opengl.GLES20;
33 import android.os.Build; 33 import android.os.Build;
34 import android.os.Handler; 34 import android.os.Handler;
35 import android.os.HandlerThread; 35 import android.os.HandlerThread;
36 import android.os.SystemClock; 36 import android.os.SystemClock;
37 37
38 import org.webrtc.Logging;
39
40 import java.nio.ByteBuffer;
41 import java.nio.FloatBuffer;
38 import java.util.concurrent.Callable; 42 import java.util.concurrent.Callable;
39 import java.util.concurrent.CountDownLatch; 43 import java.util.concurrent.CountDownLatch;
40 import java.util.concurrent.TimeUnit; 44 import java.util.concurrent.TimeUnit;
41 45
42 import javax.microedition.khronos.egl.EGLContext; 46 import javax.microedition.khronos.egl.EGLContext;
43 47
44 /** 48 /**
45 * Helper class to create and synchronize access to a SurfaceTexture. The caller will get notified 49 * Helper class to create and synchronize access to a SurfaceTexture. The caller will get notified
46 * of new frames in onTextureFrameAvailable(), and should call returnTextureFram e() when done with 50 * of new frames in onTextureFrameAvailable(), and should call returnTextureFram e() when done with
47 * the frame. Only one texture frame can be in flight at once, so returnTextureF rame() must be 51 * the frame. Only one texture frame can be in flight at once, so returnTextureF rame() must be
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
87 // http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.andr oid/android/5.1.1_r1/android/graphics/SurfaceTexture.java#195. 91 // http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.andr oid/android/5.1.1_r1/android/graphics/SurfaceTexture.java#195.
88 // Therefore, in order to control the callback thread on API lvl < 21, the S urfaceTextureHelper 92 // Therefore, in order to control the callback thread on API lvl < 21, the S urfaceTextureHelper
89 // is constructed on the |handler| thread. 93 // is constructed on the |handler| thread.
90 return ThreadUtils.invokeUninterruptibly(finalHandler, new Callable<SurfaceT extureHelper>() { 94 return ThreadUtils.invokeUninterruptibly(finalHandler, new Callable<SurfaceT extureHelper>() {
91 @Override public SurfaceTextureHelper call() { 95 @Override public SurfaceTextureHelper call() {
92 return new SurfaceTextureHelper(sharedContext, finalHandler, (handler == null)); 96 return new SurfaceTextureHelper(sharedContext, finalHandler, (handler == null));
93 } 97 }
94 }); 98 });
95 } 99 }
96 100
101 // State for RGBA conversion, instantiated on demand.
102 static private class ConvertRGBA {
magjed_webrtc 2015/12/03 12:33:58 I don't want to land a ConvertToRGBA until we need
nisse-webrtc 2015/12/03 13:35:20 I'll do. I wonder if it's worth the effort to keep
magjed_webrtc 2015/12/03 14:30:46 Yes, do that :) It is also saved in the patch hist
103 private final EglBase eglBase;
104 private GlRectDrawer drawer;
105 ConvertRGBA (EGLContext sharedContext) {
106 eglBase = new EglBase(sharedContext, EglBase.CONFIG_PIXEL_BUFFER);
107 drawer = null;
108 }
109
110 public void convert(ByteBuffer buf,
111 int width, int height, int textureId, float [] transformMatrix) {
112 synchronized(this) {
113 int size = 4 * width * height;
114 if (buf.capacity() < size) {
115 Logging.e(TAG, "needed size: " + size + ", available size: " + buf.cap acity());
116 throw new IllegalStateException("ConvertRGBA.convert called with too s mall buffer");
117 }
118 // Produce a frame buffer starting at top-left corner, not
119 // bottom-left.
120 transformMatrix =
121 RendererCommon.multiplyMatrices(transformMatrix,
122 RendererCommon.verticalFlipMatrix());
123
124 try {
125 // Reuse surface, if possible.
126 if (eglBase.hasSurface()) {
127 if (eglBase.surfaceWidth() != width ||
128 eglBase.surfaceHeight() != height){
129 eglBase.releaseSurface();
130 eglBase.createPbufferSurface(width, height);
131 }
132 } else {
133 eglBase.createPbufferSurface(width, height);
134 }
135
136 eglBase.makeCurrent();
137 GLES20.glViewport(0, 0, width, height);
138 GlUtil.checkNoGLES2Error("Viewport");
139
140 if (drawer == null)
141 drawer = new GlRectDrawer();
142
143 drawer.drawOes(textureId, transformMatrix);
144 GLES20.glReadPixels(0, 0, width, height, GLES20.GL_RGBA, GLES20.GL_UNS IGNED_BYTE, buf);
145 GlUtil.checkNoGLES2Error("glReadPixels");
146 }
147 finally {
148 eglBase.detachCurrent();
149 }
150 }
151 }
152 public void release() {
153 synchronized(this) {
154 eglBase.makeCurrent();
155 if (drawer != null)
156 drawer.release();
157 eglBase.release();
158 }
159 }
160 }
161
162 // State for YUV conversion, instantiated on demand.
163 static private class ConvertYUV {
164 private final EglBase eglBase;
165 private final GlShader shader;
166 private boolean released = false;
167
168 // Vertex coordinates in Normalized Device Coordinates, i.e.
169 // (-1, -1) is bottom-left and (1, 1) is top-right.
170 private static final FloatBuffer DEVICE_RECTANGLE =
171 GlUtil.createFloatBuffer(new float[] {
172 -1.0f, -1.0f, // Bottom left.
173 1.0f, -1.0f, // Bottom right.
174 -1.0f, 1.0f, // Top left.
175 1.0f, 1.0f, // Top right.
176 });
177
178 // Texture coordinates - (0, 0) is bottom-left and (1, 1) is top-right.
179 private static final FloatBuffer TEXTURE_RECTANGLE =
180 GlUtil.createFloatBuffer(new float[] {
181 0.0f, 0.0f, // Bottom left.
182 1.0f, 0.0f, // Bottom right.
183 0.0f, 1.0f, // Top left.
184 1.0f, 1.0f // Top right.
185 });
186
187 private static final String VERTEX_SHADER =
188 "varying vec2 interp_tc;\n"
189 + "attribute vec4 in_pos;\n"
190 + "attribute vec4 in_tc;\n"
191 + "\n"
192 + "uniform mat4 texMatrix;\n"
193 + "\n"
194 + "void main() {\n"
195 + " gl_Position = in_pos;\n"
196 + " interp_tc = (texMatrix * in_tc).xy;\n"
197 + "}\n";
198
199 private static final String FRAGMENT_SHADER =
200 "#extension GL_OES_EGL_image_external : require\n"
201 + "precision mediump float;\n"
202 + "varying vec2 interp_tc;\n"
203 + "\n"
204 + "uniform samplerExternalOES oesTex;\n"
205 // Difference in texture coordinate corresponding to one
206 // sub-pixel in the x direction.
207 + "uniform vec2 xUnit;\n"
208 // Color conversion coefficients, including constant term
209 + "uniform vec4 coeffs;\n"
210 + "\n"
211 + "void main() {\n"
212 // TODO(nisse): Arrange color values into a matrix?
213 + " gl_FragColor.r = coeffs.a + dot(coeffs.rgb,\n"
214 + " texture2D(oesTex, interp_tc - 1.5 * xUnit).rgb);\n"
magjed_webrtc 2015/12/03 12:33:58 The alpha value from the texture2D should always b
215 + " gl_FragColor.g = coeffs.a + dot(coeffs.rgb,\n"
216 + " texture2D(oesTex, interp_tc - 0.5 * xUnit).rgb);\n"
217 + " gl_FragColor.b = coeffs.a + dot(coeffs.rgb,\n"
218 + " texture2D(oesTex, interp_tc + 0.5 * xUnit).rgb);\n"
219 + " gl_FragColor.a = coeffs.a + dot(coeffs.rgb,\n"
220 + " texture2D(oesTex, interp_tc + 1.5 * xUnit).rgb);\n"
221 + "}\n";
222
223 private int texMatrixLoc;
224 private int xUnitLoc;
225 private int coeffsLoc;;
226
227 ConvertYUV (EGLContext sharedContext) {
228 eglBase = new EglBase(sharedContext, EglBase.CONFIG_PIXEL_RGBA_BUFFER);
229 eglBase.createDummyPbufferSurface();
230 eglBase.makeCurrent();
231 try {
magjed_webrtc 2015/12/03 12:33:58 You don't need this try-finally. Detaching the EGL
nisse-webrtc 2015/12/04 09:40:34 Done.
232 shader = new GlShader(VERTEX_SHADER, FRAGMENT_SHADER);
233 shader.useProgram();
234 texMatrixLoc = shader.getUniformLocation("texMatrix");
235 xUnitLoc = shader.getUniformLocation("xUnit");
236 coeffsLoc = shader.getUniformLocation("coeffs");
237 GLES20.glUniform1i(shader.getUniformLocation("oesTex"), 0);
238 GlUtil.checkNoGLES2Error("Initialize fragment shader uniform values.");
239 // Initialize vertex shader attributes.
240 shader.setVertexAttribArray("in_pos", 2, DEVICE_RECTANGLE);
241 // If the width is not a multiple of 4 pixels, the texture
242 // will be scaled up slightly and clipped at the right border.
243 shader.setVertexAttribArray("in_tc", 2, TEXTURE_RECTANGLE);
244 }
245 finally {
246 eglBase.detachCurrent();
247 }
248 }
249
250 public void convert(ByteBuffer buf,
251 int width, int height, int stride, int textureId, float [] transformMatr ix) {
magjed_webrtc 2015/12/03 12:33:58 why do you need a stride value? width/height shoul
nisse-webrtc 2015/12/03 13:35:20 To allow for some additional alignment, and at the
252 synchronized(this) {
magjed_webrtc 2015/12/03 12:33:58 If the whole function is synchronized on |this|, y
nisse-webrtc 2015/12/03 13:35:20 Acknowledged.
nisse-webrtc 2015/12/04 09:40:34 Done.
253 // TODO(nisse): For now only produces the Y plane.
254 if (released) {
255 throw new IllegalStateException(
256 "ConvertYUV.convert called on released object");
257 }
258 if (stride % 8 != 0) {
259 throw new IllegalArgumentException(
260 "Invalid stride, must be a multiple of 8");
magjed_webrtc 2015/12/03 12:33:58 why?
nisse-webrtc 2015/12/03 13:35:20 Because we do a split in half for drawing u and v,
261 }
262 if (stride < width){
263 throw new IllegalArgumentException(
264 "Invalid stride, must >= width");
265 }
266
267 int y_width = (width+3) / 4;
268 int uv_width = (width+7) / 8;
269 int uv_height = (height+1)/2;
270 int total_height = height + uv_height;
271 int size = stride * total_height;
272
273 Logging.e(TAG, "width: " + width + ", height: " + height +
274 ", y-width: " + y_width + ", stride: " + stride);
275
276 Logging.e(TAG, "matrix: \n " + transformMatrix[0]
277 + " " + transformMatrix[1]
278 + " " + transformMatrix[2]
279 + " " + transformMatrix[3]
280 + "\n " + transformMatrix[4]
281 + " " + transformMatrix[5]
282 + " " + transformMatrix[6]
283 + " " + transformMatrix[7]
284 + "\n " + transformMatrix[8]
285 + " " + transformMatrix[9]
286 + " " + transformMatrix[10]
287 + " " + transformMatrix[11]
288 + "\n " + transformMatrix[12]
289 + " " + transformMatrix[13]
290 + " " + transformMatrix[14]
291 + " " + transformMatrix[15]);
292
293 if (buf.capacity() < size) {
294 Logging.e(TAG, "needed size: " + size + ", available size: " + buf.cap acity());
295 throw new IllegalStateException("ConvertYUV.convert called with too sm all buffer");
magjed_webrtc 2015/12/03 12:33:58 IllegalArgument
nisse-webrtc 2015/12/04 09:40:34 Done.
296 }
297 // Produce a frame buffer starting at top-left corner, not
298 // bottom-left.
299 transformMatrix =
300 RendererCommon.multiplyMatrices(transformMatrix,
301 RendererCommon.verticalFlipMatrix());
302
303 try {
304 // Reuse surface, if possible. TODO(nisse): Add an eglBase
305 // helper function, say, makeCurrentWithSize.
306 if (eglBase.hasSurface()) {
307 if (eglBase.surfaceWidth() != stride/4 ||
308 eglBase.surfaceHeight() != total_height){
309 eglBase.releaseSurface();
310 eglBase.createPbufferSurface(stride/4, total_height);
311 }
312 } else {
313 eglBase.createPbufferSurface(stride/4, total_height);
314 }
315
316 eglBase.makeCurrent();
317
318 GlUtil.checkNoGLES2Error("Initialize fragment shader uniform values.") ;
319
320 GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
321 GlUtil.checkNoGLES2Error("Active texture");
322 GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, textureId);
323 GLES20.glUniformMatrix4fv(texMatrixLoc, 1, false, transformMatrix, 0);
324
325 // Draw Y */
326 GLES20.glViewport(0, 0, y_width, height);
327 GlUtil.checkNoGLES2Error("Viewport");
328 // Matrix * (1;0;0;0) / width. Note that opengl uses column major orde r.
329 GLES20.glUniform2f(xUnitLoc,
330 transformMatrix[0] / width,
331 transformMatrix[1] / width);
332 // Y'UV444 to RGB888, see
333 // https://en.wikipedia.org/wiki/YUV#Y.27UV444_to_RGB888_conversion
334 GLES20.glUniform4f(coeffsLoc, 0.299f, 0.587f, 0.114f, 0.0f);
335 GlUtil.checkNoGLES2Error("Binding texture and matrix");
336
337 Logging.e(TAG, "ConvertYUV: glDrawArrays");
338 GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
339 GlUtil.checkNoGLES2Error("glDrawArrays, Y");
340
341 // Draw U */
342 GLES20.glViewport(0, height, uv_width, uv_height);
343 GlUtil.checkNoGLES2Error("Viewport");
344 // Matrix * (1;0;0;0) / (2*width). Note that opengl uses column major order.
345 GLES20.glUniform2f(xUnitLoc,
346 transformMatrix[0] / (2.0f*width),
347 transformMatrix[1] / (2.0f*width));
348 /* Use ITU-R coefficients for U and V */
349 GLES20.glUniform4f(coeffsLoc, -0.169f, -0.331f, 0.499f, 0.5f);
350 GlUtil.checkNoGLES2Error("Binding texture and matrix");
351
352 Logging.e(TAG, "ConvertYUV: glDrawArrays");
353 GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
354 GlUtil.checkNoGLES2Error("glDrawArrays, U");
355
356 // Draw V */
357 GLES20.glViewport(stride/8, height, uv_width, uv_height);
358 GlUtil.checkNoGLES2Error("Viewport");
359 /* Use ITU-R coefficients for U and V */
360 GLES20.glUniform4f(coeffsLoc, 0.499f, -0.418f, -0.0813f, 0.5f);
361 GlUtil.checkNoGLES2Error("Binding texture and matrix");
362
363 Logging.e(TAG, "ConvertYUV: glDrawArrays");
364 GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
365 GlUtil.checkNoGLES2Error("glDrawArrays, V");
366
367 Logging.e(TAG, "ConvertYUV: glReadPixels");
368 GLES20.glReadPixels(0, 0, stride/4, total_height, GLES20.GL_RGBA,
369 GLES20.GL_UNSIGNED_BYTE, buf);
370 GlUtil.checkNoGLES2Error("glReadPixels");
371
372 // Unbind texture. Reportedly needed on some devices to get
373 // the texture updated from the camera.
374 GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, 0);
375 }
376 finally {
377 eglBase.detachCurrent();
378 }
379 }
380 }
381
382 public void release() {
383 synchronized(this) {
384 released = true;
385 shader.release();
386 eglBase.makeCurrent();
magjed_webrtc 2015/12/03 12:33:58 shader.release() need an EGLContext current, so yo
nisse-webrtc 2015/12/04 09:40:34 Done.
387 eglBase.release();
388 }
389 }
390 }
391
97 private final Handler handler; 392 private final Handler handler;
98 private boolean isOwningThread; 393 private boolean isOwningThread;
99 private final EglBase eglBase; 394 private final EglBase eglBase;
100 private final SurfaceTexture surfaceTexture; 395 private final SurfaceTexture surfaceTexture;
101 private final int oesTextureId; 396 private final int oesTextureId;
397 private ConvertRGBA convertRGBA;
398 private ConvertYUV convertYUV;
399
102 private OnTextureFrameAvailableListener listener; 400 private OnTextureFrameAvailableListener listener;
103 // The possible states of this class. 401 // The possible states of this class.
104 private boolean hasPendingTexture = false; 402 private boolean hasPendingTexture = false;
105 private boolean isTextureInUse = false; 403 private boolean isTextureInUse = false;
106 private boolean isQuitting = false; 404 private boolean isQuitting = false;
107 405
108 private SurfaceTextureHelper(EGLContext sharedContext, Handler handler, boolea n isOwningThread) { 406 private SurfaceTextureHelper(EGLContext sharedContext, Handler handler, boolea n isOwningThread) {
109 if (handler.getLooper().getThread() != Thread.currentThread()) { 407 if (handler.getLooper().getThread() != Thread.currentThread()) {
110 throw new IllegalStateException("SurfaceTextureHelper must be created on t he handler thread"); 408 throw new IllegalStateException("SurfaceTextureHelper must be created on t he handler thread");
111 } 409 }
112 this.handler = handler; 410 this.handler = handler;
113 this.isOwningThread = isOwningThread; 411 this.isOwningThread = isOwningThread;
114 412
115 eglBase = new EglBase(sharedContext, EglBase.ConfigType.PIXEL_BUFFER); 413 eglBase = new EglBase(sharedContext, EglBase.CONFIG_PIXEL_BUFFER);
116 eglBase.createDummyPbufferSurface(); 414 eglBase.createDummyPbufferSurface();
117 eglBase.makeCurrent(); 415 eglBase.makeCurrent();
118 416
119 oesTextureId = GlUtil.generateTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES); 417 oesTextureId = GlUtil.generateTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES);
120 surfaceTexture = new SurfaceTexture(oesTextureId); 418 surfaceTexture = new SurfaceTexture(oesTextureId);
121 } 419 }
122 420
421 private ConvertRGBA getConvertRGBA() {
422 // convertRGBA is assign once
423 if (convertRGBA != null)
424 return convertRGBA;
425
426 synchronized(this) {
427 if (convertRGBA == null)
428 convertRGBA = new ConvertRGBA(eglBase.getContext());
429 return convertRGBA;
430 }
431 }
432
433 private ConvertYUV getConvertYUV() {
434 // convertYUV is assign once
435 if (convertYUV != null)
436 return convertYUV;
437
438 synchronized(this) {
439 if (convertYUV == null)
440 convertYUV = new ConvertYUV(eglBase.getContext());
441 return convertYUV;
442 }
443 }
444
123 /** 445 /**
124 * Start to stream textures to the given |listener|. 446 * Start to stream textures to the given |listener|.
125 * A Listener can only be set once. 447 * A Listener can only be set once.
126 */ 448 */
127 public void setListener(OnTextureFrameAvailableListener listener) { 449 public void setListener(OnTextureFrameAvailableListener listener) {
128 if (this.listener != null) { 450 if (this.listener != null) {
129 throw new IllegalStateException("SurfaceTextureHelper listener has already been set."); 451 throw new IllegalStateException("SurfaceTextureHelper listener has already been set.");
130 } 452 }
131 this.listener = listener; 453 this.listener = listener;
132 surfaceTexture.setOnFrameAvailableListener(new SurfaceTexture.OnFrameAvailab leListener() { 454 surfaceTexture.setOnFrameAvailableListener(new SurfaceTexture.OnFrameAvailab leListener() {
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after
200 * onTextureFrameAvailable() after this function returns. 522 * onTextureFrameAvailable() after this function returns.
201 */ 523 */
202 public void disconnect(Handler handler) { 524 public void disconnect(Handler handler) {
203 if (this.handler != handler) { 525 if (this.handler != handler) {
204 throw new IllegalStateException("Wrong handler."); 526 throw new IllegalStateException("Wrong handler.");
205 } 527 }
206 isOwningThread = true; 528 isOwningThread = true;
207 disconnect(); 529 disconnect();
208 } 530 }
209 531
532 public void textureToRGBA(ByteBuffer buf,
533 int width, int height, int textureId, float [] transformMatrix) {
534
535 Logging.e(TAG, "textureToRGBA called");
536
537 if (textureId != oesTextureId)
538 throw new IllegalStateException("textureToByteBuffer called with unexpecte d textureId");
539
540 getConvertRGBA().convert(buf, width, height, textureId, transformMatrix);
541 }
542
543 public void textureToYUV(ByteBuffer buf,
544 int width, int height, int stride, int textureId, float [] transformMatrix ) {
545 Logging.e(TAG, "textureToYUV called");
546
547 if (textureId != oesTextureId)
548 throw new IllegalStateException("textureToByteBuffer called with unexpecte d textureId");
549
550 getConvertYUV().convert(buf, width, height, stride, textureId, transformMatr ix);
551 }
552
210 private void tryDeliverTextureFrame() { 553 private void tryDeliverTextureFrame() {
211 if (handler.getLooper().getThread() != Thread.currentThread()) { 554 if (handler.getLooper().getThread() != Thread.currentThread()) {
212 throw new IllegalStateException("Wrong thread."); 555 throw new IllegalStateException("Wrong thread.");
213 } 556 }
214 if (isQuitting || !hasPendingTexture || isTextureInUse) { 557 if (isQuitting || !hasPendingTexture || isTextureInUse) {
215 return; 558 return;
216 } 559 }
217 isTextureInUse = true; 560 isTextureInUse = true;
218 hasPendingTexture = false; 561 hasPendingTexture = false;
219 562
220 eglBase.makeCurrent(); 563 eglBase.makeCurrent();
221 surfaceTexture.updateTexImage(); 564 surfaceTexture.updateTexImage();
222 565
223 final float[] transformMatrix = new float[16]; 566 final float[] transformMatrix = new float[16];
224 surfaceTexture.getTransformMatrix(transformMatrix); 567 surfaceTexture.getTransformMatrix(transformMatrix);
225 final long timestampNs = (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_C REAM_SANDWICH) 568 final long timestampNs = (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_C REAM_SANDWICH)
226 ? surfaceTexture.getTimestamp() 569 ? surfaceTexture.getTimestamp()
227 : TimeUnit.MILLISECONDS.toNanos(SystemClock.elapsedRealtime()); 570 : TimeUnit.MILLISECONDS.toNanos(SystemClock.elapsedRealtime());
228 listener.onTextureFrameAvailable(oesTextureId, transformMatrix, timestampNs) ; 571 listener.onTextureFrameAvailable(oesTextureId, transformMatrix, timestampNs) ;
229 } 572 }
230 573
231 private void release() { 574 private void release() {
232 if (handler.getLooper().getThread() != Thread.currentThread()) { 575 if (handler.getLooper().getThread() != Thread.currentThread()) {
233 throw new IllegalStateException("Wrong thread."); 576 throw new IllegalStateException("Wrong thread.");
234 } 577 }
235 if (isTextureInUse || !isQuitting) { 578 if (isTextureInUse || !isQuitting) {
236 throw new IllegalStateException("Unexpected release."); 579 throw new IllegalStateException("Unexpected release.");
237 } 580 }
581 synchronized (this) {
582 if (convertRGBA != null)
583 convertRGBA.release();
584 if (convertYUV != null)
585 convertYUV.release();
586 }
238 eglBase.makeCurrent(); 587 eglBase.makeCurrent();
239 GLES20.glDeleteTextures(1, new int[] {oesTextureId}, 0); 588 GLES20.glDeleteTextures(1, new int[] {oesTextureId}, 0);
240 surfaceTexture.release(); 589 surfaceTexture.release();
241 eglBase.release(); 590 eglBase.release();
242 handler.getLooper().quit(); 591 handler.getLooper().quit();
243 } 592 }
244 } 593 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698