Plumb DrmSessionManager into HlsMediaSource
PiperOrigin-RevId: 259520431
This commit is contained in:
parent
e6bafec418
commit
2a8cf2f5ef
@ -484,7 +484,9 @@ public class PlayerActivity extends AppCompatActivity
|
||||
.setDrmSessionManager(drmSessionManager)
|
||||
.createMediaSource(uri);
|
||||
case C.TYPE_HLS:
|
||||
return new HlsMediaSource.Factory(dataSourceFactory).createMediaSource(uri);
|
||||
return new HlsMediaSource.Factory(dataSourceFactory)
|
||||
.setDrmSessionManager(drmSessionManager)
|
||||
.createMediaSource(uri);
|
||||
case C.TYPE_OTHER:
|
||||
return new ProgressiveMediaSource.Factory(dataSourceFactory)
|
||||
.setDrmSessionManager(drmSessionManager)
|
||||
|
@ -22,6 +22,8 @@ import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.Format;
|
||||
import com.google.android.exoplayer2.SeekParameters;
|
||||
import com.google.android.exoplayer2.drm.DrmInitData;
|
||||
import com.google.android.exoplayer2.drm.DrmSession;
|
||||
import com.google.android.exoplayer2.drm.DrmSessionManager;
|
||||
import com.google.android.exoplayer2.extractor.Extractor;
|
||||
import com.google.android.exoplayer2.offline.StreamKey;
|
||||
import com.google.android.exoplayer2.source.CompositeSequenceableLoaderFactory;
|
||||
@ -63,6 +65,7 @@ public final class HlsMediaPeriod implements MediaPeriod, HlsSampleStreamWrapper
|
||||
private final HlsPlaylistTracker playlistTracker;
|
||||
private final HlsDataSourceFactory dataSourceFactory;
|
||||
@Nullable private final TransferListener mediaTransferListener;
|
||||
private final DrmSessionManager<?> drmSessionManager;
|
||||
private final LoadErrorHandlingPolicy loadErrorHandlingPolicy;
|
||||
private final EventDispatcher eventDispatcher;
|
||||
private final Allocator allocator;
|
||||
@ -91,6 +94,8 @@ public final class HlsMediaPeriod implements MediaPeriod, HlsSampleStreamWrapper
|
||||
* and keys.
|
||||
* @param mediaTransferListener The transfer listener to inform of any media data transfers. May
|
||||
* be null if no listener is available.
|
||||
* @param drmSessionManager The {@link DrmSessionManager} to acquire {@link DrmSession
|
||||
* DrmSessions} with.
|
||||
* @param loadErrorHandlingPolicy A {@link LoadErrorHandlingPolicy}.
|
||||
* @param eventDispatcher A dispatcher to notify of events.
|
||||
* @param allocator An {@link Allocator} from which to obtain media buffer allocations.
|
||||
@ -104,6 +109,7 @@ public final class HlsMediaPeriod implements MediaPeriod, HlsSampleStreamWrapper
|
||||
HlsPlaylistTracker playlistTracker,
|
||||
HlsDataSourceFactory dataSourceFactory,
|
||||
@Nullable TransferListener mediaTransferListener,
|
||||
DrmSessionManager<?> drmSessionManager,
|
||||
LoadErrorHandlingPolicy loadErrorHandlingPolicy,
|
||||
EventDispatcher eventDispatcher,
|
||||
Allocator allocator,
|
||||
@ -114,6 +120,7 @@ public final class HlsMediaPeriod implements MediaPeriod, HlsSampleStreamWrapper
|
||||
this.playlistTracker = playlistTracker;
|
||||
this.dataSourceFactory = dataSourceFactory;
|
||||
this.mediaTransferListener = mediaTransferListener;
|
||||
this.drmSessionManager = drmSessionManager;
|
||||
this.loadErrorHandlingPolicy = loadErrorHandlingPolicy;
|
||||
this.eventDispatcher = eventDispatcher;
|
||||
this.allocator = allocator;
|
||||
@ -735,6 +742,7 @@ public final class HlsMediaPeriod implements MediaPeriod, HlsSampleStreamWrapper
|
||||
allocator,
|
||||
positionUs,
|
||||
muxedAudioFormat,
|
||||
drmSessionManager,
|
||||
loadErrorHandlingPolicy,
|
||||
eventDispatcher);
|
||||
}
|
||||
|
@ -20,6 +20,8 @@ import android.os.Handler;
|
||||
import androidx.annotation.Nullable;
|
||||
import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.ExoPlayerLibraryInfo;
|
||||
import com.google.android.exoplayer2.drm.DrmSession;
|
||||
import com.google.android.exoplayer2.drm.DrmSessionManager;
|
||||
import com.google.android.exoplayer2.extractor.Extractor;
|
||||
import com.google.android.exoplayer2.offline.StreamKey;
|
||||
import com.google.android.exoplayer2.source.BaseMediaSource;
|
||||
@ -65,6 +67,7 @@ public final class HlsMediaSource extends BaseMediaSource
|
||||
@Nullable private List<StreamKey> streamKeys;
|
||||
private HlsPlaylistTracker.Factory playlistTrackerFactory;
|
||||
private CompositeSequenceableLoaderFactory compositeSequenceableLoaderFactory;
|
||||
private DrmSessionManager<?> drmSessionManager;
|
||||
private LoadErrorHandlingPolicy loadErrorHandlingPolicy;
|
||||
private boolean allowChunklessPreparation;
|
||||
private boolean useSessionKeys;
|
||||
@ -93,6 +96,7 @@ public final class HlsMediaSource extends BaseMediaSource
|
||||
playlistParserFactory = new DefaultHlsPlaylistParserFactory();
|
||||
playlistTrackerFactory = DefaultHlsPlaylistTracker.FACTORY;
|
||||
extractorFactory = HlsExtractorFactory.DEFAULT;
|
||||
drmSessionManager = DrmSessionManager.getDummyDrmSessionManager();
|
||||
loadErrorHandlingPolicy = new DefaultLoadErrorHandlingPolicy();
|
||||
compositeSequenceableLoaderFactory = new DefaultCompositeSequenceableLoaderFactory();
|
||||
}
|
||||
@ -127,6 +131,20 @@ public final class HlsMediaSource extends BaseMediaSource
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the {@link DrmSessionManager} to use for acquiring {@link DrmSession DrmSessions}. The
|
||||
* default value is {@link DrmSessionManager#DUMMY}.
|
||||
*
|
||||
* @param drmSessionManager The {@link DrmSessionManager}.
|
||||
* @return This factory, for convenience.
|
||||
* @throws IllegalStateException If one of the {@code create} methods has already been called.
|
||||
*/
|
||||
public Factory setDrmSessionManager(DrmSessionManager<?> drmSessionManager) {
|
||||
Assertions.checkState(!isCreateCalled);
|
||||
this.drmSessionManager = drmSessionManager;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the {@link LoadErrorHandlingPolicy}. The default value is created by calling {@link
|
||||
* DefaultLoadErrorHandlingPolicy#DefaultLoadErrorHandlingPolicy()}.
|
||||
@ -271,6 +289,7 @@ public final class HlsMediaSource extends BaseMediaSource
|
||||
hlsDataSourceFactory,
|
||||
extractorFactory,
|
||||
compositeSequenceableLoaderFactory,
|
||||
drmSessionManager,
|
||||
loadErrorHandlingPolicy,
|
||||
playlistTrackerFactory.createTracker(
|
||||
hlsDataSourceFactory, loadErrorHandlingPolicy, playlistParserFactory),
|
||||
@ -297,6 +316,7 @@ public final class HlsMediaSource extends BaseMediaSource
|
||||
private final Uri manifestUri;
|
||||
private final HlsDataSourceFactory dataSourceFactory;
|
||||
private final CompositeSequenceableLoaderFactory compositeSequenceableLoaderFactory;
|
||||
private final DrmSessionManager<?> drmSessionManager;
|
||||
private final LoadErrorHandlingPolicy loadErrorHandlingPolicy;
|
||||
private final boolean allowChunklessPreparation;
|
||||
private final boolean useSessionKeys;
|
||||
@ -310,6 +330,7 @@ public final class HlsMediaSource extends BaseMediaSource
|
||||
HlsDataSourceFactory dataSourceFactory,
|
||||
HlsExtractorFactory extractorFactory,
|
||||
CompositeSequenceableLoaderFactory compositeSequenceableLoaderFactory,
|
||||
DrmSessionManager<?> drmSessionManager,
|
||||
LoadErrorHandlingPolicy loadErrorHandlingPolicy,
|
||||
HlsPlaylistTracker playlistTracker,
|
||||
boolean allowChunklessPreparation,
|
||||
@ -319,6 +340,7 @@ public final class HlsMediaSource extends BaseMediaSource
|
||||
this.dataSourceFactory = dataSourceFactory;
|
||||
this.extractorFactory = extractorFactory;
|
||||
this.compositeSequenceableLoaderFactory = compositeSequenceableLoaderFactory;
|
||||
this.drmSessionManager = drmSessionManager;
|
||||
this.loadErrorHandlingPolicy = loadErrorHandlingPolicy;
|
||||
this.playlistTracker = playlistTracker;
|
||||
this.allowChunklessPreparation = allowChunklessPreparation;
|
||||
@ -352,6 +374,7 @@ public final class HlsMediaSource extends BaseMediaSource
|
||||
playlistTracker,
|
||||
dataSourceFactory,
|
||||
mediaTransferListener,
|
||||
drmSessionManager,
|
||||
loadErrorHandlingPolicy,
|
||||
eventDispatcher,
|
||||
allocator,
|
||||
|
@ -62,8 +62,11 @@ import java.io.IOException;
|
||||
if (sampleQueueIndex == HlsSampleStreamWrapper.SAMPLE_QUEUE_INDEX_NO_MAPPING_FATAL) {
|
||||
throw new SampleQueueMappingException(
|
||||
sampleStreamWrapper.getTrackGroups().get(trackGroupIndex).getFormat(0).sampleMimeType);
|
||||
} else if (sampleQueueIndex == HlsSampleStreamWrapper.SAMPLE_QUEUE_INDEX_PENDING) {
|
||||
sampleStreamWrapper.maybeThrowError();
|
||||
} else if (sampleQueueIndex != HlsSampleStreamWrapper.SAMPLE_QUEUE_INDEX_NO_MAPPING_NON_FATAL) {
|
||||
sampleStreamWrapper.maybeThrowError(sampleQueueIndex);
|
||||
}
|
||||
sampleStreamWrapper.maybeThrowError();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -23,12 +23,15 @@ import com.google.android.exoplayer2.Format;
|
||||
import com.google.android.exoplayer2.FormatHolder;
|
||||
import com.google.android.exoplayer2.decoder.DecoderInputBuffer;
|
||||
import com.google.android.exoplayer2.drm.DrmInitData;
|
||||
import com.google.android.exoplayer2.drm.DrmSession;
|
||||
import com.google.android.exoplayer2.drm.DrmSessionManager;
|
||||
import com.google.android.exoplayer2.extractor.DummyTrackOutput;
|
||||
import com.google.android.exoplayer2.extractor.ExtractorOutput;
|
||||
import com.google.android.exoplayer2.extractor.SeekMap;
|
||||
import com.google.android.exoplayer2.extractor.TrackOutput;
|
||||
import com.google.android.exoplayer2.metadata.Metadata;
|
||||
import com.google.android.exoplayer2.metadata.id3.PrivFrame;
|
||||
import com.google.android.exoplayer2.source.DecryptableSampleQueueReader;
|
||||
import com.google.android.exoplayer2.source.MediaSourceEventListener.EventDispatcher;
|
||||
import com.google.android.exoplayer2.source.SampleQueue;
|
||||
import com.google.android.exoplayer2.source.SampleQueue.UpstreamFormatChangedListener;
|
||||
@ -94,6 +97,7 @@ import java.util.Set;
|
||||
private final HlsChunkSource chunkSource;
|
||||
private final Allocator allocator;
|
||||
private final Format muxedAudioFormat;
|
||||
private final DrmSessionManager<?> drmSessionManager;
|
||||
private final LoadErrorHandlingPolicy loadErrorHandlingPolicy;
|
||||
private final Loader loader;
|
||||
private final EventDispatcher eventDispatcher;
|
||||
@ -107,6 +111,7 @@ import java.util.Set;
|
||||
private final Map<String, DrmInitData> overridingDrmInitData;
|
||||
|
||||
private SampleQueue[] sampleQueues;
|
||||
private DecryptableSampleQueueReader[] sampleQueueReaders;
|
||||
private int[] sampleQueueTrackIds;
|
||||
private boolean audioSampleQueueMappingDone;
|
||||
private int audioSampleQueueIndex;
|
||||
@ -154,6 +159,8 @@ import java.util.Set;
|
||||
* @param allocator An {@link Allocator} from which to obtain media buffer allocations.
|
||||
* @param positionUs The position from which to start loading media.
|
||||
* @param muxedAudioFormat Optional muxed audio {@link Format} as defined by the master playlist.
|
||||
* @param drmSessionManager The {@link DrmSessionManager} to acquire {@link DrmSession
|
||||
* DrmSessions} with.
|
||||
* @param loadErrorHandlingPolicy A {@link LoadErrorHandlingPolicy}.
|
||||
* @param eventDispatcher A dispatcher to notify of events.
|
||||
*/
|
||||
@ -165,6 +172,7 @@ import java.util.Set;
|
||||
Allocator allocator,
|
||||
long positionUs,
|
||||
Format muxedAudioFormat,
|
||||
DrmSessionManager<?> drmSessionManager,
|
||||
LoadErrorHandlingPolicy loadErrorHandlingPolicy,
|
||||
EventDispatcher eventDispatcher) {
|
||||
this.trackType = trackType;
|
||||
@ -173,6 +181,7 @@ import java.util.Set;
|
||||
this.overridingDrmInitData = overridingDrmInitData;
|
||||
this.allocator = allocator;
|
||||
this.muxedAudioFormat = muxedAudioFormat;
|
||||
this.drmSessionManager = drmSessionManager;
|
||||
this.loadErrorHandlingPolicy = loadErrorHandlingPolicy;
|
||||
this.eventDispatcher = eventDispatcher;
|
||||
loader = new Loader("Loader:HlsSampleStreamWrapper");
|
||||
@ -181,6 +190,7 @@ import java.util.Set;
|
||||
audioSampleQueueIndex = C.INDEX_UNSET;
|
||||
videoSampleQueueIndex = C.INDEX_UNSET;
|
||||
sampleQueues = new SampleQueue[0];
|
||||
sampleQueueReaders = new DecryptableSampleQueueReader[0];
|
||||
sampleQueueIsAudioVideoFlags = new boolean[0];
|
||||
sampleQueuesEnabledStates = new boolean[0];
|
||||
mediaChunks = new ArrayList<>();
|
||||
@ -211,7 +221,7 @@ import java.util.Set;
|
||||
public void prepareWithMasterPlaylistInfo(
|
||||
TrackGroup[] trackGroups, int primaryTrackGroupIndex, int... optionalTrackGroupsIndices) {
|
||||
prepared = true;
|
||||
this.trackGroups = new TrackGroupArray(trackGroups);
|
||||
this.trackGroups = createTrackGroupArrayWithDrmInfo(trackGroups);
|
||||
optionalTrackGroups = new HashSet<>();
|
||||
for (int optionalTrackGroupIndex : optionalTrackGroupsIndices) {
|
||||
optionalTrackGroups.add(this.trackGroups.get(optionalTrackGroupIndex));
|
||||
@ -438,6 +448,9 @@ import java.util.Set;
|
||||
for (SampleQueue sampleQueue : sampleQueues) {
|
||||
sampleQueue.discardToEnd();
|
||||
}
|
||||
for (DecryptableSampleQueueReader reader : sampleQueueReaders) {
|
||||
reader.release();
|
||||
}
|
||||
}
|
||||
loader.release(this);
|
||||
handler.removeCallbacksAndMessages(null);
|
||||
@ -448,6 +461,9 @@ import java.util.Set;
|
||||
@Override
|
||||
public void onLoaderReleased() {
|
||||
resetSampleQueues();
|
||||
for (DecryptableSampleQueueReader reader : sampleQueueReaders) {
|
||||
reader.release();
|
||||
}
|
||||
}
|
||||
|
||||
public void setIsTimestampMaster(boolean isTimestampMaster) {
|
||||
@ -461,7 +477,12 @@ import java.util.Set;
|
||||
// SampleStream implementation.
|
||||
|
||||
public boolean isReady(int sampleQueueIndex) {
|
||||
return loadingFinished || (!isPendingReset() && sampleQueues[sampleQueueIndex].hasNextSample());
|
||||
return !isPendingReset() && sampleQueueReaders[sampleQueueIndex].isReady(loadingFinished);
|
||||
}
|
||||
|
||||
public void maybeThrowError(int sampleQueueIndex) throws IOException {
|
||||
maybeThrowError();
|
||||
sampleQueueReaders[sampleQueueIndex].maybeThrowError();
|
||||
}
|
||||
|
||||
public void maybeThrowError() throws IOException {
|
||||
@ -494,13 +515,8 @@ import java.util.Set;
|
||||
}
|
||||
|
||||
int result =
|
||||
sampleQueues[sampleQueueIndex].read(
|
||||
formatHolder,
|
||||
buffer,
|
||||
requireFormat,
|
||||
/* allowOnlyClearBuffers= */ false,
|
||||
loadingFinished,
|
||||
lastSeekPositionUs);
|
||||
sampleQueueReaders[sampleQueueIndex].read(
|
||||
formatHolder, buffer, requireFormat, loadingFinished, lastSeekPositionUs);
|
||||
if (result == C.RESULT_FORMAT_READ) {
|
||||
Format format = formatHolder.format;
|
||||
if (sampleQueueIndex == primarySampleQueueIndex) {
|
||||
@ -516,12 +532,6 @@ import java.util.Set;
|
||||
: upstreamTrackFormat;
|
||||
format = format.copyWithManifestFormatInfo(trackFormat);
|
||||
}
|
||||
if (format.drmInitData != null) {
|
||||
DrmInitData drmInitData = overridingDrmInitData.get(format.drmInitData.schemeType);
|
||||
if (drmInitData != null) {
|
||||
format = format.copyWithDrmInitData(drmInitData);
|
||||
}
|
||||
}
|
||||
formatHolder.format = format;
|
||||
}
|
||||
return result;
|
||||
@ -836,6 +846,9 @@ import java.util.Set;
|
||||
sampleQueueTrackIds[trackCount] = id;
|
||||
sampleQueues = Arrays.copyOf(sampleQueues, trackCount + 1);
|
||||
sampleQueues[trackCount] = trackOutput;
|
||||
sampleQueueReaders = Arrays.copyOf(sampleQueueReaders, trackCount + 1);
|
||||
sampleQueueReaders[trackCount] =
|
||||
new DecryptableSampleQueueReader(sampleQueues[trackCount], drmSessionManager);
|
||||
sampleQueueIsAudioVideoFlags = Arrays.copyOf(sampleQueueIsAudioVideoFlags, trackCount + 1);
|
||||
sampleQueueIsAudioVideoFlags[trackCount] = type == C.TRACK_TYPE_AUDIO
|
||||
|| type == C.TRACK_TYPE_VIDEO;
|
||||
@ -1048,11 +1061,29 @@ import java.util.Set;
|
||||
trackGroups[i] = new TrackGroup(deriveFormat(trackFormat, sampleFormat, false));
|
||||
}
|
||||
}
|
||||
this.trackGroups = new TrackGroupArray(trackGroups);
|
||||
this.trackGroups = createTrackGroupArrayWithDrmInfo(trackGroups);
|
||||
Assertions.checkState(optionalTrackGroups == null);
|
||||
optionalTrackGroups = Collections.emptySet();
|
||||
}
|
||||
|
||||
private TrackGroupArray createTrackGroupArrayWithDrmInfo(TrackGroup[] trackGroups) {
|
||||
for (int i = 0; i < trackGroups.length; i++) {
|
||||
TrackGroup trackGroup = trackGroups[i];
|
||||
Format[] exposedFormats = new Format[trackGroup.length];
|
||||
for (int j = 0; j < trackGroup.length; j++) {
|
||||
Format format = trackGroup.getFormat(j);
|
||||
if (format.drmInitData != null) {
|
||||
format =
|
||||
format.copyWithExoMediaCryptoType(
|
||||
drmSessionManager.getExoMediaCryptoType(format.drmInitData));
|
||||
}
|
||||
exposedFormats[j] = format;
|
||||
}
|
||||
trackGroups[i] = new TrackGroup(exposedFormats);
|
||||
}
|
||||
return new TrackGroupArray(trackGroups);
|
||||
}
|
||||
|
||||
private HlsMediaChunk getLastMediaChunk() {
|
||||
return mediaChunks.get(mediaChunks.size() - 1);
|
||||
}
|
||||
|
@ -22,6 +22,7 @@ import static org.mockito.Mockito.when;
|
||||
import android.net.Uri;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import com.google.android.exoplayer2.Format;
|
||||
import com.google.android.exoplayer2.drm.DrmSessionManager;
|
||||
import com.google.android.exoplayer2.source.CompositeSequenceableLoaderFactory;
|
||||
import com.google.android.exoplayer2.source.MediaSource.MediaPeriodId;
|
||||
import com.google.android.exoplayer2.source.MediaSourceEventListener.EventDispatcher;
|
||||
@ -81,6 +82,7 @@ public final class HlsMediaPeriodTest {
|
||||
mockPlaylistTracker,
|
||||
mockDataSourceFactory,
|
||||
mock(TransferListener.class),
|
||||
mock(DrmSessionManager.class),
|
||||
mock(LoadErrorHandlingPolicy.class),
|
||||
new EventDispatcher()
|
||||
.withParameters(
|
||||
|
Loading…
x
Reference in New Issue
Block a user