From ff822ff9fddae946a4417f35d2b18150fb11f539 Mon Sep 17 00:00:00 2001 From: olly Date: Thu, 30 Jan 2020 12:37:28 +0000 Subject: [PATCH] HLS: Fix key rotation Passing EXT-X-KEY DrmInitData through the FragmentedMp4Extractor doesn't work for streams with key rotation, because an extractor instance is used for multiple segments, but is only passed the EXT-X-KEY DrmInitData corresponding to the first segment. This change removes passing DrmInitData through the extractor, and instead passes it via FormatAdjustingSampleQueue. This is in-line with how manifest DrmInitData is handled during DASH playbacks. Issue: #6903 PiperOrigin-RevId: 292323429 --- RELEASENOTES.md | 2 + .../source/dash/DefaultDashChunkSource.java | 8 ++- .../extractor/mp4/FragmentedMp4Extractor.java | 36 ++++------ .../mp4/FragmentedMp4ExtractorTest.java | 13 +++- .../hls/DefaultHlsExtractorFactory.java | 13 +--- .../source/hls/HlsExtractorFactory.java | 3 - .../exoplayer2/source/hls/HlsMediaChunk.java | 4 +- .../source/hls/HlsSampleStreamWrapper.java | 72 ++++++++++++++++--- 8 files changed, 99 insertions(+), 52 deletions(-) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 5cc598d7b1..3562e28ed0 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -25,6 +25,8 @@ * Fix `SubtitlePainter` to render `EDGE_TYPE_OUTLINE` using the correct color ([#6724](https://github.com/google/ExoPlayer/pull/6724)). * DRM: Add support for attaching DRM sessions to clear content in the demo app. +* HLS: Fix playback of DRM protected content that uses key rotation + ([#6903](https://github.com/google/ExoPlayer/issues/6903)). * Downloads: Merge downloads in `SegmentDownloader` to improve overall download speed ([#5978](https://github.com/google/ExoPlayer/issues/5978)). * MP3: Add `IndexSeeker` for accurate seeks in VBR streams diff --git a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DefaultDashChunkSource.java b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DefaultDashChunkSource.java index c4a05113a4..a83d0ab3b2 100644 --- a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DefaultDashChunkSource.java +++ b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DefaultDashChunkSource.java @@ -804,10 +804,12 @@ public class DefaultDashChunkSource implements DashChunkSource { } extractor = new FragmentedMp4Extractor( - flags, null, null, null, closedCaptionFormats, playerEmsgTrackOutput); + flags, + /* timestampAdjuster= */ null, + /* sideloadedTrack= */ null, + closedCaptionFormats, + playerEmsgTrackOutput); } - // Prefer drmInitData obtained from the manifest over drmInitData obtained from the stream, - // as per DASH IF Interoperability Recommendations V3.0, 7.5.3. return new ChunkExtractorWrapper(extractor, trackType, representation.format); } } diff --git a/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/mp4/FragmentedMp4Extractor.java b/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/mp4/FragmentedMp4Extractor.java index 19dbe6bc69..a0286b695a 100644 --- a/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/mp4/FragmentedMp4Extractor.java +++ b/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/mp4/FragmentedMp4Extractor.java @@ -129,7 +129,6 @@ public class FragmentedMp4Extractor implements Extractor { // Sideloaded data. private final List closedCaptionFormats; - @Nullable private final DrmInitData sideloadedDrmInitData; // Track-linked data bundle, accessible as a whole through trackID. private final SparseArray trackBundles; @@ -185,7 +184,7 @@ public class FragmentedMp4Extractor implements Extractor { * @param flags Flags that control the extractor's behavior. */ public FragmentedMp4Extractor(@Flags int flags) { - this(flags, null); + this(flags, /* timestampAdjuster= */ null); } /** @@ -193,7 +192,7 @@ public class FragmentedMp4Extractor implements Extractor { * @param timestampAdjuster Adjusts sample timestamps. May be null if no adjustment is needed. */ public FragmentedMp4Extractor(@Flags int flags, @Nullable TimestampAdjuster timestampAdjuster) { - this(flags, timestampAdjuster, null, null); + this(flags, timestampAdjuster, /* sideloadedTrack= */ null, Collections.emptyList()); } /** @@ -201,15 +200,12 @@ public class FragmentedMp4Extractor implements Extractor { * @param timestampAdjuster Adjusts sample timestamps. May be null if no adjustment is needed. * @param sideloadedTrack Sideloaded track information, in the case that the extractor will not * receive a moov box in the input data. Null if a moov box is expected. - * @param sideloadedDrmInitData The {@link DrmInitData} to use for encrypted tracks. If null, the - * pssh boxes (if present) will be used. */ public FragmentedMp4Extractor( @Flags int flags, @Nullable TimestampAdjuster timestampAdjuster, - @Nullable Track sideloadedTrack, - @Nullable DrmInitData sideloadedDrmInitData) { - this(flags, timestampAdjuster, sideloadedTrack, sideloadedDrmInitData, Collections.emptyList()); + @Nullable Track sideloadedTrack) { + this(flags, timestampAdjuster, sideloadedTrack, Collections.emptyList()); } /** @@ -217,8 +213,6 @@ public class FragmentedMp4Extractor implements Extractor { * @param timestampAdjuster Adjusts sample timestamps. May be null if no adjustment is needed. * @param sideloadedTrack Sideloaded track information, in the case that the extractor will not * receive a moov box in the input data. Null if a moov box is expected. - * @param sideloadedDrmInitData The {@link DrmInitData} to use for encrypted tracks. If null, the - * pssh boxes (if present) will be used. * @param closedCaptionFormats For tracks that contain SEI messages, the formats of the closed * caption channels to expose. */ @@ -226,10 +220,13 @@ public class FragmentedMp4Extractor implements Extractor { @Flags int flags, @Nullable TimestampAdjuster timestampAdjuster, @Nullable Track sideloadedTrack, - @Nullable DrmInitData sideloadedDrmInitData, List closedCaptionFormats) { - this(flags, timestampAdjuster, sideloadedTrack, sideloadedDrmInitData, - closedCaptionFormats, null); + this( + flags, + timestampAdjuster, + sideloadedTrack, + closedCaptionFormats, + /* additionalEmsgTrackOutput= */ null); } /** @@ -237,8 +234,6 @@ public class FragmentedMp4Extractor implements Extractor { * @param timestampAdjuster Adjusts sample timestamps. May be null if no adjustment is needed. * @param sideloadedTrack Sideloaded track information, in the case that the extractor will not * receive a moov box in the input data. Null if a moov box is expected. - * @param sideloadedDrmInitData The {@link DrmInitData} to use for encrypted tracks. If null, the - * pssh boxes (if present) will be used. * @param closedCaptionFormats For tracks that contain SEI messages, the formats of the closed * caption channels to expose. * @param additionalEmsgTrackOutput An extra track output that will receive all emsg messages @@ -249,13 +244,11 @@ public class FragmentedMp4Extractor implements Extractor { @Flags int flags, @Nullable TimestampAdjuster timestampAdjuster, @Nullable Track sideloadedTrack, - @Nullable DrmInitData sideloadedDrmInitData, List closedCaptionFormats, @Nullable TrackOutput additionalEmsgTrackOutput) { this.flags = flags | (sideloadedTrack != null ? FLAG_SIDELOADED : 0); this.timestampAdjuster = timestampAdjuster; this.sideloadedTrack = sideloadedTrack; - this.sideloadedDrmInitData = sideloadedDrmInitData; this.closedCaptionFormats = Collections.unmodifiableList(closedCaptionFormats); this.additionalEmsgTrackOutput = additionalEmsgTrackOutput; eventMessageEncoder = new EventMessageEncoder(); @@ -470,8 +463,7 @@ public class FragmentedMp4Extractor implements Extractor { private void onMoovContainerAtomRead(ContainerAtom moov) throws ParserException { Assertions.checkState(sideloadedTrack == null, "Unexpected moov box."); - DrmInitData drmInitData = sideloadedDrmInitData != null ? sideloadedDrmInitData - : getDrmInitDataFromAtoms(moov.leafChildren); + @Nullable DrmInitData drmInitData = getDrmInitDataFromAtoms(moov.leafChildren); // Read declaration of track fragments in the Moov box. ContainerAtom mvex = moov.getContainerAtomOfType(Atom.TYPE_mvex); @@ -550,9 +542,8 @@ public class FragmentedMp4Extractor implements Extractor { private void onMoofContainerAtomRead(ContainerAtom moof) throws ParserException { parseMoof(moof, trackBundles, flags, scratchBytes); - // If drm init data is sideloaded, we ignore pssh boxes. - DrmInitData drmInitData = sideloadedDrmInitData != null ? null - : getDrmInitDataFromAtoms(moof.leafChildren); + + @Nullable DrmInitData drmInitData = getDrmInitDataFromAtoms(moof.leafChildren); if (drmInitData != null) { int trackCount = trackBundles.size(); for (int i = 0; i < trackCount; i++) { @@ -1417,6 +1408,7 @@ public class FragmentedMp4Extractor implements Extractor { } /** Returns DrmInitData from leaf atoms. */ + @Nullable private static DrmInitData getDrmInitDataFromAtoms(List leafChildren) { @Nullable ArrayList schemeDatas = null; int leafChildrenSize = leafChildren.size(); diff --git a/library/extractor/src/test/java/com/google/android/exoplayer2/extractor/mp4/FragmentedMp4ExtractorTest.java b/library/extractor/src/test/java/com/google/android/exoplayer2/extractor/mp4/FragmentedMp4ExtractorTest.java index 28e0b9e0f8..1d25848306 100644 --- a/library/extractor/src/test/java/com/google/android/exoplayer2/extractor/mp4/FragmentedMp4ExtractorTest.java +++ b/library/extractor/src/test/java/com/google/android/exoplayer2/extractor/mp4/FragmentedMp4ExtractorTest.java @@ -47,7 +47,11 @@ public final class FragmentedMp4ExtractorTest { ExtractorFactory extractorFactory = getExtractorFactory( Collections.singletonList( - Format.createTextSampleFormat(null, MimeTypes.APPLICATION_CEA608, 0, null))); + Format.createTextSampleFormat( + null, + MimeTypes.APPLICATION_CEA608, + /* selectionFlags= */ 0, + /* language= */ null))); ExtractorAsserts.assertBehavior(extractorFactory, "mp4/sample_fragmented_sei.mp4"); } @@ -64,6 +68,11 @@ public final class FragmentedMp4ExtractorTest { } private static ExtractorFactory getExtractorFactory(final List closedCaptionFormats) { - return () -> new FragmentedMp4Extractor(0, null, null, null, closedCaptionFormats); + return () -> + new FragmentedMp4Extractor( + /* flags= */ 0, + /* timestampAdjuster= */ null, + /* sideloadedTrack= */ null, + closedCaptionFormats); } } diff --git a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/DefaultHlsExtractorFactory.java b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/DefaultHlsExtractorFactory.java index 8db6166bb8..de4c425c7d 100644 --- a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/DefaultHlsExtractorFactory.java +++ b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/DefaultHlsExtractorFactory.java @@ -19,7 +19,6 @@ import android.net.Uri; import android.text.TextUtils; import androidx.annotation.Nullable; import com.google.android.exoplayer2.Format; -import com.google.android.exoplayer2.drm.DrmInitData; import com.google.android.exoplayer2.extractor.Extractor; import com.google.android.exoplayer2.extractor.ExtractorInput; import com.google.android.exoplayer2.extractor.mp3.Mp3Extractor; @@ -89,7 +88,6 @@ public final class DefaultHlsExtractorFactory implements HlsExtractorFactory { Uri uri, Format format, @Nullable List muxedCaptionFormats, - @Nullable DrmInitData drmInitData, TimestampAdjuster timestampAdjuster, Map> responseHeaders, ExtractorInput extractorInput) @@ -111,8 +109,7 @@ public final class DefaultHlsExtractorFactory implements HlsExtractorFactory { // Try selecting the extractor by the file extension. Extractor extractorByFileExtension = - createExtractorByFileExtension( - uri, format, muxedCaptionFormats, drmInitData, timestampAdjuster); + createExtractorByFileExtension(uri, format, muxedCaptionFormats, timestampAdjuster); extractorInput.resetPeekPosition(); if (sniffQuietly(extractorByFileExtension, extractorInput)) { return buildResult(extractorByFileExtension); @@ -159,7 +156,7 @@ public final class DefaultHlsExtractorFactory implements HlsExtractorFactory { if (!(extractorByFileExtension instanceof FragmentedMp4Extractor)) { FragmentedMp4Extractor fragmentedMp4Extractor = - createFragmentedMp4Extractor(timestampAdjuster, format, drmInitData, muxedCaptionFormats); + createFragmentedMp4Extractor(timestampAdjuster, format, muxedCaptionFormats); if (sniffQuietly(fragmentedMp4Extractor, extractorInput)) { return buildResult(fragmentedMp4Extractor); } @@ -186,7 +183,6 @@ public final class DefaultHlsExtractorFactory implements HlsExtractorFactory { Uri uri, Format format, @Nullable List muxedCaptionFormats, - @Nullable DrmInitData drmInitData, TimestampAdjuster timestampAdjuster) { String lastPathSegment = uri.getLastPathSegment(); if (lastPathSegment == null) { @@ -209,8 +205,7 @@ public final class DefaultHlsExtractorFactory implements HlsExtractorFactory { || lastPathSegment.startsWith(M4_FILE_EXTENSION_PREFIX, lastPathSegment.length() - 4) || lastPathSegment.startsWith(MP4_FILE_EXTENSION_PREFIX, lastPathSegment.length() - 5) || lastPathSegment.startsWith(CMF_FILE_EXTENSION_PREFIX, lastPathSegment.length() - 5)) { - return createFragmentedMp4Extractor( - timestampAdjuster, format, drmInitData, muxedCaptionFormats); + return createFragmentedMp4Extractor(timestampAdjuster, format, muxedCaptionFormats); } else { // For any other file extension, we assume TS format. return createTsExtractor( @@ -270,7 +265,6 @@ public final class DefaultHlsExtractorFactory implements HlsExtractorFactory { private static FragmentedMp4Extractor createFragmentedMp4Extractor( TimestampAdjuster timestampAdjuster, Format format, - @Nullable DrmInitData drmInitData, @Nullable List muxedCaptionFormats) { // Only enable the EMSG TrackOutput if this is the 'variant' track (i.e. the main one) to avoid // creating a separate EMSG track for every audio track in a video stream. @@ -278,7 +272,6 @@ public final class DefaultHlsExtractorFactory implements HlsExtractorFactory { /* flags= */ isFmp4Variant(format) ? FragmentedMp4Extractor.FLAG_ENABLE_EMSG_TRACK : 0, timestampAdjuster, /* sideloadedTrack= */ null, - drmInitData, muxedCaptionFormats != null ? muxedCaptionFormats : Collections.emptyList()); } diff --git a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsExtractorFactory.java b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsExtractorFactory.java index 927b79899d..ace04145ed 100644 --- a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsExtractorFactory.java +++ b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsExtractorFactory.java @@ -18,7 +18,6 @@ package com.google.android.exoplayer2.source.hls; import android.net.Uri; import androidx.annotation.Nullable; import com.google.android.exoplayer2.Format; -import com.google.android.exoplayer2.drm.DrmInitData; import com.google.android.exoplayer2.extractor.Extractor; import com.google.android.exoplayer2.extractor.ExtractorInput; import com.google.android.exoplayer2.extractor.PositionHolder; @@ -71,7 +70,6 @@ public interface HlsExtractorFactory { * @param format A {@link Format} associated with the chunk to extract. * @param muxedCaptionFormats List of muxed caption {@link Format}s. Null if no closed caption * information is available in the master playlist. - * @param drmInitData {@link DrmInitData} associated with the chunk. * @param timestampAdjuster Adjuster corresponding to the provided discontinuity sequence number. * @param responseHeaders The HTTP response headers associated with the media segment or * initialization section to extract. @@ -87,7 +85,6 @@ public interface HlsExtractorFactory { Uri uri, Format format, @Nullable List muxedCaptionFormats, - @Nullable DrmInitData drmInitData, TimestampAdjuster timestampAdjuster, Map> responseHeaders, ExtractorInput sniffingExtractorInput) diff --git a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaChunk.java b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaChunk.java index e2bc5a1755..f1d6648193 100644 --- a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaChunk.java +++ b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaChunk.java @@ -388,7 +388,6 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull; private DefaultExtractorInput prepareExtraction(DataSource dataSource, DataSpec dataSpec) throws IOException, InterruptedException { long bytesToRead = dataSource.open(dataSpec); - DefaultExtractorInput extractorInput = new DefaultExtractorInput(dataSource, dataSpec.absoluteStreamPosition, bytesToRead); @@ -402,7 +401,6 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull; dataSpec.uri, trackFormat, muxedCaptionFormats, - drmInitData, timestampAdjuster, dataSource.getResponseHeaders(), extractorInput); @@ -421,7 +419,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull; output.onNewExtractor(); extractor.init(output); } - + output.setDrmInitData(drmInitData); return extractorInput; } diff --git a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsSampleStreamWrapper.java b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsSampleStreamWrapper.java index 2e97845d23..48227d72ff 100644 --- a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsSampleStreamWrapper.java +++ b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsSampleStreamWrapper.java @@ -128,7 +128,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull; private final ArrayList hlsSampleStreams; private final Map overridingDrmInitData; - private SampleQueue[] sampleQueues; + private FormatAdjustingSampleQueue[] sampleQueues; private int[] sampleQueueTrackIds; private Set sampleQueueMappingDoneByType; private SparseIntArray sampleQueueIndicesByType; @@ -162,6 +162,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull; // Accessed only by the loading thread. private boolean tracksEnded; private long sampleOffsetUs; + @Nullable private DrmInitData drmInitData; private int chunkUid; /** @@ -207,7 +208,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull; sampleQueueTrackIds = new int[0]; sampleQueueMappingDoneByType = new HashSet<>(MAPPABLE_TYPES.size()); sampleQueueIndicesByType = new SparseIntArray(MAPPABLE_TYPES.size()); - sampleQueues = new SampleQueue[0]; + sampleQueues = new FormatAdjustingSampleQueue[0]; sampleQueueIsAudioVideoFlags = new boolean[0]; sampleQueuesEnabledStates = new boolean[0]; mediaChunks = new ArrayList<>(); @@ -904,8 +905,12 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull; private SampleQueue createSampleQueue(int id, int type) { int trackCount = sampleQueues.length; - SampleQueue trackOutput = + boolean isAudioVideo = type == C.TRACK_TYPE_AUDIO || type == C.TRACK_TYPE_VIDEO; + FormatAdjustingSampleQueue trackOutput = new FormatAdjustingSampleQueue(allocator, drmSessionManager, overridingDrmInitData); + if (isAudioVideo) { + trackOutput.setDrmInitData(drmInitData); + } trackOutput.setSampleOffsetUs(sampleOffsetUs); trackOutput.sourceId(chunkUid); trackOutput.setUpstreamFormatChangeListener(this); @@ -913,8 +918,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull; sampleQueueTrackIds[trackCount] = id; sampleQueues = Util.nullSafeArrayAppend(sampleQueues, trackOutput); sampleQueueIsAudioVideoFlags = Arrays.copyOf(sampleQueueIsAudioVideoFlags, trackCount + 1); - sampleQueueIsAudioVideoFlags[trackCount] = - type == C.TRACK_TYPE_AUDIO || type == C.TRACK_TYPE_VIDEO; + sampleQueueIsAudioVideoFlags[trackCount] = isAudioVideo; haveAudioVideoSampleQueues |= sampleQueueIsAudioVideoFlags[trackCount]; sampleQueueMappingDoneByType.add(type); sampleQueueIndicesByType.append(type, trackCount); @@ -951,10 +955,53 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull; sampleQueueMappingDoneByType.clear(); } + /** + * Sets an offset that will be added to the timestamps (and sub-sample timestamps) of samples that + * are subsequently loaded by this wrapper. + * + * @param sampleOffsetUs The timestamp offset in microseconds. + */ public void setSampleOffsetUs(long sampleOffsetUs) { - this.sampleOffsetUs = sampleOffsetUs; - for (SampleQueue sampleQueue : sampleQueues) { - sampleQueue.setSampleOffsetUs(sampleOffsetUs); + if (this.sampleOffsetUs != sampleOffsetUs) { + this.sampleOffsetUs = sampleOffsetUs; + for (SampleQueue sampleQueue : sampleQueues) { + sampleQueue.setSampleOffsetUs(sampleOffsetUs); + } + } + } + + /** + * Sets default {@link DrmInitData} for samples that are subsequently loaded by this wrapper. + * + *

This method should be called prior to loading each {@link HlsMediaChunk}. The {@link + * DrmInitData} passed should be that of an EXT-X-KEY tag that applies to the chunk, or {@code + * null} otherwise. + * + *

The final {@link DrmInitData} for subsequently queued samples is determined as followed: + * + *

    + *
  1. It is initially set to {@code drmInitData}, unless {@code drmInitData} is null in which + * case it's set to {@link Format#drmInitData} of the upstream {@link Format}. + *
  2. If the initial {@link DrmInitData} is non-null and {@link #overridingDrmInitData} + * contains an entry whose key matches the {@link DrmInitData#schemeType}, then the sample's + * {@link DrmInitData} is overridden to be this entry's value. + *
+ * + *

+ * + * @param drmInitData The default {@link DrmInitData} for samples that are subsequently queued. If + * non-null then it takes precedence over {@link Format#drmInitData} of the upstream {@link + * Format}, but will still be overridden by a matching override in {@link + * #overridingDrmInitData}. + */ + public void setDrmInitData(@Nullable DrmInitData drmInitData) { + if (!Util.areEqual(this.drmInitData, drmInitData)) { + this.drmInitData = drmInitData; + for (int i = 0; i < sampleQueues.length; i++) { + if (sampleQueueIsAudioVideoFlags[i]) { + sampleQueues[i].setDrmInitData(drmInitData); + } + } } } @@ -1280,6 +1327,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull; private static final class FormatAdjustingSampleQueue extends SampleQueue { private final Map overridingDrmInitData; + @Nullable private DrmInitData drmInitData; public FormatAdjustingSampleQueue( Allocator allocator, @@ -1289,9 +1337,15 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull; this.overridingDrmInitData = overridingDrmInitData; } + public void setDrmInitData(@Nullable DrmInitData drmInitData) { + this.drmInitData = drmInitData; + invalidateUpstreamFormatAdjustment(); + } + @Override public Format getAdjustedUpstreamFormat(Format format) { - @Nullable DrmInitData drmInitData = format.drmInitData; + @Nullable + DrmInitData drmInitData = this.drmInitData != null ? this.drmInitData : format.drmInitData; if (drmInitData != null) { @Nullable DrmInitData overridingDrmInitData = this.overridingDrmInitData.get(drmInitData.schemeType);