mirror of
https://github.com/androidx/media.git
synced 2025-05-21 23:56:32 +08:00
Simplify playback of clear samples without keys
- Move property to DrmSession; it feels like a more natural place for it to go (and provides greater flexibility). - Change flags to a boolean. PiperOrigin-RevId: 281758729
This commit is contained in:
parent
a7d962bf27
commit
ab8816214e
@ -106,6 +106,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
|
||||
private final ProvisioningManager<T> provisioningManager;
|
||||
private final ReleaseCallback<T> releaseCallback;
|
||||
private final @DefaultDrmSessionManager.Mode int mode;
|
||||
private final boolean playClearSamplesWithoutKeys;
|
||||
private final boolean isPlaceholderSession;
|
||||
private final HashMap<String, String> keyRequestParameters;
|
||||
private final EventDispatcher<DefaultDrmSessionEventListener> eventDispatcher;
|
||||
@ -154,6 +155,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
|
||||
ReleaseCallback<T> releaseCallback,
|
||||
@Nullable List<SchemeData> schemeDatas,
|
||||
@DefaultDrmSessionManager.Mode int mode,
|
||||
boolean playClearSamplesWithoutKeys,
|
||||
boolean isPlaceholderSession,
|
||||
@Nullable byte[] offlineLicenseKeySetId,
|
||||
HashMap<String, String> keyRequestParameters,
|
||||
@ -170,6 +172,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
|
||||
this.releaseCallback = releaseCallback;
|
||||
this.mediaDrm = mediaDrm;
|
||||
this.mode = mode;
|
||||
this.playClearSamplesWithoutKeys = playClearSamplesWithoutKeys;
|
||||
this.isPlaceholderSession = isPlaceholderSession;
|
||||
if (offlineLicenseKeySetId != null) {
|
||||
this.offlineLicenseKeySetId = offlineLicenseKeySetId;
|
||||
@ -228,6 +231,11 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
|
||||
return state;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean playClearSamplesWithoutKeys() {
|
||||
return playClearSamplesWithoutKeys;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final @Nullable DrmSessionException getError() {
|
||||
return state == STATE_ERROR ? lastException : null;
|
||||
|
@ -58,7 +58,7 @@ public class DefaultDrmSessionManager<T extends ExoMediaCrypto> implements DrmSe
|
||||
private ExoMediaDrm.Provider<ExoMediaCrypto> exoMediaDrmProvider;
|
||||
private boolean multiSession;
|
||||
private int[] useDrmSessionsForClearContentTrackTypes;
|
||||
@Flags private int flags;
|
||||
private boolean playClearSamplesWithoutKeys;
|
||||
private LoadErrorHandlingPolicy loadErrorHandlingPolicy;
|
||||
|
||||
/**
|
||||
@ -164,11 +164,7 @@ public class DefaultDrmSessionManager<T extends ExoMediaCrypto> implements DrmSe
|
||||
* @return This builder.
|
||||
*/
|
||||
public Builder setPlayClearSamplesWithoutKeys(boolean playClearSamplesWithoutKeys) {
|
||||
if (playClearSamplesWithoutKeys) {
|
||||
this.flags |= FLAG_PLAY_CLEAR_SAMPLES_WITHOUT_KEYS;
|
||||
} else {
|
||||
this.flags &= ~FLAG_PLAY_CLEAR_SAMPLES_WITHOUT_KEYS;
|
||||
}
|
||||
this.playClearSamplesWithoutKeys = playClearSamplesWithoutKeys;
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -192,7 +188,7 @@ public class DefaultDrmSessionManager<T extends ExoMediaCrypto> implements DrmSe
|
||||
keyRequestParameters,
|
||||
multiSession,
|
||||
useDrmSessionsForClearContentTrackTypes,
|
||||
flags,
|
||||
playClearSamplesWithoutKeys,
|
||||
loadErrorHandlingPolicy);
|
||||
}
|
||||
}
|
||||
@ -245,7 +241,7 @@ public class DefaultDrmSessionManager<T extends ExoMediaCrypto> implements DrmSe
|
||||
private final EventDispatcher<DefaultDrmSessionEventListener> eventDispatcher;
|
||||
private final boolean multiSession;
|
||||
private final int[] useDrmSessionsForClearContentTrackTypes;
|
||||
@Flags private final int flags;
|
||||
private final boolean playClearSamplesWithoutKeys;
|
||||
private final ProvisioningManagerImpl provisioningManagerImpl;
|
||||
private final LoadErrorHandlingPolicy loadErrorHandlingPolicy;
|
||||
|
||||
@ -339,7 +335,7 @@ public class DefaultDrmSessionManager<T extends ExoMediaCrypto> implements DrmSe
|
||||
keyRequestParameters == null ? new HashMap<>() : keyRequestParameters,
|
||||
multiSession,
|
||||
/* useDrmSessionsForClearContentTrackTypes= */ new int[0],
|
||||
/* flags= */ 0,
|
||||
/* playClearSamplesWithoutKeys= */ false,
|
||||
new DefaultLoadErrorHandlingPolicy(initialDrmRequestRetryCount));
|
||||
}
|
||||
|
||||
@ -352,7 +348,7 @@ public class DefaultDrmSessionManager<T extends ExoMediaCrypto> implements DrmSe
|
||||
HashMap<String, String> keyRequestParameters,
|
||||
boolean multiSession,
|
||||
int[] useDrmSessionsForClearContentTrackTypes,
|
||||
@Flags int flags,
|
||||
boolean playClearSamplesWithoutKeys,
|
||||
LoadErrorHandlingPolicy loadErrorHandlingPolicy) {
|
||||
Assertions.checkNotNull(uuid);
|
||||
Assertions.checkArgument(!C.COMMON_PSSH_UUID.equals(uuid), "Use C.CLEARKEY_UUID instead");
|
||||
@ -363,7 +359,7 @@ public class DefaultDrmSessionManager<T extends ExoMediaCrypto> implements DrmSe
|
||||
this.eventDispatcher = new EventDispatcher<>();
|
||||
this.multiSession = multiSession;
|
||||
this.useDrmSessionsForClearContentTrackTypes = useDrmSessionsForClearContentTrackTypes;
|
||||
this.flags = flags;
|
||||
this.playClearSamplesWithoutKeys = playClearSamplesWithoutKeys;
|
||||
this.loadErrorHandlingPolicy = loadErrorHandlingPolicy;
|
||||
provisioningManagerImpl = new ProvisioningManagerImpl();
|
||||
mode = MODE_PLAYBACK;
|
||||
@ -541,12 +537,6 @@ public class DefaultDrmSessionManager<T extends ExoMediaCrypto> implements DrmSe
|
||||
return session;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Flags
|
||||
public final int getFlags() {
|
||||
return flags;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public Class<T> getExoMediaCryptoType(DrmInitData drmInitData) {
|
||||
@ -571,6 +561,8 @@ public class DefaultDrmSessionManager<T extends ExoMediaCrypto> implements DrmSe
|
||||
private DefaultDrmSession<T> createNewDefaultSession(
|
||||
@Nullable List<SchemeData> schemeDatas, boolean isPlaceholderSession) {
|
||||
Assertions.checkNotNull(exoMediaDrm);
|
||||
// Placeholder sessions should always play clear samples without keys.
|
||||
boolean playClearSamplesWithoutKeys = this.playClearSamplesWithoutKeys | isPlaceholderSession;
|
||||
return new DefaultDrmSession<>(
|
||||
uuid,
|
||||
exoMediaDrm,
|
||||
@ -578,6 +570,7 @@ public class DefaultDrmSessionManager<T extends ExoMediaCrypto> implements DrmSe
|
||||
/* releaseCallback= */ this::onSessionReleased,
|
||||
schemeDatas,
|
||||
mode,
|
||||
playClearSamplesWithoutKeys,
|
||||
isPlaceholderSession,
|
||||
offlineLicenseKeySetId,
|
||||
keyRequestParameters,
|
||||
|
@ -93,6 +93,11 @@ public interface DrmSession<T extends ExoMediaCrypto> {
|
||||
*/
|
||||
@State int getState();
|
||||
|
||||
/** Returns whether this session allows playback of clear samples prior to keys being loaded. */
|
||||
default boolean playClearSamplesWithoutKeys() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the cause of the error state, or null if {@link #getState()} is not {@link
|
||||
* #STATE_ERROR}.
|
||||
|
@ -16,13 +16,9 @@
|
||||
package com.google.android.exoplayer2.drm;
|
||||
|
||||
import android.os.Looper;
|
||||
import androidx.annotation.IntDef;
|
||||
import androidx.annotation.Nullable;
|
||||
import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.drm.DrmInitData.SchemeData;
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
/**
|
||||
* Manages a DRM session.
|
||||
@ -59,26 +55,6 @@ public interface DrmSessionManager<T extends ExoMediaCrypto> {
|
||||
}
|
||||
};
|
||||
|
||||
/** Flags that control the handling of DRM protected content. */
|
||||
@Documented
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@IntDef(
|
||||
flag = true,
|
||||
value = {FLAG_PLAY_CLEAR_SAMPLES_WITHOUT_KEYS})
|
||||
@interface Flags {}
|
||||
|
||||
/**
|
||||
* When this flag is set, clear samples of an encrypted region may be rendered when no keys are
|
||||
* available.
|
||||
*
|
||||
* <p>Encrypted media may contain clear (un-encrypted) regions. For example a media file may start
|
||||
* with a short clear region so as to allow playback to begin in parallel with key acquisition.
|
||||
* When this flag is set, consumers of sample data are permitted to access the clear regions of
|
||||
* encrypted media files when the associated {@link DrmSession} has not yet obtained the keys
|
||||
* necessary for the encrypted regions of the media.
|
||||
*/
|
||||
int FLAG_PLAY_CLEAR_SAMPLES_WITHOUT_KEYS = 1;
|
||||
|
||||
/**
|
||||
* Acquires any required resources.
|
||||
*
|
||||
@ -136,12 +112,6 @@ public interface DrmSessionManager<T extends ExoMediaCrypto> {
|
||||
*/
|
||||
DrmSession<T> acquireSession(Looper playbackLooper, DrmInitData drmInitData);
|
||||
|
||||
/** Returns flags that control the handling of DRM protected content. */
|
||||
@Flags
|
||||
default int getFlags() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link ExoMediaCrypto} type returned by sessions acquired using the given {@link
|
||||
* DrmInitData}, or null if a session cannot be acquired with the given {@link DrmInitData}.
|
||||
|
@ -33,6 +33,11 @@ public final class ErrorStateDrmSession<T extends ExoMediaCrypto> implements Drm
|
||||
return STATE_ERROR;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean playClearSamplesWithoutKeys() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public DrmSessionException getError() {
|
||||
|
@ -49,7 +49,6 @@ import java.io.IOException;
|
||||
private static final int SAMPLE_CAPACITY_INCREMENT = 1000;
|
||||
|
||||
private final DrmSessionManager<?> drmSessionManager;
|
||||
private final boolean playClearSamplesWithoutKeys;
|
||||
|
||||
@Nullable private Format downstreamFormat;
|
||||
@Nullable private DrmSession<?> currentDrmSession;
|
||||
@ -79,9 +78,6 @@ import java.io.IOException;
|
||||
|
||||
public SampleMetadataQueue(DrmSessionManager<?> drmSessionManager) {
|
||||
this.drmSessionManager = drmSessionManager;
|
||||
playClearSamplesWithoutKeys =
|
||||
(drmSessionManager.getFlags() & DrmSessionManager.FLAG_PLAY_CLEAR_SAMPLES_WITHOUT_KEYS)
|
||||
!= 0;
|
||||
capacity = SAMPLE_CAPACITY_INCREMENT;
|
||||
sourceIds = new int[capacity];
|
||||
offsets = new long[capacity];
|
||||
@ -282,7 +278,7 @@ import java.io.IOException;
|
||||
} else {
|
||||
// A clear sample in an encrypted section may be read if playClearSamplesWithoutKeys is true.
|
||||
return (flags[relativeReadIndex] & C.BUFFER_FLAG_ENCRYPTED) == 0
|
||||
&& playClearSamplesWithoutKeys;
|
||||
&& Assertions.checkNotNull(currentDrmSession).playClearSamplesWithoutKeys();
|
||||
}
|
||||
}
|
||||
|
||||
@ -341,7 +337,8 @@ import java.io.IOException;
|
||||
boolean mayReadSample =
|
||||
skipDrmChecks
|
||||
|| Util.castNonNull(downstreamFormat).drmInitData == null
|
||||
|| (playClearSamplesWithoutKeys && !isNextSampleEncrypted)
|
||||
|| (Assertions.checkNotNull(currentDrmSession).playClearSamplesWithoutKeys()
|
||||
&& !isNextSampleEncrypted)
|
||||
|| Assertions.checkNotNull(currentDrmSession).getState()
|
||||
== DrmSession.STATE_OPENED_WITH_KEYS;
|
||||
if (!mayReadSample) {
|
||||
|
@ -331,8 +331,7 @@ public final class SampleQueueTest {
|
||||
|
||||
@Test
|
||||
public void testIsReadyReturnsTrueForClearSampleAndPlayClearSamplesWithoutKeysIsTrue() {
|
||||
when(mockDrmSessionManager.getFlags())
|
||||
.thenReturn(DrmSessionManager.FLAG_PLAY_CLEAR_SAMPLES_WITHOUT_KEYS);
|
||||
when(mockDrmSession.playClearSamplesWithoutKeys()).thenReturn(true);
|
||||
// We recreate the queue to ensure the mock DRM session manager flags are taken into account.
|
||||
sampleQueue = new SampleQueue(allocator, mockDrmSessionManager);
|
||||
writeTestDataWithEncryptedSections();
|
||||
@ -458,8 +457,7 @@ public final class SampleQueueTest {
|
||||
|
||||
@Test
|
||||
public void testAllowPlayClearSamplesWithoutKeysReadsClearSamples() {
|
||||
when(mockDrmSessionManager.getFlags())
|
||||
.thenReturn(DrmSessionManager.FLAG_PLAY_CLEAR_SAMPLES_WITHOUT_KEYS);
|
||||
when(mockDrmSession.playClearSamplesWithoutKeys()).thenReturn(true);
|
||||
// We recreate the queue to ensure the mock DRM session manager flags are taken into account.
|
||||
sampleQueue = new SampleQueue(allocator, mockDrmSessionManager);
|
||||
when(mockDrmSession.getState()).thenReturn(DrmSession.STATE_OPENED);
|
||||
|
Loading…
x
Reference in New Issue
Block a user