Android: Move layout measure code from SurfaceViewRenderer to RendererCommon
BUG=webrtc:6470 R=sakal@webrtc.org Review URL: https://codereview.webrtc.org/2386253003 . Cr-Commit-Position: refs/heads/master@{#14526}
This commit is contained in:
parent
3360352c2b
commit
62b1c35d30
@ -13,6 +13,7 @@ package org.webrtc;
|
||||
import android.graphics.Point;
|
||||
import android.opengl.GLES20;
|
||||
import android.opengl.Matrix;
|
||||
import android.view.View;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
@ -103,6 +104,56 @@ public class RendererCommon {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper class for determining layout size based on layout requirements, scaling type, and video
|
||||
* aspect ratio.
|
||||
*/
|
||||
public static class VideoLayoutMeasure {
|
||||
// The scaling type determines how the video will fill the allowed layout area in measure(). It
|
||||
// can be specified separately for the case when video has matched orientation with layout size
|
||||
// and when there is an orientation mismatch.
|
||||
private ScalingType scalingTypeMatchOrientation = ScalingType.SCALE_ASPECT_BALANCED;
|
||||
private ScalingType scalingTypeMismatchOrientation = ScalingType.SCALE_ASPECT_BALANCED;
|
||||
|
||||
public void setScalingType(ScalingType scalingType) {
|
||||
this.scalingTypeMatchOrientation = scalingType;
|
||||
this.scalingTypeMismatchOrientation = scalingType;
|
||||
}
|
||||
|
||||
public void setScalingType(
|
||||
ScalingType scalingTypeMatchOrientation, ScalingType scalingTypeMismatchOrientation) {
|
||||
this.scalingTypeMatchOrientation = scalingTypeMatchOrientation;
|
||||
this.scalingTypeMismatchOrientation = scalingTypeMismatchOrientation;
|
||||
}
|
||||
|
||||
public Point measure(int widthSpec, int heightSpec, int frameWidth, int frameHeight) {
|
||||
// Calculate max allowed layout size.
|
||||
final int maxWidth = View.getDefaultSize(Integer.MAX_VALUE, widthSpec);
|
||||
final int maxHeight = View.getDefaultSize(Integer.MAX_VALUE, heightSpec);
|
||||
if (frameWidth == 0 || frameHeight == 0 || maxWidth == 0 || maxHeight == 0) {
|
||||
return new Point(maxWidth, maxHeight);
|
||||
}
|
||||
// Calculate desired display size based on scaling type, video aspect ratio,
|
||||
// and maximum layout size.
|
||||
final float frameAspect = frameWidth / (float) frameHeight;
|
||||
final float displayAspect = maxWidth / (float) maxHeight;
|
||||
final RendererCommon.ScalingType scalingType = (frameAspect > 1.0f) == (displayAspect > 1.0f)
|
||||
? scalingTypeMatchOrientation
|
||||
: scalingTypeMismatchOrientation;
|
||||
final Point layoutSize =
|
||||
RendererCommon.getDisplaySize(scalingType, frameAspect, maxWidth, maxHeight);
|
||||
|
||||
// If the measure specification is forcing a specific size - yield.
|
||||
if (View.MeasureSpec.getMode(widthSpec) == View.MeasureSpec.EXACTLY) {
|
||||
layoutSize.x = maxWidth;
|
||||
}
|
||||
if (View.MeasureSpec.getMode(heightSpec) == View.MeasureSpec.EXACTLY) {
|
||||
layoutSize.y = maxHeight;
|
||||
}
|
||||
return layoutSize;
|
||||
}
|
||||
}
|
||||
|
||||
// Types of video scaling:
|
||||
// SCALE_ASPECT_FIT - video frame is scaled to fit the size of the view by
|
||||
// maintaining the aspect ratio (black borders may be displayed).
|
||||
|
||||
@ -77,11 +77,12 @@ public class SurfaceViewRenderer
|
||||
// |isSurfaceCreated| keeps track of the current status in surfaceCreated()/surfaceDestroyed().
|
||||
private boolean isSurfaceCreated;
|
||||
// Last rendered frame dimensions, or 0 if no frame has been rendered yet.
|
||||
private int frameWidth;
|
||||
private int frameHeight;
|
||||
private int rotatedFrameWidth;
|
||||
private int rotatedFrameHeight;
|
||||
private int frameRotation;
|
||||
// |scalingType| determines how the video will fill the allowed layout area in onMeasure().
|
||||
private RendererCommon.ScalingType scalingType = RendererCommon.ScalingType.SCALE_ASPECT_BALANCED;
|
||||
private final RendererCommon.VideoLayoutMeasure videoLayoutMeasure =
|
||||
new RendererCommon.VideoLayoutMeasure();
|
||||
|
||||
// If true, mirrors the video stream horizontally.
|
||||
private boolean mirror;
|
||||
// Callback for reporting renderer events.
|
||||
@ -243,8 +244,8 @@ public class SurfaceViewRenderer
|
||||
renderThread = null;
|
||||
// Reset statistics and event reporting.
|
||||
synchronized (layoutLock) {
|
||||
frameWidth = 0;
|
||||
frameHeight = 0;
|
||||
rotatedFrameWidth = 0;
|
||||
rotatedFrameHeight = 0;
|
||||
frameRotation = 0;
|
||||
rendererEvents = null;
|
||||
}
|
||||
@ -278,9 +279,14 @@ public class SurfaceViewRenderer
|
||||
* Set how the video will fill the allowed layout area.
|
||||
*/
|
||||
public void setScalingType(RendererCommon.ScalingType scalingType) {
|
||||
synchronized (layoutLock) {
|
||||
this.scalingType = scalingType;
|
||||
}
|
||||
ThreadUtils.checkIsOnMainThread();
|
||||
videoLayoutMeasure.setScalingType(scalingType);
|
||||
}
|
||||
|
||||
public void setScalingType(RendererCommon.ScalingType scalingTypeMatchOrientation,
|
||||
RendererCommon.ScalingType scalingTypeMismatchOrientation) {
|
||||
ThreadUtils.checkIsOnMainThread();
|
||||
videoLayoutMeasure.setScalingType(scalingTypeMatchOrientation, scalingTypeMismatchOrientation);
|
||||
}
|
||||
|
||||
// VideoRenderer.Callbacks interface.
|
||||
@ -309,33 +315,14 @@ public class SurfaceViewRenderer
|
||||
}
|
||||
}
|
||||
|
||||
// Returns desired layout size given current measure specification and video aspect ratio.
|
||||
private Point getDesiredLayoutSize(int widthSpec, int heightSpec) {
|
||||
synchronized (layoutLock) {
|
||||
final int maxWidth = getDefaultSize(Integer.MAX_VALUE, widthSpec);
|
||||
final int maxHeight = getDefaultSize(Integer.MAX_VALUE, heightSpec);
|
||||
final Point size =
|
||||
RendererCommon.getDisplaySize(scalingType, frameAspectRatio(), maxWidth, maxHeight);
|
||||
if (MeasureSpec.getMode(widthSpec) == MeasureSpec.EXACTLY) {
|
||||
size.x = maxWidth;
|
||||
}
|
||||
if (MeasureSpec.getMode(heightSpec) == MeasureSpec.EXACTLY) {
|
||||
size.y = maxHeight;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
}
|
||||
|
||||
// View layout interface.
|
||||
@Override
|
||||
protected void onMeasure(int widthSpec, int heightSpec) {
|
||||
ThreadUtils.checkIsOnMainThread();
|
||||
final boolean isNewSize;
|
||||
synchronized (layoutLock) {
|
||||
if (frameWidth == 0 || frameHeight == 0) {
|
||||
super.onMeasure(widthSpec, heightSpec);
|
||||
return;
|
||||
}
|
||||
desiredLayoutSize = getDesiredLayoutSize(widthSpec, heightSpec);
|
||||
desiredLayoutSize =
|
||||
videoLayoutMeasure.measure(widthSpec, heightSpec, rotatedFrameWidth, rotatedFrameHeight);
|
||||
isNewSize =
|
||||
(desiredLayoutSize.x != getMeasuredWidth() || desiredLayoutSize.y != getMeasuredHeight());
|
||||
setMeasuredDimension(desiredLayoutSize.x, desiredLayoutSize.y);
|
||||
@ -487,8 +474,9 @@ public class SurfaceViewRenderer
|
||||
synchronized (layoutLock) {
|
||||
final float[] rotatedSamplingMatrix =
|
||||
RendererCommon.rotateTextureMatrix(frame.samplingMatrix, frame.rotationDegree);
|
||||
final float[] layoutMatrix = RendererCommon.getLayoutMatrix(
|
||||
mirror, frameAspectRatio(), (float) layoutSize.x / layoutSize.y);
|
||||
final float[] layoutMatrix = RendererCommon.getLayoutMatrix(mirror,
|
||||
frame.rotatedWidth() / (float) frame.rotatedHeight(),
|
||||
layoutSize.x / (float) layoutSize.y);
|
||||
texMatrix = RendererCommon.multiplyMatrices(rotatedSamplingMatrix, layoutMatrix);
|
||||
}
|
||||
|
||||
@ -532,29 +520,18 @@ public class SurfaceViewRenderer
|
||||
}
|
||||
}
|
||||
|
||||
// Return current frame aspect ratio, taking rotation into account.
|
||||
private float frameAspectRatio() {
|
||||
synchronized (layoutLock) {
|
||||
if (frameWidth == 0 || frameHeight == 0) {
|
||||
return 0.0f;
|
||||
}
|
||||
return (frameRotation % 180 == 0) ? (float) frameWidth / frameHeight
|
||||
: (float) frameHeight / frameWidth;
|
||||
}
|
||||
}
|
||||
|
||||
// Update frame dimensions and report any changes to |rendererEvents|.
|
||||
private void updateFrameDimensionsAndReportEvents(VideoRenderer.I420Frame frame) {
|
||||
synchronized (layoutLock) {
|
||||
if (frameWidth != frame.width || frameHeight != frame.height
|
||||
if (rotatedFrameWidth != frame.rotatedWidth() || rotatedFrameHeight != frame.rotatedHeight()
|
||||
|| frameRotation != frame.rotationDegree) {
|
||||
Logging.d(TAG, getResourceName() + "Reporting frame resolution changed to " + frame.width
|
||||
+ "x" + frame.height + " with rotation " + frame.rotationDegree);
|
||||
if (rendererEvents != null) {
|
||||
rendererEvents.onFrameResolutionChanged(frame.width, frame.height, frame.rotationDegree);
|
||||
}
|
||||
frameWidth = frame.width;
|
||||
frameHeight = frame.height;
|
||||
rotatedFrameWidth = frame.rotatedWidth();
|
||||
rotatedFrameHeight = frame.rotatedHeight();
|
||||
frameRotation = frame.rotationDegree;
|
||||
post(new Runnable() {
|
||||
@Override
|
||||
|
||||
@ -12,9 +12,9 @@ package org.webrtc;
|
||||
|
||||
import android.graphics.Point;
|
||||
import android.test.ActivityTestCase;
|
||||
import android.test.UiThreadTest;
|
||||
import android.test.suitebuilder.annotation.MediumTest;
|
||||
import android.view.View.MeasureSpec;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
@ -68,6 +68,7 @@ public final class SurfaceViewRendererOnMeasureTest extends ActivityTestCase {
|
||||
/**
|
||||
* Test how SurfaceViewRenderer.onMeasure() behaves when no frame has been delivered.
|
||||
*/
|
||||
@UiThreadTest
|
||||
@MediumTest
|
||||
public void testNoFrame() {
|
||||
final SurfaceViewRenderer surfaceViewRenderer =
|
||||
@ -105,6 +106,7 @@ public final class SurfaceViewRendererOnMeasureTest extends ActivityTestCase {
|
||||
/**
|
||||
* Test how SurfaceViewRenderer.onMeasure() behaves with a 1280x720 frame.
|
||||
*/
|
||||
@UiThreadTest
|
||||
@MediumTest
|
||||
public void testFrame1280x720() throws InterruptedException {
|
||||
final SurfaceViewRenderer surfaceViewRenderer =
|
||||
|
||||
@ -11,6 +11,7 @@
|
||||
package org.webrtc;
|
||||
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.os.SystemClock;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
@ -38,6 +39,15 @@ public class ThreadUtils {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Throws exception if called from other than main thread.
|
||||
*/
|
||||
public static void checkIsOnMainThread() {
|
||||
if (Thread.currentThread() != Looper.getMainLooper().getThread()) {
|
||||
throw new IllegalStateException("Not on main thread!");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility interface to be used with executeUninterruptibly() to wait for blocking operations
|
||||
* to complete without getting interrupted..
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user