Skip to content

Commit

Permalink
Use surfaceless context in DummySurface, if available
Browse files Browse the repository at this point in the history
Issue: #3558

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=178604607
  • Loading branch information
andrewlewis authored and ojw28 committed Dec 12, 2017
1 parent 42b612a commit babd575
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 45 deletions.
2 changes: 2 additions & 0 deletions RELEASENOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
implementations.
* CEA-608: Fix handling of row count changes in roll-up mode
([#3513](https://github.com/google/ExoPlayer/issues/3513)).
* Use surfaceless context for secure DummySurface, if available
([#3558](https://github.com/google/ExoPlayer/issues/3558)).
* IMA extension:
* Skip ads before the ad preceding the player's initial seek position
([#3527](https://github.com/google/ExoPlayer/issues/3527)).
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import static android.opengl.EGL14.EGL_GREEN_SIZE;
import static android.opengl.EGL14.EGL_HEIGHT;
import static android.opengl.EGL14.EGL_NONE;
import static android.opengl.EGL14.EGL_NO_SURFACE;
import static android.opengl.EGL14.EGL_OPENGL_ES2_BIT;
import static android.opengl.EGL14.EGL_RED_SIZE;
import static android.opengl.EGL14.EGL_RENDERABLE_TYPE;
Expand Down Expand Up @@ -56,10 +57,13 @@
import android.os.Handler.Callback;
import android.os.HandlerThread;
import android.os.Message;
import android.support.annotation.IntDef;
import android.util.Log;
import android.view.Surface;
import com.google.android.exoplayer2.util.Assertions;
import com.google.android.exoplayer2.util.Util;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import javax.microedition.khronos.egl.EGL10;

/**
Expand All @@ -70,16 +74,27 @@ public final class DummySurface extends Surface {

private static final String TAG = "DummySurface";

private static final String EXTENSION_PROTECTED_CONTENT = "EGL_EXT_protected_content";
private static final String EXTENSION_SURFACELESS_CONTEXT = "EGL_KHR_surfaceless_context";

private static final int EGL_PROTECTED_CONTENT_EXT = 0x32C0;

private static boolean secureSupported;
private static boolean secureSupportedInitialized;
@Retention(RetentionPolicy.SOURCE)
@IntDef({SECURE_MODE_NONE, SECURE_MODE_SURFACELESS_CONTEXT, SECURE_MODE_PROTECTED_PBUFFER})
private @interface SecureMode {}

private static final int SECURE_MODE_NONE = 0;
private static final int SECURE_MODE_SURFACELESS_CONTEXT = 1;
private static final int SECURE_MODE_PROTECTED_PBUFFER = 2;

/**
* Whether the surface is secure.
*/
public final boolean secure;

private static @SecureMode int secureMode;
private static boolean secureModeInitialized;

private final DummySurfaceThread thread;
private boolean threadReleased;

Expand All @@ -90,11 +105,11 @@ public final class DummySurface extends Surface {
* @return Whether the device supports secure dummy surfaces.
*/
public static synchronized boolean isSecureSupported(Context context) {
if (!secureSupportedInitialized) {
secureSupported = Util.SDK_INT >= 24 && enableSecureDummySurfaceV24(context);
secureSupportedInitialized = true;
if (!secureModeInitialized) {
secureMode = Util.SDK_INT < 24 ? SECURE_MODE_NONE : getSecureModeV24(context);
secureModeInitialized = true;
}
return secureSupported;
return secureMode != SECURE_MODE_NONE;
}

/**
Expand All @@ -113,7 +128,7 @@ public static DummySurface newInstanceV17(Context context, boolean secure) {
assertApiLevel17OrHigher();
Assertions.checkState(!secure || isSecureSupported(context));
DummySurfaceThread thread = new DummySurfaceThread();
return thread.init(secure);
return thread.init(secure ? secureMode : SECURE_MODE_NONE);
}

private DummySurface(DummySurfaceThread thread, SurfaceTexture surfaceTexture, boolean secure) {
Expand Down Expand Up @@ -143,33 +158,34 @@ private static void assertApiLevel17OrHigher() {
}
}

/**
* Returns whether use of secure dummy surfaces should be enabled.
*
* @param context Any {@link Context}.
*/
@TargetApi(24)
private static boolean enableSecureDummySurfaceV24(Context context) {
private static @SecureMode int getSecureModeV24(Context context) {
if (Util.SDK_INT < 26 && ("samsung".equals(Util.MANUFACTURER) || "XT1650".equals(Util.MODEL))) {
// Samsung devices running Nougat are known to be broken. See
// https://github.com/google/ExoPlayer/issues/3373 and [Internal: b/37197802].
// Moto Z XT1650 is also affected. See
// https://github.com/google/ExoPlayer/issues/3215.
return false;
return SECURE_MODE_NONE;
}
if (Util.SDK_INT < 26 && !context.getPackageManager().hasSystemFeature(
PackageManager.FEATURE_VR_MODE_HIGH_PERFORMANCE)) {
// Pre API level 26 devices were not well tested unless they supported VR mode. See
// https://github.com/google/ExoPlayer/issues/3215.
return false;
// Pre API level 26 devices were not well tested unless they supported VR mode.
return SECURE_MODE_NONE;
}
EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
String eglExtensions = EGL14.eglQueryString(display, EGL10.EGL_EXTENSIONS);
if (eglExtensions == null || !eglExtensions.contains("EGL_EXT_protected_content")) {
// EGL_EXT_protected_content is required to enable secure dummy surfaces.
return false;
if (eglExtensions == null) {
return SECURE_MODE_NONE;
}
return true;
if (!eglExtensions.contains(EXTENSION_PROTECTED_CONTENT)) {
return SECURE_MODE_NONE;
}
// If we can't use surfaceless contexts, we use a protected 1 * 1 pixel buffer surface. This may
// require support for EXT_protected_surface, but in practice it works on some devices that
// don't have that extension. See also https://github.com/google/ExoPlayer/issues/3558.
return eglExtensions.contains(EXTENSION_SURFACELESS_CONTEXT)
? SECURE_MODE_SURFACELESS_CONTEXT
: SECURE_MODE_PROTECTED_PBUFFER;
}

private static class DummySurfaceThread extends HandlerThread implements OnFrameAvailableListener,
Expand All @@ -195,12 +211,12 @@ public DummySurfaceThread() {
textureIdHolder = new int[1];
}

public DummySurface init(boolean secure) {
public DummySurface init(@SecureMode int secureMode) {
start();
handler = new Handler(getLooper(), this);
boolean wasInterrupted = false;
synchronized (this) {
handler.obtainMessage(MSG_INIT, secure ? 1 : 0, 0).sendToTarget();
handler.obtainMessage(MSG_INIT, secureMode, 0).sendToTarget();
while (surface == null && initException == null && initError == null) {
try {
wait();
Expand Down Expand Up @@ -236,7 +252,7 @@ public boolean handleMessage(Message msg) {
switch (msg.what) {
case MSG_INIT:
try {
initInternal(msg.arg1 != 0);
initInternal(/* secureMode= */ msg.arg1);
} catch (RuntimeException e) {
Log.e(TAG, "Failed to initialize dummy surface", e);
initException = e;
Expand Down Expand Up @@ -266,7 +282,7 @@ public boolean handleMessage(Message msg) {
}
}

private void initInternal(boolean secure) {
private void initInternal(@SecureMode int secureMode) {
display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
Assertions.checkState(display != null, "eglGetDisplay failed");

Expand Down Expand Up @@ -294,43 +310,45 @@ private void initInternal(boolean secure) {

EGLConfig config = configs[0];
int[] glAttributes;
if (secure) {
if (secureMode == SECURE_MODE_NONE) {
glAttributes = new int[] {
EGL_CONTEXT_CLIENT_VERSION, 2,
EGL_PROTECTED_CONTENT_EXT, EGL_TRUE,
EGL_NONE};
} else {
glAttributes = new int[] {
EGL_CONTEXT_CLIENT_VERSION, 2,
EGL_NONE};
glAttributes =
new int[] {
EGL_CONTEXT_CLIENT_VERSION, 2, EGL_PROTECTED_CONTENT_EXT, EGL_TRUE, EGL_NONE
};
}
context = eglCreateContext(display, config, android.opengl.EGL14.EGL_NO_CONTEXT, glAttributes,
0);
Assertions.checkState(context != null, "eglCreateContext failed");

int[] pbufferAttributes;
if (secure) {
pbufferAttributes = new int[] {
EGL_WIDTH, 1,
EGL_HEIGHT, 1,
EGL_PROTECTED_CONTENT_EXT, EGL_TRUE,
EGL_NONE};
EGLSurface surface;
if (secureMode == SECURE_MODE_SURFACELESS_CONTEXT) {
surface = EGL_NO_SURFACE;
} else {
pbufferAttributes = new int[] {
EGL_WIDTH, 1,
EGL_HEIGHT, 1,
EGL_NONE};
int[] pbufferAttributes;
if (secureMode == SECURE_MODE_PROTECTED_PBUFFER) {
pbufferAttributes =
new int[] {
EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_PROTECTED_CONTENT_EXT, EGL_TRUE, EGL_NONE
};
} else {
pbufferAttributes = new int[] {EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE};
}
pbuffer = eglCreatePbufferSurface(display, config, pbufferAttributes, 0);
Assertions.checkState(pbuffer != null, "eglCreatePbufferSurface failed");
surface = pbuffer;
}
pbuffer = eglCreatePbufferSurface(display, config, pbufferAttributes, 0);
Assertions.checkState(pbuffer != null, "eglCreatePbufferSurface failed");

boolean eglMadeCurrent = eglMakeCurrent(display, pbuffer, pbuffer, context);
boolean eglMadeCurrent = eglMakeCurrent(display, surface, surface, context);
Assertions.checkState(eglMadeCurrent, "eglMakeCurrent failed");

glGenTextures(1, textureIdHolder, 0);
surfaceTexture = new SurfaceTexture(textureIdHolder[0]);
surfaceTexture.setOnFrameAvailableListener(this);
surface = new DummySurface(this, surfaceTexture, secure);
this.surface = new DummySurface(this, surfaceTexture, secureMode != SECURE_MODE_NONE);
}

private void releaseInternal() {
Expand Down

0 comments on commit babd575

Please sign in to comment.