mirror of
https://github.com/androidx/media.git
synced 2025-04-30 06:46:50 +08:00
Use surfaceless context in DummySurface, if available
Issue: #3558 ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=178604607
This commit is contained in:
parent
ba32d95dc4
commit
f8834dacc6
@ -41,6 +41,8 @@
|
|||||||
implementations.
|
implementations.
|
||||||
* CEA-608: Fix handling of row count changes in roll-up mode
|
* CEA-608: Fix handling of row count changes in roll-up mode
|
||||||
([#3513](https://github.com/google/ExoPlayer/issues/3513)).
|
([#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:
|
* IMA extension:
|
||||||
* Skip ads before the ad preceding the player's initial seek position
|
* Skip ads before the ad preceding the player's initial seek position
|
||||||
([#3527](https://github.com/google/ExoPlayer/issues/3527)).
|
([#3527](https://github.com/google/ExoPlayer/issues/3527)).
|
||||||
|
@ -24,6 +24,7 @@ import static android.opengl.EGL14.EGL_DEPTH_SIZE;
|
|||||||
import static android.opengl.EGL14.EGL_GREEN_SIZE;
|
import static android.opengl.EGL14.EGL_GREEN_SIZE;
|
||||||
import static android.opengl.EGL14.EGL_HEIGHT;
|
import static android.opengl.EGL14.EGL_HEIGHT;
|
||||||
import static android.opengl.EGL14.EGL_NONE;
|
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_OPENGL_ES2_BIT;
|
||||||
import static android.opengl.EGL14.EGL_RED_SIZE;
|
import static android.opengl.EGL14.EGL_RED_SIZE;
|
||||||
import static android.opengl.EGL14.EGL_RENDERABLE_TYPE;
|
import static android.opengl.EGL14.EGL_RENDERABLE_TYPE;
|
||||||
@ -56,10 +57,13 @@ import android.os.Handler;
|
|||||||
import android.os.Handler.Callback;
|
import android.os.Handler.Callback;
|
||||||
import android.os.HandlerThread;
|
import android.os.HandlerThread;
|
||||||
import android.os.Message;
|
import android.os.Message;
|
||||||
|
import android.support.annotation.IntDef;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.Surface;
|
import android.view.Surface;
|
||||||
import com.google.android.exoplayer2.util.Assertions;
|
import com.google.android.exoplayer2.util.Assertions;
|
||||||
import com.google.android.exoplayer2.util.Util;
|
import com.google.android.exoplayer2.util.Util;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
import javax.microedition.khronos.egl.EGL10;
|
import javax.microedition.khronos.egl.EGL10;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -70,16 +74,27 @@ public final class DummySurface extends Surface {
|
|||||||
|
|
||||||
private static final String TAG = "DummySurface";
|
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 final int EGL_PROTECTED_CONTENT_EXT = 0x32C0;
|
||||||
|
|
||||||
private static boolean secureSupported;
|
@Retention(RetentionPolicy.SOURCE)
|
||||||
private static boolean secureSupportedInitialized;
|
@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.
|
* Whether the surface is secure.
|
||||||
*/
|
*/
|
||||||
public final boolean secure;
|
public final boolean secure;
|
||||||
|
|
||||||
|
private static @SecureMode int secureMode;
|
||||||
|
private static boolean secureModeInitialized;
|
||||||
|
|
||||||
private final DummySurfaceThread thread;
|
private final DummySurfaceThread thread;
|
||||||
private boolean threadReleased;
|
private boolean threadReleased;
|
||||||
|
|
||||||
@ -90,11 +105,11 @@ public final class DummySurface extends Surface {
|
|||||||
* @return Whether the device supports secure dummy surfaces.
|
* @return Whether the device supports secure dummy surfaces.
|
||||||
*/
|
*/
|
||||||
public static synchronized boolean isSecureSupported(Context context) {
|
public static synchronized boolean isSecureSupported(Context context) {
|
||||||
if (!secureSupportedInitialized) {
|
if (!secureModeInitialized) {
|
||||||
secureSupported = Util.SDK_INT >= 24 && enableSecureDummySurfaceV24(context);
|
secureMode = Util.SDK_INT < 24 ? SECURE_MODE_NONE : getSecureModeV24(context);
|
||||||
secureSupportedInitialized = true;
|
secureModeInitialized = true;
|
||||||
}
|
}
|
||||||
return secureSupported;
|
return secureMode != SECURE_MODE_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -113,7 +128,7 @@ public final class DummySurface extends Surface {
|
|||||||
assertApiLevel17OrHigher();
|
assertApiLevel17OrHigher();
|
||||||
Assertions.checkState(!secure || isSecureSupported(context));
|
Assertions.checkState(!secure || isSecureSupported(context));
|
||||||
DummySurfaceThread thread = new DummySurfaceThread();
|
DummySurfaceThread thread = new DummySurfaceThread();
|
||||||
return thread.init(secure);
|
return thread.init(secure ? secureMode : SECURE_MODE_NONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
private DummySurface(DummySurfaceThread thread, SurfaceTexture surfaceTexture, boolean secure) {
|
private DummySurface(DummySurfaceThread thread, SurfaceTexture surfaceTexture, boolean secure) {
|
||||||
@ -143,33 +158,34 @@ public final class DummySurface extends Surface {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns whether use of secure dummy surfaces should be enabled.
|
|
||||||
*
|
|
||||||
* @param context Any {@link Context}.
|
|
||||||
*/
|
|
||||||
@TargetApi(24)
|
@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))) {
|
if (Util.SDK_INT < 26 && ("samsung".equals(Util.MANUFACTURER) || "XT1650".equals(Util.MODEL))) {
|
||||||
// Samsung devices running Nougat are known to be broken. See
|
// Samsung devices running Nougat are known to be broken. See
|
||||||
// https://github.com/google/ExoPlayer/issues/3373 and [Internal: b/37197802].
|
// https://github.com/google/ExoPlayer/issues/3373 and [Internal: b/37197802].
|
||||||
// Moto Z XT1650 is also affected. See
|
// Moto Z XT1650 is also affected. See
|
||||||
// https://github.com/google/ExoPlayer/issues/3215.
|
// https://github.com/google/ExoPlayer/issues/3215.
|
||||||
return false;
|
return SECURE_MODE_NONE;
|
||||||
}
|
}
|
||||||
if (Util.SDK_INT < 26 && !context.getPackageManager().hasSystemFeature(
|
if (Util.SDK_INT < 26 && !context.getPackageManager().hasSystemFeature(
|
||||||
PackageManager.FEATURE_VR_MODE_HIGH_PERFORMANCE)) {
|
PackageManager.FEATURE_VR_MODE_HIGH_PERFORMANCE)) {
|
||||||
// Pre API level 26 devices were not well tested unless they supported VR mode. See
|
// Pre API level 26 devices were not well tested unless they supported VR mode.
|
||||||
// https://github.com/google/ExoPlayer/issues/3215.
|
return SECURE_MODE_NONE;
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
|
EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
|
||||||
String eglExtensions = EGL14.eglQueryString(display, EGL10.EGL_EXTENSIONS);
|
String eglExtensions = EGL14.eglQueryString(display, EGL10.EGL_EXTENSIONS);
|
||||||
if (eglExtensions == null || !eglExtensions.contains("EGL_EXT_protected_content")) {
|
if (eglExtensions == null) {
|
||||||
// EGL_EXT_protected_content is required to enable secure dummy surfaces.
|
return SECURE_MODE_NONE;
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
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,
|
private static class DummySurfaceThread extends HandlerThread implements OnFrameAvailableListener,
|
||||||
@ -195,12 +211,12 @@ public final class DummySurface extends Surface {
|
|||||||
textureIdHolder = new int[1];
|
textureIdHolder = new int[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
public DummySurface init(boolean secure) {
|
public DummySurface init(@SecureMode int secureMode) {
|
||||||
start();
|
start();
|
||||||
handler = new Handler(getLooper(), this);
|
handler = new Handler(getLooper(), this);
|
||||||
boolean wasInterrupted = false;
|
boolean wasInterrupted = false;
|
||||||
synchronized (this) {
|
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) {
|
while (surface == null && initException == null && initError == null) {
|
||||||
try {
|
try {
|
||||||
wait();
|
wait();
|
||||||
@ -236,7 +252,7 @@ public final class DummySurface extends Surface {
|
|||||||
switch (msg.what) {
|
switch (msg.what) {
|
||||||
case MSG_INIT:
|
case MSG_INIT:
|
||||||
try {
|
try {
|
||||||
initInternal(msg.arg1 != 0);
|
initInternal(/* secureMode= */ msg.arg1);
|
||||||
} catch (RuntimeException e) {
|
} catch (RuntimeException e) {
|
||||||
Log.e(TAG, "Failed to initialize dummy surface", e);
|
Log.e(TAG, "Failed to initialize dummy surface", e);
|
||||||
initException = e;
|
initException = e;
|
||||||
@ -266,7 +282,7 @@ public final class DummySurface extends Surface {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initInternal(boolean secure) {
|
private void initInternal(@SecureMode int secureMode) {
|
||||||
display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
|
display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
|
||||||
Assertions.checkState(display != null, "eglGetDisplay failed");
|
Assertions.checkState(display != null, "eglGetDisplay failed");
|
||||||
|
|
||||||
@ -294,43 +310,45 @@ public final class DummySurface extends Surface {
|
|||||||
|
|
||||||
EGLConfig config = configs[0];
|
EGLConfig config = configs[0];
|
||||||
int[] glAttributes;
|
int[] glAttributes;
|
||||||
if (secure) {
|
if (secureMode == SECURE_MODE_NONE) {
|
||||||
glAttributes = new int[] {
|
glAttributes = new int[] {
|
||||||
EGL_CONTEXT_CLIENT_VERSION, 2,
|
EGL_CONTEXT_CLIENT_VERSION, 2,
|
||||||
EGL_PROTECTED_CONTENT_EXT, EGL_TRUE,
|
|
||||||
EGL_NONE};
|
EGL_NONE};
|
||||||
} else {
|
} else {
|
||||||
glAttributes = new int[] {
|
glAttributes =
|
||||||
EGL_CONTEXT_CLIENT_VERSION, 2,
|
new int[] {
|
||||||
EGL_NONE};
|
EGL_CONTEXT_CLIENT_VERSION, 2, EGL_PROTECTED_CONTENT_EXT, EGL_TRUE, EGL_NONE
|
||||||
|
};
|
||||||
}
|
}
|
||||||
context = eglCreateContext(display, config, android.opengl.EGL14.EGL_NO_CONTEXT, glAttributes,
|
context = eglCreateContext(display, config, android.opengl.EGL14.EGL_NO_CONTEXT, glAttributes,
|
||||||
0);
|
0);
|
||||||
Assertions.checkState(context != null, "eglCreateContext failed");
|
Assertions.checkState(context != null, "eglCreateContext failed");
|
||||||
|
|
||||||
int[] pbufferAttributes;
|
EGLSurface surface;
|
||||||
if (secure) {
|
if (secureMode == SECURE_MODE_SURFACELESS_CONTEXT) {
|
||||||
pbufferAttributes = new int[] {
|
surface = EGL_NO_SURFACE;
|
||||||
EGL_WIDTH, 1,
|
|
||||||
EGL_HEIGHT, 1,
|
|
||||||
EGL_PROTECTED_CONTENT_EXT, EGL_TRUE,
|
|
||||||
EGL_NONE};
|
|
||||||
} else {
|
} else {
|
||||||
pbufferAttributes = new int[] {
|
int[] pbufferAttributes;
|
||||||
EGL_WIDTH, 1,
|
if (secureMode == SECURE_MODE_PROTECTED_PBUFFER) {
|
||||||
EGL_HEIGHT, 1,
|
pbufferAttributes =
|
||||||
EGL_NONE};
|
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);
|
pbuffer = eglCreatePbufferSurface(display, config, pbufferAttributes, 0);
|
||||||
Assertions.checkState(pbuffer != null, "eglCreatePbufferSurface failed");
|
Assertions.checkState(pbuffer != null, "eglCreatePbufferSurface failed");
|
||||||
|
surface = pbuffer;
|
||||||
|
}
|
||||||
|
|
||||||
boolean eglMadeCurrent = eglMakeCurrent(display, pbuffer, pbuffer, context);
|
boolean eglMadeCurrent = eglMakeCurrent(display, surface, surface, context);
|
||||||
Assertions.checkState(eglMadeCurrent, "eglMakeCurrent failed");
|
Assertions.checkState(eglMadeCurrent, "eglMakeCurrent failed");
|
||||||
|
|
||||||
glGenTextures(1, textureIdHolder, 0);
|
glGenTextures(1, textureIdHolder, 0);
|
||||||
surfaceTexture = new SurfaceTexture(textureIdHolder[0]);
|
surfaceTexture = new SurfaceTexture(textureIdHolder[0]);
|
||||||
surfaceTexture.setOnFrameAvailableListener(this);
|
surfaceTexture.setOnFrameAvailableListener(this);
|
||||||
surface = new DummySurface(this, surfaceTexture, secure);
|
this.surface = new DummySurface(this, surfaceTexture, secureMode != SECURE_MODE_NONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void releaseInternal() {
|
private void releaseInternal() {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user