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

Side by Side Diff: webrtc/sdk/android/api/org/webrtc/VideoFrameDrawer.java

Issue 3008423002: Android: Add helper class VideoFrameDrawer that can render VideoFrames (Closed)
Patch Set: similarity=10 Created 3 years, 3 months 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
« no previous file with comments | « webrtc/sdk/android/api/org/webrtc/RendererCommon.java ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 * Copyright 2015 The WebRTC project authors. All Rights Reserved. 2 * Copyright 2017 The WebRTC project authors. All Rights Reserved.
3 * 3 *
4 * Use of this source code is governed by a BSD-style license 4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source 5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found 6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may 7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree. 8 * be found in the AUTHORS file in the root of the source tree.
9 */ 9 */
10 10
11 package org.webrtc; 11 package org.webrtc;
12 12
13 import android.graphics.Matrix;
13 import android.graphics.Point; 14 import android.graphics.Point;
14 import android.opengl.GLES20; 15 import android.opengl.GLES20;
15 import android.opengl.Matrix;
16 import android.view.View;
17 import java.nio.ByteBuffer; 16 import java.nio.ByteBuffer;
18 17
19 /** 18 /**
20 * Static helper functions for renderer implementations. 19 * Helper class to draw VideoFrames. Calls either drawer.drawOes, drawer.drawRgb , or
20 * drawer.drawYuv depending on the type of the buffer. The frame will be rendere d with rotation
21 * taken into account. You can supply an additional render matrix for custom tra nsformations.
21 */ 22 */
22 public class RendererCommon { 23 public class VideoFrameDrawer {
23 /** Interface for reporting rendering events. */
24 public static interface RendererEvents {
25 /**
26 * Callback fired once first frame is rendered.
27 */
28 public void onFirstFrameRendered();
29
30 /**
31 * Callback fired when rendered frame resolution or rotation has changed.
32 */
33 public void onFrameResolutionChanged(int videoWidth, int videoHeight, int ro tation);
34 }
35
36 /** Interface for rendering frames on an EGLSurface. */
37 public static interface GlDrawer {
38 /**
39 * Functions for drawing frames with different sources. The rendering surfac e target is
40 * implied by the current EGL context of the calling thread and requires no explicit argument.
41 * The coordinates specify the viewport location on the surface target.
42 */
43 void drawOes(int oesTextureId, float[] texMatrix, int frameWidth, int frameH eight,
44 int viewportX, int viewportY, int viewportWidth, int viewportHeight);
45 void drawRgb(int textureId, float[] texMatrix, int frameWidth, int frameHeig ht, int viewportX,
46 int viewportY, int viewportWidth, int viewportHeight);
47 void drawYuv(int[] yuvTextures, float[] texMatrix, int frameWidth, int frame Height,
48 int viewportX, int viewportY, int viewportWidth, int viewportHeight);
49
50 /**
51 * Release all GL resources. This needs to be done manually, otherwise resou rces may leak.
52 */
53 void release();
54 }
55
56 /** 24 /**
57 * Draws a VideoFrame.TextureBuffer. Calls either drawer.drawOes or drawer.dra wRgb 25 * Draws a VideoFrame.TextureBuffer. Calls either drawer.drawOes or drawer.dra wRgb
58 * depending on the type of the buffer. You can supply an additional render ma trix. This is 26 * depending on the type of the buffer. You can supply an additional render ma trix. This is
59 * used multiplied together with the transformation matrix of the frame. (M = renderMatrix * 27 * used multiplied together with the transformation matrix of the frame. (M = renderMatrix *
60 * transformationMatrix) 28 * transformationMatrix)
61 */ 29 */
62 static void drawTexture(GlDrawer drawer, VideoFrame.TextureBuffer buffer, 30 static void drawTexture(RendererCommon.GlDrawer drawer, VideoFrame.TextureBuff er buffer,
63 android.graphics.Matrix renderMatrix, int frameWidth, int frameHeight, int viewportX, 31 Matrix renderMatrix, int frameWidth, int frameHeight, int viewportX, int v iewportY,
64 int viewportY, int viewportWidth, int viewportHeight) { 32 int viewportWidth, int viewportHeight) {
65 android.graphics.Matrix finalMatrix = new android.graphics.Matrix(buffer.get TransformMatrix()); 33 Matrix finalMatrix = new Matrix(buffer.getTransformMatrix());
66 finalMatrix.preConcat(renderMatrix); 34 finalMatrix.preConcat(renderMatrix);
67 float[] finalGlMatrix = convertMatrixFromAndroidGraphicsMatrix(finalMatrix); 35 float[] finalGlMatrix = RendererCommon.convertMatrixFromAndroidGraphicsMatri x(finalMatrix);
68 switch (buffer.getType()) { 36 switch (buffer.getType()) {
69 case OES: 37 case OES:
70 drawer.drawOes(buffer.getTextureId(), finalGlMatrix, frameWidth, frameHe ight, viewportX, 38 drawer.drawOes(buffer.getTextureId(), finalGlMatrix, frameWidth, frameHe ight, viewportX,
71 viewportY, viewportWidth, viewportHeight); 39 viewportY, viewportWidth, viewportHeight);
72 break; 40 break;
73 case RGB: 41 case RGB:
74 drawer.drawRgb(buffer.getTextureId(), finalGlMatrix, frameWidth, frameHe ight, viewportX, 42 drawer.drawRgb(buffer.getTextureId(), finalGlMatrix, frameWidth, frameHe ight, viewportX,
75 viewportY, viewportWidth, viewportHeight); 43 viewportY, viewportWidth, viewportHeight);
76 break; 44 break;
77 default: 45 default:
78 throw new RuntimeException("Unknown texture type."); 46 throw new RuntimeException("Unknown texture type.");
79 } 47 }
80 } 48 }
81 49
82 /** 50 /**
83 * Helper class for uploading YUV bytebuffer frames to textures that handles s tride > width. This 51 * Helper class for uploading YUV bytebuffer frames to textures that handles s tride > width. This
84 * class keeps an internal ByteBuffer to avoid unnecessary allocations for int ermediate copies. 52 * class keeps an internal ByteBuffer to avoid unnecessary allocations for int ermediate copies.
85 */ 53 */
86 public static class YuvUploader { 54 private static class YuvUploader {
87 // Intermediate copy buffer for uploading yuv frames that are not packed, i. e. stride > width. 55 // Intermediate copy buffer for uploading yuv frames that are not packed, i. e. stride > width.
88 // TODO(magjed): Investigate when GL_UNPACK_ROW_LENGTH is available, or make a custom shader 56 // TODO(magjed): Investigate when GL_UNPACK_ROW_LENGTH is available, or make a custom shader
89 // that handles stride and compare performance with intermediate copy. 57 // that handles stride and compare performance with intermediate copy.
90 private ByteBuffer copyBuffer; 58 private ByteBuffer copyBuffer;
91 private int[] yuvTextures; 59 private int[] yuvTextures;
92 60
93 /** 61 /**
94 * Upload |planes| into OpenGL textures, taking stride into consideration. 62 * Upload |planes| into OpenGL textures, taking stride into consideration.
95 * 63 *
96 * @return Array of three texture indices corresponding to Y-, U-, and V-pla ne respectively. 64 * @return Array of three texture indices corresponding to Y-, U-, and V-pla ne respectively.
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
136 } 104 }
137 return yuvTextures; 105 return yuvTextures;
138 } 106 }
139 107
140 public int[] uploadFromBuffer(VideoFrame.I420Buffer buffer) { 108 public int[] uploadFromBuffer(VideoFrame.I420Buffer buffer) {
141 int[] strides = {buffer.getStrideY(), buffer.getStrideU(), buffer.getStrid eV()}; 109 int[] strides = {buffer.getStrideY(), buffer.getStrideU(), buffer.getStrid eV()};
142 ByteBuffer[] planes = {buffer.getDataY(), buffer.getDataU(), buffer.getDat aV()}; 110 ByteBuffer[] planes = {buffer.getDataY(), buffer.getDataU(), buffer.getDat aV()};
143 return uploadYuvData(buffer.getWidth(), buffer.getHeight(), strides, plane s); 111 return uploadYuvData(buffer.getWidth(), buffer.getHeight(), strides, plane s);
144 } 112 }
145 113
114 public int[] getYuvTextures() {
115 return yuvTextures;
116 }
117
146 /** 118 /**
147 * Releases cached resources. Uploader can still be used and the resources w ill be reallocated 119 * Releases cached resources. Uploader can still be used and the resources w ill be reallocated
148 * on first use. 120 * on first use.
149 */ 121 */
150 public void release() { 122 public void release() {
151 copyBuffer = null; 123 copyBuffer = null;
152 if (yuvTextures != null) { 124 if (yuvTextures != null) {
153 GLES20.glDeleteTextures(3, yuvTextures, 0); 125 GLES20.glDeleteTextures(3, yuvTextures, 0);
154 yuvTextures = null; 126 yuvTextures = null;
155 } 127 }
156 } 128 }
157 } 129 }
158 130
159 /** 131 private static int distance(float x0, float y0, float x1, float y1) {
160 * Helper class for determining layout size based on layout requirements, scal ing type, and video 132 return (int) Math.round(Math.hypot(x1 - x0, y1 - y0));
161 * aspect ratio. 133 }
162 */
163 public static class VideoLayoutMeasure {
164 // The scaling type determines how the video will fill the allowed layout ar ea in measure(). It
165 // can be specified separately for the case when video has matched orientati on with layout size
166 // and when there is an orientation mismatch.
167 private ScalingType scalingTypeMatchOrientation = ScalingType.SCALE_ASPECT_B ALANCED;
168 private ScalingType scalingTypeMismatchOrientation = ScalingType.SCALE_ASPEC T_BALANCED;
169 134
170 public void setScalingType(ScalingType scalingType) { 135 // These points are used to calculate the size of the part of the frame we are rendering.
171 this.scalingTypeMatchOrientation = scalingType; 136 final static float[] srcPoints =
172 this.scalingTypeMismatchOrientation = scalingType; 137 new float[] {0f /* x0 */, 0f /* y0 */, 1f /* x1 */, 0f /* y1 */, 0f /* x2 */, 1f /* y2 */};
138 private final float[] dstPoints = new float[6];
139 private final Point renderSize = new Point();
140 private int renderWidth;
141 private int renderHeight;
142
143 // Calculate the frame size after |renderMatrix| is applied. Stores the output in member variables
144 // |renderWidth| and |renderHeight| to avoid allocations since this function i s called for every
145 // frame.
146 private void calculateTransformedRenderSize(
147 int frameWidth, int frameHeight, Matrix renderMatrix) {
148 if (renderMatrix == null) {
149 renderWidth = frameWidth;
150 renderHeight = frameHeight;
151 return;
152 }
153 // Transform the texture coordinates (in the range [0, 1]) according to |ren derMatrix|.
154 renderMatrix.mapPoints(dstPoints, srcPoints);
155
156 // Multiply with the width and height to get the positions in terms of pixel s.
157 for (int i = 0; i < 3; ++i) {
158 dstPoints[i * 2 + 0] *= frameWidth;
159 dstPoints[i * 2 + 1] *= frameHeight;
173 } 160 }
174 161
175 public void setScalingType( 162 // Get the length of the sides of the transformed rectangle in terms of pixe ls.
176 ScalingType scalingTypeMatchOrientation, ScalingType scalingTypeMismatch Orientation) { 163 renderWidth = distance(dstPoints[0], dstPoints[1], dstPoints[2], dstPoints[3 ]);
177 this.scalingTypeMatchOrientation = scalingTypeMatchOrientation; 164 renderHeight = distance(dstPoints[0], dstPoints[1], dstPoints[4], dstPoints[ 5]);
178 this.scalingTypeMismatchOrientation = scalingTypeMismatchOrientation; 165 }
166
167 private final YuvUploader yuvUploader = new YuvUploader();
168 // This variable will only be used for checking reference equality and is used for caching I420
169 // textures.
170 private VideoFrame lastI420Frame;
171 private final Matrix renderMatrix = new Matrix();
172
173 public void drawFrame(VideoFrame frame, RendererCommon.GlDrawer drawer) {
174 drawFrame(frame, drawer, null /* additionalRenderMatrix */);
175 }
176
177 public void drawFrame(
178 VideoFrame frame, RendererCommon.GlDrawer drawer, Matrix additionalRenderM atrix) {
179 drawFrame(frame, drawer, additionalRenderMatrix, 0 /* viewportX */, 0 /* vie wportY */,
180 frame.getRotatedWidth(), frame.getRotatedHeight());
181 }
182
183 public void drawFrame(VideoFrame frame, RendererCommon.GlDrawer drawer,
184 Matrix additionalRenderMatrix, int viewportX, int viewportY, int viewportW idth,
185 int viewportHeight) {
186 final int width = frame.getRotatedWidth();
187 final int height = frame.getRotatedHeight();
188
189 calculateTransformedRenderSize(width, height, additionalRenderMatrix);
190
191 final boolean isTextureFrame = frame.getBuffer() instanceof VideoFrame.Textu reBuffer;
192 renderMatrix.reset();
193 renderMatrix.preTranslate(0.5f, 0.5f);
194 if (!isTextureFrame) {
195 renderMatrix.preScale(1f, -1f); // I420-frames are upside down
196 }
197 renderMatrix.preRotate(frame.getRotation());
198 renderMatrix.preTranslate(-0.5f, -0.5f);
199 if (additionalRenderMatrix != null) {
200 renderMatrix.preConcat(additionalRenderMatrix);
179 } 201 }
180 202
181 public Point measure(int widthSpec, int heightSpec, int frameWidth, int fram eHeight) { 203 if (isTextureFrame) {
182 // Calculate max allowed layout size. 204 lastI420Frame = null;
183 final int maxWidth = View.getDefaultSize(Integer.MAX_VALUE, widthSpec); 205 drawTexture(drawer, (VideoFrame.TextureBuffer) frame.getBuffer(), renderMa trix, renderWidth,
184 final int maxHeight = View.getDefaultSize(Integer.MAX_VALUE, heightSpec); 206 renderHeight, viewportX, viewportY, viewportWidth, viewportHeight);
185 if (frameWidth == 0 || frameHeight == 0 || maxWidth == 0 || maxHeight == 0 ) { 207 } else {
186 return new Point(maxWidth, maxHeight); 208 // Only upload the I420 data to textures once per frame, if we are called multiple times
209 // with the same frame.
210 if (frame != lastI420Frame) {
211 lastI420Frame = frame;
212 final VideoFrame.I420Buffer i420Buffer = frame.getBuffer().toI420();
213 yuvUploader.uploadFromBuffer(i420Buffer);
214 i420Buffer.release();
187 } 215 }
188 // Calculate desired display size based on scaling type, video aspect rati o,
189 // and maximum layout size.
190 final float frameAspect = frameWidth / (float) frameHeight;
191 final float displayAspect = maxWidth / (float) maxHeight;
192 final ScalingType scalingType = (frameAspect > 1.0f) == (displayAspect > 1 .0f)
193 ? scalingTypeMatchOrientation
194 : scalingTypeMismatchOrientation;
195 final Point layoutSize = getDisplaySize(scalingType, frameAspect, maxWidth , maxHeight);
196 216
197 // If the measure specification is forcing a specific size - yield. 217 drawer.drawYuv(yuvUploader.getYuvTextures(),
198 if (View.MeasureSpec.getMode(widthSpec) == View.MeasureSpec.EXACTLY) { 218 RendererCommon.convertMatrixFromAndroidGraphicsMatrix(renderMatrix), r enderWidth,
199 layoutSize.x = maxWidth; 219 renderHeight, viewportX, viewportY, viewportWidth, viewportHeight);
200 }
201 if (View.MeasureSpec.getMode(heightSpec) == View.MeasureSpec.EXACTLY) {
202 layoutSize.y = maxHeight;
203 }
204 return layoutSize;
205 } 220 }
206 } 221 }
207 222
208 // Types of video scaling: 223 public void release() {
209 // SCALE_ASPECT_FIT - video frame is scaled to fit the size of the view by 224 yuvUploader.release();
210 // maintaining the aspect ratio (black borders may be displayed). 225 lastI420Frame = null;
211 // SCALE_ASPECT_FILL - video frame is scaled to fill the size of the view by
212 // maintaining the aspect ratio. Some portion of the video frame may be
213 // clipped.
214 // SCALE_ASPECT_BALANCED - Compromise between FIT and FILL. Video frame will f ill as much as
215 // possible of the view while maintaining aspect ratio, under the constraint t hat at least
216 // |BALANCED_VISIBLE_FRACTION| of the frame content will be shown.
217 public static enum ScalingType { SCALE_ASPECT_FIT, SCALE_ASPECT_FILL, SCALE_AS PECT_BALANCED }
218 // The minimum fraction of the frame content that will be shown for |SCALE_ASP ECT_BALANCED|.
219 // This limits excessive cropping when adjusting display size.
220 private static float BALANCED_VISIBLE_FRACTION = 0.5625f;
221 // clang-format off
222 public static final float[] identityMatrix() {
223 return new float[] {
224 1, 0, 0, 0,
225 0, 1, 0, 0,
226 0, 0, 1, 0,
227 0, 0, 0, 1};
228 }
229 // Matrix with transform y' = 1 - y.
230 public static final float[] verticalFlipMatrix() {
231 return new float[] {
232 1, 0, 0, 0,
233 0, -1, 0, 0,
234 0, 0, 1, 0,
235 0, 1, 0, 1};
236 }
237
238 // Matrix with transform x' = 1 - x.
239 public static final float[] horizontalFlipMatrix() {
240 return new float[] {
241 -1, 0, 0, 0,
242 0, 1, 0, 0,
243 0, 0, 1, 0,
244 1, 0, 0, 1};
245 }
246 // clang-format on
247
248 /**
249 * Returns texture matrix that will have the effect of rotating the frame |rot ationDegree|
250 * clockwise when rendered.
251 */
252 public static float[] rotateTextureMatrix(float[] textureMatrix, float rotatio nDegree) {
253 final float[] rotationMatrix = new float[16];
254 Matrix.setRotateM(rotationMatrix, 0, rotationDegree, 0, 0, 1);
255 adjustOrigin(rotationMatrix);
256 return multiplyMatrices(textureMatrix, rotationMatrix);
257 }
258
259 /**
260 * Returns new matrix with the result of a * b.
261 */
262 public static float[] multiplyMatrices(float[] a, float[] b) {
263 final float[] resultMatrix = new float[16];
264 Matrix.multiplyMM(resultMatrix, 0, a, 0, b, 0);
265 return resultMatrix;
266 }
267
268 /**
269 * Returns layout transformation matrix that applies an optional mirror effect and compensates
270 * for video vs display aspect ratio.
271 */
272 public static float[] getLayoutMatrix(
273 boolean mirror, float videoAspectRatio, float displayAspectRatio) {
274 float scaleX = 1;
275 float scaleY = 1;
276 // Scale X or Y dimension so that video and display size have same aspect ra tio.
277 if (displayAspectRatio > videoAspectRatio) {
278 scaleY = videoAspectRatio / displayAspectRatio;
279 } else {
280 scaleX = displayAspectRatio / videoAspectRatio;
281 }
282 // Apply optional horizontal flip.
283 if (mirror) {
284 scaleX *= -1;
285 }
286 final float matrix[] = new float[16];
287 Matrix.setIdentityM(matrix, 0);
288 Matrix.scaleM(matrix, 0, scaleX, scaleY, 1);
289 adjustOrigin(matrix);
290 return matrix;
291 }
292
293 /** Converts a float[16] matrix array to android.graphics.Matrix. */
294 public static android.graphics.Matrix convertMatrixToAndroidGraphicsMatrix(flo at[] matrix4x4) {
295 // clang-format off
296 float[] values = {
297 matrix4x4[0 * 4 + 0], matrix4x4[1 * 4 + 0], matrix4x4[3 * 4 + 0],
298 matrix4x4[0 * 4 + 1], matrix4x4[1 * 4 + 1], matrix4x4[3 * 4 + 1],
299 matrix4x4[0 * 4 + 3], matrix4x4[1 * 4 + 3], matrix4x4[3 * 4 + 3],
300 };
301 // clang-format on
302
303 android.graphics.Matrix matrix = new android.graphics.Matrix();
304 matrix.setValues(values);
305 return matrix;
306 }
307
308 /** Converts android.graphics.Matrix to a float[16] matrix array. */
309 public static float[] convertMatrixFromAndroidGraphicsMatrix(android.graphics. Matrix matrix) {
310 float[] values = new float[9];
311 matrix.getValues(values);
312
313 // The android.graphics.Matrix looks like this:
314 // [x1 y1 w1]
315 // [x2 y2 w2]
316 // [x3 y3 w3]
317 // We want to contruct a matrix that looks like this:
318 // [x1 y1 0 w1]
319 // [x2 y2 0 w2]
320 // [ 0 0 1 0]
321 // [x3 y3 0 w3]
322 // Since it is stored in column-major order, it looks like this:
323 // [x1 x2 0 x3
324 // y1 y2 0 y3
325 // 0 0 1 0
326 // w1 w2 0 w3]
327 // clang-format off
328 float[] matrix4x4 = {
329 values[0 * 3 + 0], values[1 * 3 + 0], 0, values[2 * 3 + 0],
330 values[0 * 3 + 1], values[1 * 3 + 1], 0, values[2 * 3 + 1],
331 0, 0, 1, 0,
332 values[0 * 3 + 2], values[1 * 3 + 2], 0, values[2 * 3 + 2],
333 };
334 // clang-format on
335 return matrix4x4;
336 }
337
338 /**
339 * Calculate display size based on scaling type, video aspect ratio, and maxim um display size.
340 */
341 public static Point getDisplaySize(
342 ScalingType scalingType, float videoAspectRatio, int maxDisplayWidth, int maxDisplayHeight) {
343 return getDisplaySize(convertScalingTypeToVisibleFraction(scalingType), vide oAspectRatio,
344 maxDisplayWidth, maxDisplayHeight);
345 }
346
347 /**
348 * Move |matrix| transformation origin to (0.5, 0.5). This is the origin for t exture coordinates
349 * that are in the range 0 to 1.
350 */
351 private static void adjustOrigin(float[] matrix) {
352 // Note that OpenGL is using column-major order.
353 // Pre translate with -0.5 to move coordinates to range [-0.5, 0.5].
354 matrix[12] -= 0.5f * (matrix[0] + matrix[4]);
355 matrix[13] -= 0.5f * (matrix[1] + matrix[5]);
356 // Post translate with 0.5 to move coordinates to range [0, 1].
357 matrix[12] += 0.5f;
358 matrix[13] += 0.5f;
359 }
360
361 /**
362 * Each scaling type has a one-to-one correspondence to a numeric minimum frac tion of the video
363 * that must remain visible.
364 */
365 private static float convertScalingTypeToVisibleFraction(ScalingType scalingTy pe) {
366 switch (scalingType) {
367 case SCALE_ASPECT_FIT:
368 return 1.0f;
369 case SCALE_ASPECT_FILL:
370 return 0.0f;
371 case SCALE_ASPECT_BALANCED:
372 return BALANCED_VISIBLE_FRACTION;
373 default:
374 throw new IllegalArgumentException();
375 }
376 }
377
378 /**
379 * Calculate display size based on minimum fraction of the video that must rem ain visible,
380 * video aspect ratio, and maximum display size.
381 */
382 private static Point getDisplaySize(
383 float minVisibleFraction, float videoAspectRatio, int maxDisplayWidth, int maxDisplayHeight) {
384 // If there is no constraint on the amount of cropping, fill the allowed dis play area.
385 if (minVisibleFraction == 0 || videoAspectRatio == 0) {
386 return new Point(maxDisplayWidth, maxDisplayHeight);
387 }
388 // Each dimension is constrained on max display size and how much we are all owed to crop.
389 final int width = Math.min(
390 maxDisplayWidth, Math.round(maxDisplayHeight / minVisibleFraction * vide oAspectRatio));
391 final int height = Math.min(
392 maxDisplayHeight, Math.round(maxDisplayWidth / minVisibleFraction / vide oAspectRatio));
393 return new Point(width, height);
394 } 226 }
395 } 227 }
OLDNEW
« no previous file with comments | « webrtc/sdk/android/api/org/webrtc/RendererCommon.java ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698