OLD | NEW |
1 /* | 1 /* |
2 * libjingle | 2 * libjingle |
3 * Copyright 2014 Google Inc. | 3 * Copyright 2014 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 24 matching lines...) Expand all Loading... |
35 import javax.microedition.khronos.opengles.GL10; | 35 import javax.microedition.khronos.opengles.GL10; |
36 | 36 |
37 import android.annotation.SuppressLint; | 37 import android.annotation.SuppressLint; |
38 import android.graphics.Point; | 38 import android.graphics.Point; |
39 import android.graphics.Rect; | 39 import android.graphics.Rect; |
40 import android.graphics.SurfaceTexture; | 40 import android.graphics.SurfaceTexture; |
41 import android.opengl.EGL14; | 41 import android.opengl.EGL14; |
42 import android.opengl.EGLContext; | 42 import android.opengl.EGLContext; |
43 import android.opengl.GLES20; | 43 import android.opengl.GLES20; |
44 import android.opengl.GLSurfaceView; | 44 import android.opengl.GLSurfaceView; |
45 import android.opengl.Matrix; | |
46 import android.util.Log; | 45 import android.util.Log; |
47 | 46 |
48 import org.webrtc.VideoRenderer.I420Frame; | 47 import org.webrtc.VideoRenderer.I420Frame; |
49 | 48 |
50 /** | 49 /** |
51 * Efficiently renders YUV frames using the GPU for CSC. | 50 * Efficiently renders YUV frames using the GPU for CSC. |
52 * Clients will want first to call setView() to pass GLSurfaceView | 51 * Clients will want first to call setView() to pass GLSurfaceView |
53 * and then for each video stream either create instance of VideoRenderer using | 52 * and then for each video stream either create instance of VideoRenderer using |
54 * createGui() call or VideoRenderer.Callbacks interface using create() call. | 53 * createGui() call or VideoRenderer.Callbacks interface using create() call. |
55 * Only one instance of the class can be created. | 54 * Only one instance of the class can be created. |
56 */ | 55 */ |
57 public class VideoRendererGui implements GLSurfaceView.Renderer { | 56 public class VideoRendererGui implements GLSurfaceView.Renderer { |
58 private static VideoRendererGui instance = null; | 57 private static VideoRendererGui instance = null; |
59 private static Runnable eglContextReady = null; | 58 private static Runnable eglContextReady = null; |
60 private static final String TAG = "VideoRendererGui"; | 59 private static final String TAG = "VideoRendererGui"; |
61 private GLSurfaceView surface; | 60 private GLSurfaceView surface; |
62 private static EGLContext eglContext = null; | 61 private static EGLContext eglContext = null; |
63 // Indicates if SurfaceView.Renderer.onSurfaceCreated was called. | 62 // Indicates if SurfaceView.Renderer.onSurfaceCreated was called. |
64 // If true then for every newly created yuv image renderer createTexture() | 63 // If true then for every newly created yuv image renderer createTexture() |
65 // should be called. The variable is accessed on multiple threads and | 64 // should be called. The variable is accessed on multiple threads and |
66 // all accesses are synchronized on yuvImageRenderers' object lock. | 65 // all accesses are synchronized on yuvImageRenderers' object lock. |
67 private boolean onSurfaceCreatedCalled; | 66 private boolean onSurfaceCreatedCalled; |
68 private int screenWidth; | 67 private int screenWidth; |
69 private int screenHeight; | 68 private int screenHeight; |
70 // List of yuv renderers. | 69 // List of yuv renderers. |
71 private ArrayList<YuvImageRenderer> yuvImageRenderers; | 70 private ArrayList<YuvImageRenderer> yuvImageRenderers; |
72 private GlRectDrawer drawer; | 71 private GlRectDrawer drawer; |
73 // The minimum fraction of the frame content that will be shown for |SCALE_ASP
ECT_BALANCED|. | |
74 // This limits excessive cropping when adjusting display size. | |
75 private static float BALANCED_VISIBLE_FRACTION = 0.56f; | |
76 // Types of video scaling: | |
77 // SCALE_ASPECT_FIT - video frame is scaled to fit the size of the view by | |
78 // maintaining the aspect ratio (black borders may be displayed). | |
79 // SCALE_ASPECT_FILL - video frame is scaled to fill the size of the view by | |
80 // maintaining the aspect ratio. Some portion of the video frame may be | |
81 // clipped. | |
82 // SCALE_ASPECT_BALANCED - Compromise between FIT and FILL. Video frame will f
ill as much as | |
83 // possible of the view while maintaining aspect ratio, under the constraint t
hat at least | |
84 // |BALANCED_VISIBLE_FRACTION| of the frame content will be shown. | |
85 public static enum ScalingType | |
86 { SCALE_ASPECT_FIT, SCALE_ASPECT_FILL, SCALE_ASPECT_BALANCED } | |
87 private static final int EGL14_SDK_VERSION = | 72 private static final int EGL14_SDK_VERSION = |
88 android.os.Build.VERSION_CODES.JELLY_BEAN_MR1; | 73 android.os.Build.VERSION_CODES.JELLY_BEAN_MR1; |
89 // Current SDK version. | 74 // Current SDK version. |
90 private static final int CURRENT_SDK_VERSION = | 75 private static final int CURRENT_SDK_VERSION = |
91 android.os.Build.VERSION.SDK_INT; | 76 android.os.Build.VERSION.SDK_INT; |
92 | 77 |
93 private VideoRendererGui(GLSurfaceView surface) { | 78 private VideoRendererGui(GLSurfaceView surface) { |
94 this.surface = surface; | 79 this.surface = surface; |
95 // Create an OpenGL ES 2.0 context. | 80 // Create an OpenGL ES 2.0 context. |
96 surface.setPreserveEGLContextOnPause(true); | 81 surface.setPreserveEGLContextOnPause(true); |
(...skipping 19 matching lines...) Expand all Loading... |
116 // an offer (writing I420Frame to render) and early-returns (recording | 101 // an offer (writing I420Frame to render) and early-returns (recording |
117 // a dropped frame) if that queue is full. draw() call does a peek(), | 102 // a dropped frame) if that queue is full. draw() call does a peek(), |
118 // copies frame to texture and then removes it from a queue using poll(). | 103 // copies frame to texture and then removes it from a queue using poll(). |
119 LinkedBlockingQueue<I420Frame> frameToRenderQueue; | 104 LinkedBlockingQueue<I420Frame> frameToRenderQueue; |
120 // Local copy of incoming video frame. | 105 // Local copy of incoming video frame. |
121 private I420Frame yuvFrameToRender; | 106 private I420Frame yuvFrameToRender; |
122 private I420Frame textureFrameToRender; | 107 private I420Frame textureFrameToRender; |
123 // Type of video frame used for recent frame rendering. | 108 // Type of video frame used for recent frame rendering. |
124 private static enum RendererType { RENDERER_YUV, RENDERER_TEXTURE }; | 109 private static enum RendererType { RENDERER_YUV, RENDERER_TEXTURE }; |
125 private RendererType rendererType; | 110 private RendererType rendererType; |
126 private ScalingType scalingType; | 111 private RendererCommon.ScalingType scalingType; |
127 private boolean mirror; | 112 private boolean mirror; |
128 // Flag if renderFrame() was ever called. | 113 // Flag if renderFrame() was ever called. |
129 boolean seenFrame; | 114 boolean seenFrame; |
130 // Total number of video frames received in renderFrame() call. | 115 // Total number of video frames received in renderFrame() call. |
131 private int framesReceived; | 116 private int framesReceived; |
132 // Number of video frames dropped by renderFrame() because previous | 117 // Number of video frames dropped by renderFrame() because previous |
133 // frame has not been rendered yet. | 118 // frame has not been rendered yet. |
134 private int framesDropped; | 119 private int framesDropped; |
135 // Number of rendered video frames. | 120 // Number of rendered video frames. |
136 private int framesRendered; | 121 private int framesRendered; |
(...skipping 22 matching lines...) Expand all Loading... |
159 private int videoWidth; | 144 private int videoWidth; |
160 private int videoHeight; | 145 private int videoHeight; |
161 | 146 |
162 // This is the degree that the frame should be rotated clockwisely to have | 147 // This is the degree that the frame should be rotated clockwisely to have |
163 // it rendered up right. | 148 // it rendered up right. |
164 private int rotationDegree; | 149 private int rotationDegree; |
165 | 150 |
166 private YuvImageRenderer( | 151 private YuvImageRenderer( |
167 GLSurfaceView surface, int id, | 152 GLSurfaceView surface, int id, |
168 int x, int y, int width, int height, | 153 int x, int y, int width, int height, |
169 ScalingType scalingType, boolean mirror) { | 154 RendererCommon.ScalingType scalingType, boolean mirror) { |
170 Log.d(TAG, "YuvImageRenderer.Create id: " + id); | 155 Log.d(TAG, "YuvImageRenderer.Create id: " + id); |
171 this.surface = surface; | 156 this.surface = surface; |
172 this.id = id; | 157 this.id = id; |
173 this.scalingType = scalingType; | 158 this.scalingType = scalingType; |
174 this.mirror = mirror; | 159 this.mirror = mirror; |
175 frameToRenderQueue = new LinkedBlockingQueue<I420Frame>(1); | 160 frameToRenderQueue = new LinkedBlockingQueue<I420Frame>(1); |
176 layoutInPercentage = new Rect(x, y, Math.min(100, x + width), Math.min(100
, y + height)); | 161 layoutInPercentage = new Rect(x, y, Math.min(100, x + width), Math.min(100
, y + height)); |
177 updateTextureProperties = false; | 162 updateTextureProperties = false; |
178 rotationDegree = 0; | 163 rotationDegree = 0; |
179 } | 164 } |
(...skipping 12 matching lines...) Expand all Loading... |
192 GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, | 177 GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, |
193 GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR); | 178 GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR); |
194 GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, | 179 GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, |
195 GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE); | 180 GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE); |
196 GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, | 181 GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, |
197 GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE); | 182 GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE); |
198 } | 183 } |
199 GlUtil.checkNoGLES2Error("y/u/v glGenTextures"); | 184 GlUtil.checkNoGLES2Error("y/u/v glGenTextures"); |
200 } | 185 } |
201 | 186 |
202 private static float convertScalingTypeToVisibleFraction(ScalingType scaling
Type) { | |
203 switch (scalingType) { | |
204 case SCALE_ASPECT_FIT: | |
205 return 1.0f; | |
206 case SCALE_ASPECT_FILL: | |
207 return 0.0f; | |
208 case SCALE_ASPECT_BALANCED: | |
209 return BALANCED_VISIBLE_FRACTION; | |
210 default: | |
211 throw new IllegalArgumentException(); | |
212 } | |
213 } | |
214 | |
215 private static Point getDisplaySize(float minVisibleFraction, float videoAsp
ectRatio, | |
216 int maxDisplayWidth, int maxDisplayHeight) { | |
217 // If there is no constraint on the amount of cropping, fill the allowed d
isplay area. | |
218 if (minVisibleFraction == 0) { | |
219 return new Point(maxDisplayWidth, maxDisplayHeight); | |
220 } | |
221 // Each dimension is constrained on max display size and how much we are a
llowed to crop. | |
222 final int width = Math.min(maxDisplayWidth, | |
223 (int) (maxDisplayHeight / minVisibleFraction * videoAspectRatio)); | |
224 final int height = Math.min(maxDisplayHeight, | |
225 (int) (maxDisplayWidth / minVisibleFraction / videoAspectRatio)); | |
226 return new Point(width, height); | |
227 } | |
228 | |
229 private void checkAdjustTextureCoords() { | 187 private void checkAdjustTextureCoords() { |
230 synchronized(updateTextureLock) { | 188 synchronized(updateTextureLock) { |
231 if (!updateTextureProperties) { | 189 if (!updateTextureProperties) { |
232 return; | 190 return; |
233 } | 191 } |
234 // Initialize to maximum allowed area. Round to integer coordinates inwa
rds the layout | 192 // Initialize to maximum allowed area. Round to integer coordinates inwa
rds the layout |
235 // bounding box (ceil left/top and floor right/bottom) to not break cons
traints. | 193 // bounding box (ceil left/top and floor right/bottom) to not break cons
traints. |
236 displayLayout.set( | 194 displayLayout.set( |
237 (screenWidth * layoutInPercentage.left + 99) / 100, | 195 (screenWidth * layoutInPercentage.left + 99) / 100, |
238 (screenHeight * layoutInPercentage.top + 99) / 100, | 196 (screenHeight * layoutInPercentage.top + 99) / 100, |
239 (screenWidth * layoutInPercentage.right) / 100, | 197 (screenWidth * layoutInPercentage.right) / 100, |
240 (screenHeight * layoutInPercentage.bottom) / 100); | 198 (screenHeight * layoutInPercentage.bottom) / 100); |
241 Log.d(TAG, "ID: " + id + ". AdjustTextureCoords. Allowed display size:
" | 199 Log.d(TAG, "ID: " + id + ". AdjustTextureCoords. Allowed display size:
" |
242 + displayLayout.width() + " x " + displayLayout.height() + ". Video:
" + videoWidth | 200 + displayLayout.width() + " x " + displayLayout.height() + ". Video:
" + videoWidth |
243 + " x " + videoHeight + ". Rotation: " + rotationDegree + ". Mirror:
" + mirror); | 201 + " x " + videoHeight + ". Rotation: " + rotationDegree + ". Mirror:
" + mirror); |
244 final float videoAspectRatio = (rotationDegree % 180 == 0) | 202 final float videoAspectRatio = (rotationDegree % 180 == 0) |
245 ? (float) videoWidth / videoHeight | 203 ? (float) videoWidth / videoHeight |
246 : (float) videoHeight / videoWidth; | 204 : (float) videoHeight / videoWidth; |
247 // Adjust display size based on |scalingType|. | 205 // Adjust display size based on |scalingType|. |
248 final float minVisibleFraction = convertScalingTypeToVisibleFraction(sca
lingType); | 206 final Point displaySize = RendererCommon.getDisplaySize(scalingType, |
249 final Point displaySize = getDisplaySize(minVisibleFraction, videoAspect
Ratio, | 207 videoAspectRatio, displayLayout.width(), displayLayout.height()); |
250 displayLayout.width(), displayLayout.height()); | |
251 displayLayout.inset((displayLayout.width() - displaySize.x) / 2, | 208 displayLayout.inset((displayLayout.width() - displaySize.x) / 2, |
252 (displayLayout.height() - displaySize.y) / 2); | 209 (displayLayout.height() - displaySize.y) / 2); |
253 Log.d(TAG, " Adjusted display size: " + displayLayout.width() + " x " | 210 Log.d(TAG, " Adjusted display size: " + displayLayout.width() + " x " |
254 + displayLayout.height()); | 211 + displayLayout.height()); |
255 // The matrix stack is using post-multiplication, which means that matri
x operations: | 212 RendererCommon.getTextureMatrix(texMatrix, rotationDegree, mirror, video
AspectRatio, |
256 // A; B; C; will end up as A * B * C. When you apply this to a vertex, i
t will result in: | 213 (float) displayLayout.width() / displayLayout.height()); |
257 // v' = A * B * C * v, i.e. the last matrix operation is the first thing
that affects the | |
258 // vertex. This is the opposite of what you might expect. | |
259 Matrix.setIdentityM(texMatrix, 0); | |
260 // Move coordinates back to [0,1]x[0,1]. | |
261 Matrix.translateM(texMatrix, 0, 0.5f, 0.5f, 0.0f); | |
262 // Rotate frame clockwise in the XY-plane (around the Z-axis). | |
263 Matrix.rotateM(texMatrix, 0, -rotationDegree, 0, 0, 1); | |
264 // Scale one dimension until video and display size have same aspect rat
io. | |
265 final float displayAspectRatio = (float) displayLayout.width() / display
Layout.height(); | |
266 if (displayAspectRatio > videoAspectRatio) { | |
267 Matrix.scaleM(texMatrix, 0, 1, videoAspectRatio / displayAspectRatio
, 1); | |
268 } else { | |
269 Matrix.scaleM(texMatrix, 0, displayAspectRatio / videoAspectRatio, 1
, 1); | |
270 } | |
271 // TODO(magjed): We currently ignore the texture transform matrix from t
he SurfaceTexture. | |
272 // It contains a vertical flip that is hardcoded here instead. | |
273 Matrix.scaleM(texMatrix, 0, 1, -1, 1); | |
274 // Apply optional horizontal flip. | |
275 if (mirror) { | |
276 Matrix.scaleM(texMatrix, 0, -1, 1, 1); | |
277 } | |
278 // Center coordinates around origin. | |
279 Matrix.translateM(texMatrix, 0, -0.5f, -0.5f, 0.0f); | |
280 updateTextureProperties = false; | 214 updateTextureProperties = false; |
281 Log.d(TAG, " AdjustTextureCoords done"); | 215 Log.d(TAG, " AdjustTextureCoords done"); |
282 } | 216 } |
283 } | 217 } |
284 | 218 |
285 private void draw(GlRectDrawer drawer) { | 219 private void draw(GlRectDrawer drawer) { |
286 if (!seenFrame) { | 220 if (!seenFrame) { |
287 // No frame received yet - nothing to render. | 221 // No frame received yet - nothing to render. |
288 return; | 222 return; |
289 } | 223 } |
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
368 } | 302 } |
369 Log.d(TAG, "ID: " + id + ". YuvImageRenderer.setScreenSize: " + | 303 Log.d(TAG, "ID: " + id + ". YuvImageRenderer.setScreenSize: " + |
370 screenWidth + " x " + screenHeight); | 304 screenWidth + " x " + screenHeight); |
371 this.screenWidth = screenWidth; | 305 this.screenWidth = screenWidth; |
372 this.screenHeight = screenHeight; | 306 this.screenHeight = screenHeight; |
373 updateTextureProperties = true; | 307 updateTextureProperties = true; |
374 } | 308 } |
375 } | 309 } |
376 | 310 |
377 public void setPosition(int x, int y, int width, int height, | 311 public void setPosition(int x, int y, int width, int height, |
378 ScalingType scalingType, boolean mirror) { | 312 RendererCommon.ScalingType scalingType, boolean mirror) { |
379 final Rect layoutInPercentage = | 313 final Rect layoutInPercentage = |
380 new Rect(x, y, Math.min(100, x + width), Math.min(100, y + height)); | 314 new Rect(x, y, Math.min(100, x + width), Math.min(100, y + height)); |
381 synchronized(updateTextureLock) { | 315 synchronized(updateTextureLock) { |
382 if (layoutInPercentage.equals(this.layoutInPercentage) && scalingType ==
this.scalingType | 316 if (layoutInPercentage.equals(this.layoutInPercentage) && scalingType ==
this.scalingType |
383 && mirror == this.mirror) { | 317 && mirror == this.mirror) { |
384 return; | 318 return; |
385 } | 319 } |
386 Log.d(TAG, "ID: " + id + ". YuvImageRenderer.setPosition: (" + x + ", "
+ y + | 320 Log.d(TAG, "ID: " + id + ". YuvImageRenderer.setPosition: (" + x + ", "
+ y + |
387 ") " + width + " x " + height + ". Scaling: " + scalingType + | 321 ") " + width + " x " + height + ". Scaling: " + scalingType + |
388 ". Mirror: " + mirror); | 322 ". Mirror: " + mirror); |
(...skipping 19 matching lines...) Expand all Loading... |
408 | 342 |
409 this.videoWidth = videoWidth; | 343 this.videoWidth = videoWidth; |
410 this.videoHeight = videoHeight; | 344 this.videoHeight = videoHeight; |
411 rotationDegree = rotation; | 345 rotationDegree = rotation; |
412 int[] strides = { videoWidth, videoWidth / 2, videoWidth / 2 }; | 346 int[] strides = { videoWidth, videoWidth / 2, videoWidth / 2 }; |
413 | 347 |
414 // Clear rendering queue. | 348 // Clear rendering queue. |
415 frameToRenderQueue.poll(); | 349 frameToRenderQueue.poll(); |
416 // Re-allocate / allocate the frame. | 350 // Re-allocate / allocate the frame. |
417 yuvFrameToRender = new I420Frame(videoWidth, videoHeight, rotationDegree
, | 351 yuvFrameToRender = new I420Frame(videoWidth, videoHeight, rotationDegree
, |
418 strides, null); | 352 strides, null, 0); |
419 textureFrameToRender = new I420Frame(videoWidth, videoHeight, rotationDe
gree, | 353 textureFrameToRender = new I420Frame(videoWidth, videoHeight, rotationDe
gree, |
420 null, -1); | 354 null, -1, 0); |
421 updateTextureProperties = true; | 355 updateTextureProperties = true; |
422 Log.d(TAG, " YuvImageRenderer.setSize done."); | 356 Log.d(TAG, " YuvImageRenderer.setSize done."); |
423 } | 357 } |
424 } | 358 } |
425 | 359 |
426 @Override | 360 @Override |
427 public synchronized void renderFrame(I420Frame frame) { | 361 public synchronized void renderFrame(I420Frame frame) { |
428 setSize(frame.width, frame.height, frame.rotationDegree); | 362 setSize(frame.width, frame.height, frame.rotationDegree); |
429 long now = System.nanoTime(); | 363 long now = System.nanoTime(); |
430 framesReceived++; | 364 framesReceived++; |
431 // Skip rendering of this frame if setSize() was not called. | 365 // Skip rendering of this frame if setSize() was not called. |
432 if (yuvFrameToRender == null || textureFrameToRender == null) { | 366 if (yuvFrameToRender == null || textureFrameToRender == null) { |
433 framesDropped++; | 367 framesDropped++; |
| 368 VideoRenderer.renderFrameDone(frame); |
434 return; | 369 return; |
435 } | 370 } |
436 // Check input frame parameters. | 371 // Check input frame parameters. |
437 if (frame.yuvFrame) { | 372 if (frame.yuvFrame) { |
438 if (frame.yuvStrides[0] < frame.width || | 373 if (frame.yuvStrides[0] < frame.width || |
439 frame.yuvStrides[1] < frame.width / 2 || | 374 frame.yuvStrides[1] < frame.width / 2 || |
440 frame.yuvStrides[2] < frame.width / 2) { | 375 frame.yuvStrides[2] < frame.width / 2) { |
441 Log.e(TAG, "Incorrect strides " + frame.yuvStrides[0] + ", " + | 376 Log.e(TAG, "Incorrect strides " + frame.yuvStrides[0] + ", " + |
442 frame.yuvStrides[1] + ", " + frame.yuvStrides[2]); | 377 frame.yuvStrides[1] + ", " + frame.yuvStrides[2]); |
| 378 VideoRenderer.renderFrameDone(frame); |
443 return; | 379 return; |
444 } | 380 } |
445 // Check incoming frame dimensions. | 381 // Check incoming frame dimensions. |
446 if (frame.width != yuvFrameToRender.width || | 382 if (frame.width != yuvFrameToRender.width || |
447 frame.height != yuvFrameToRender.height) { | 383 frame.height != yuvFrameToRender.height) { |
448 throw new RuntimeException("Wrong frame size " + | 384 throw new RuntimeException("Wrong frame size " + |
449 frame.width + " x " + frame.height); | 385 frame.width + " x " + frame.height); |
450 } | 386 } |
451 } | 387 } |
452 | 388 |
453 if (frameToRenderQueue.size() > 0) { | 389 if (frameToRenderQueue.size() > 0) { |
454 // Skip rendering of this frame if previous frame was not rendered yet. | 390 // Skip rendering of this frame if previous frame was not rendered yet. |
455 framesDropped++; | 391 framesDropped++; |
| 392 VideoRenderer.renderFrameDone(frame); |
456 return; | 393 return; |
457 } | 394 } |
458 | 395 |
459 // Create a local copy of the frame. | 396 // Create a local copy of the frame. |
460 if (frame.yuvFrame) { | 397 if (frame.yuvFrame) { |
461 yuvFrameToRender.copyFrom(frame); | 398 yuvFrameToRender.copyFrom(frame); |
462 rendererType = RendererType.RENDERER_YUV; | 399 rendererType = RendererType.RENDERER_YUV; |
463 frameToRenderQueue.offer(yuvFrameToRender); | 400 frameToRenderQueue.offer(yuvFrameToRender); |
464 } else { | 401 } else { |
465 textureFrameToRender.copyFrom(frame); | 402 textureFrameToRender.copyFrom(frame); |
466 rendererType = RendererType.RENDERER_TEXTURE; | 403 rendererType = RendererType.RENDERER_TEXTURE; |
467 frameToRenderQueue.offer(textureFrameToRender); | 404 frameToRenderQueue.offer(textureFrameToRender); |
468 } | 405 } |
469 copyTimeNs += (System.nanoTime() - now); | 406 copyTimeNs += (System.nanoTime() - now); |
470 seenFrame = true; | 407 seenFrame = true; |
| 408 VideoRenderer.renderFrameDone(frame); |
471 | 409 |
472 // Request rendering. | 410 // Request rendering. |
473 surface.requestRender(); | 411 surface.requestRender(); |
474 } | 412 } |
475 | 413 |
476 // TODO(guoweis): Remove this once chrome code base is updated. | 414 // TODO(guoweis): Remove this once chrome code base is updated. |
477 @Override | 415 @Override |
478 public boolean canApplyRotation() { | 416 public boolean canApplyRotation() { |
479 return true; | 417 return true; |
480 } | 418 } |
481 } | 419 } |
482 | 420 |
483 /** Passes GLSurfaceView to video renderer. */ | 421 /** Passes GLSurfaceView to video renderer. */ |
484 public static void setView(GLSurfaceView surface, | 422 public static void setView(GLSurfaceView surface, |
485 Runnable eglContextReadyCallback) { | 423 Runnable eglContextReadyCallback) { |
486 Log.d(TAG, "VideoRendererGui.setView"); | 424 Log.d(TAG, "VideoRendererGui.setView"); |
487 instance = new VideoRendererGui(surface); | 425 instance = new VideoRendererGui(surface); |
488 eglContextReady = eglContextReadyCallback; | 426 eglContextReady = eglContextReadyCallback; |
489 } | 427 } |
490 | 428 |
491 public static EGLContext getEGLContext() { | 429 public static EGLContext getEGLContext() { |
492 return eglContext; | 430 return eglContext; |
493 } | 431 } |
494 | 432 |
495 /** | 433 /** |
496 * Creates VideoRenderer with top left corner at (x, y) and resolution | 434 * Creates VideoRenderer with top left corner at (x, y) and resolution |
497 * (width, height). All parameters are in percentage of screen resolution. | 435 * (width, height). All parameters are in percentage of screen resolution. |
498 */ | 436 */ |
499 public static VideoRenderer createGui(int x, int y, int width, int height, | 437 public static VideoRenderer createGui(int x, int y, int width, int height, |
500 ScalingType scalingType, boolean mirror) throws Exception { | 438 RendererCommon.ScalingType scalingType, boolean mirror) throws Exception { |
501 YuvImageRenderer javaGuiRenderer = create( | 439 YuvImageRenderer javaGuiRenderer = create( |
502 x, y, width, height, scalingType, mirror); | 440 x, y, width, height, scalingType, mirror); |
503 return new VideoRenderer(javaGuiRenderer); | 441 return new VideoRenderer(javaGuiRenderer); |
504 } | 442 } |
505 | 443 |
506 public static VideoRenderer.Callbacks createGuiRenderer( | 444 public static VideoRenderer.Callbacks createGuiRenderer( |
507 int x, int y, int width, int height, | 445 int x, int y, int width, int height, |
508 ScalingType scalingType, boolean mirror) { | 446 RendererCommon.ScalingType scalingType, boolean mirror) { |
509 return create(x, y, width, height, scalingType, mirror); | 447 return create(x, y, width, height, scalingType, mirror); |
510 } | 448 } |
511 | 449 |
512 /** | 450 /** |
513 * Creates VideoRenderer.Callbacks with top left corner at (x, y) and | 451 * Creates VideoRenderer.Callbacks with top left corner at (x, y) and |
514 * resolution (width, height). All parameters are in percentage of | 452 * resolution (width, height). All parameters are in percentage of |
515 * screen resolution. | 453 * screen resolution. |
516 */ | 454 */ |
517 public static YuvImageRenderer create(int x, int y, int width, int height, | 455 public static YuvImageRenderer create(int x, int y, int width, int height, |
518 ScalingType scalingType, boolean mirror) { | 456 RendererCommon.ScalingType scalingType, boolean mirror) { |
519 // Check display region parameters. | 457 // Check display region parameters. |
520 if (x < 0 || x > 100 || y < 0 || y > 100 || | 458 if (x < 0 || x > 100 || y < 0 || y > 100 || |
521 width < 0 || width > 100 || height < 0 || height > 100 || | 459 width < 0 || width > 100 || height < 0 || height > 100 || |
522 x + width > 100 || y + height > 100) { | 460 x + width > 100 || y + height > 100) { |
523 throw new RuntimeException("Incorrect window parameters."); | 461 throw new RuntimeException("Incorrect window parameters."); |
524 } | 462 } |
525 | 463 |
526 if (instance == null) { | 464 if (instance == null) { |
527 throw new RuntimeException( | 465 throw new RuntimeException( |
528 "Attempt to create yuv renderer before setting GLSurfaceView"); | 466 "Attempt to create yuv renderer before setting GLSurfaceView"); |
(...skipping 23 matching lines...) Expand all Loading... |
552 } | 490 } |
553 } | 491 } |
554 // Add yuv renderer to rendering list. | 492 // Add yuv renderer to rendering list. |
555 instance.yuvImageRenderers.add(yuvImageRenderer); | 493 instance.yuvImageRenderers.add(yuvImageRenderer); |
556 } | 494 } |
557 return yuvImageRenderer; | 495 return yuvImageRenderer; |
558 } | 496 } |
559 | 497 |
560 public static void update( | 498 public static void update( |
561 VideoRenderer.Callbacks renderer, | 499 VideoRenderer.Callbacks renderer, |
562 int x, int y, int width, int height, ScalingType scalingType, boolean mirr
or) { | 500 int x, int y, int width, int height, RendererCommon.ScalingType scalingTyp
e, boolean mirror) { |
563 Log.d(TAG, "VideoRendererGui.update"); | 501 Log.d(TAG, "VideoRendererGui.update"); |
564 if (instance == null) { | 502 if (instance == null) { |
565 throw new RuntimeException( | 503 throw new RuntimeException( |
566 "Attempt to update yuv renderer before setting GLSurfaceView"); | 504 "Attempt to update yuv renderer before setting GLSurfaceView"); |
567 } | 505 } |
568 synchronized (instance.yuvImageRenderers) { | 506 synchronized (instance.yuvImageRenderers) { |
569 for (YuvImageRenderer yuvImageRenderer : instance.yuvImageRenderers) { | 507 for (YuvImageRenderer yuvImageRenderer : instance.yuvImageRenderers) { |
570 if (yuvImageRenderer == renderer) { | 508 if (yuvImageRenderer == renderer) { |
571 yuvImageRenderer.setPosition(x, y, width, height, scalingType, mirror)
; | 509 yuvImageRenderer.setPosition(x, y, width, height, scalingType, mirror)
; |
572 } | 510 } |
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
634 GLES20.glViewport(0, 0, screenWidth, screenHeight); | 572 GLES20.glViewport(0, 0, screenWidth, screenHeight); |
635 GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT); | 573 GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT); |
636 synchronized (yuvImageRenderers) { | 574 synchronized (yuvImageRenderers) { |
637 for (YuvImageRenderer yuvImageRenderer : yuvImageRenderers) { | 575 for (YuvImageRenderer yuvImageRenderer : yuvImageRenderers) { |
638 yuvImageRenderer.draw(drawer); | 576 yuvImageRenderer.draw(drawer); |
639 } | 577 } |
640 } | 578 } |
641 } | 579 } |
642 | 580 |
643 } | 581 } |
OLD | NEW |