diff --git a/libraries/exoplayer/src/androidTest/java/androidx/media3/exoplayer/MediaExtractorCompatTest.java b/libraries/exoplayer/src/androidTest/java/androidx/media3/exoplayer/MediaExtractorCompatTest.java index 9bb3d3843d..d9e6b3dc12 100644 --- a/libraries/exoplayer/src/androidTest/java/androidx/media3/exoplayer/MediaExtractorCompatTest.java +++ b/libraries/exoplayer/src/androidTest/java/androidx/media3/exoplayer/MediaExtractorCompatTest.java @@ -15,6 +15,11 @@ */ package androidx.media3.exoplayer; +import static androidx.media3.common.C.PLAYREADY_UUID; +import static androidx.media3.common.C.WIDEVINE_UUID; +import static androidx.media3.common.MimeTypes.AUDIO_AAC; +import static androidx.media3.common.MimeTypes.VIDEO_H264; +import static androidx.media3.test.utils.TestUtil.buildTestData; import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertThrows; import static org.junit.Assume.assumeTrue; @@ -27,6 +32,7 @@ import android.media.metrics.MediaMetricsManager; import android.media.metrics.PlaybackSession; import android.net.Uri; import androidx.media3.common.C; +import androidx.media3.common.DrmInitData; import androidx.media3.common.Format; import androidx.media3.common.MimeTypes; import androidx.media3.common.ParserException; @@ -719,6 +725,74 @@ public class MediaExtractorCompatTest { assertThat(mediaExtractorCompat.getLogSessionId()).isEqualTo(logSessionId); } + @Test + public void getDrmInitData_withNoTracksHavingDrmInitData_returnsNull() throws IOException { + TrackOutput[] outputs = new TrackOutput[1]; + fakeExtractor.addReadAction( + (input, seekPosition) -> { + outputs[0] = extractorOutput.track(/* id= */ 0, C.TRACK_TYPE_VIDEO); + outputs[0].format(PLACEHOLDER_FORMAT_VIDEO); + extractorOutput.endTracks(); + return Extractor.RESULT_CONTINUE; + }); + + mediaExtractorCompat.setDataSource(PLACEHOLDER_URI, /* offset= */ 0); + + assertThat(mediaExtractorCompat.getDrmInitData()).isNull(); + } + + @Test + public void getDrmInitData_withSingleTrackHavingDrmInitData_returnsDrmInitData() + throws IOException { + TrackOutput[] outputs = new TrackOutput[1]; + DrmInitData.SchemeData schemeData = + new DrmInitData.SchemeData( + WIDEVINE_UUID, VIDEO_H264, buildTestData(128, 1 /* data seed */)); + DrmInitData drmInitData = new DrmInitData(schemeData); + fakeExtractor.addReadAction( + (input, seekPosition) -> { + outputs[0] = extractorOutput.track(/* id= */ 0, C.TRACK_TYPE_VIDEO); + outputs[0].format( + PLACEHOLDER_FORMAT_VIDEO.buildUpon().setDrmInitData(drmInitData).build()); + extractorOutput.endTracks(); + return Extractor.RESULT_CONTINUE; + }); + + mediaExtractorCompat.setDataSource(PLACEHOLDER_URI, /* offset= */ 0); + + assertThat(mediaExtractorCompat.getDrmInitData()).isEqualTo(drmInitData); + } + + @Test + public void getDrmInitData_withMultipleTracksHavingDrmInitData_returnsFirstNonNullDrmInitData() + throws IOException { + TrackOutput[] outputs = new TrackOutput[3]; + DrmInitData.SchemeData firstSchemeData = + new DrmInitData.SchemeData(WIDEVINE_UUID, AUDIO_AAC, buildTestData(128, 1 /* data seed */)); + DrmInitData firstDrmInitData = new DrmInitData(firstSchemeData); + DrmInitData.SchemeData secondSchemeData = + new DrmInitData.SchemeData( + PLAYREADY_UUID, AUDIO_AAC, buildTestData(128, 2 /* data seed */)); + DrmInitData secondDrmInitData = new DrmInitData(secondSchemeData); + fakeExtractor.addReadAction( + (input, seekPosition) -> { + outputs[0] = extractorOutput.track(/* id= */ 0, C.TRACK_TYPE_VIDEO); + outputs[0].format(PLACEHOLDER_FORMAT_VIDEO); + outputs[1] = extractorOutput.track(/* id= */ 1, C.TRACK_TYPE_AUDIO); + outputs[1].format( + PLACEHOLDER_FORMAT_AUDIO.buildUpon().setDrmInitData(firstDrmInitData).build()); + outputs[2] = extractorOutput.track(/* id= */ 2, C.TRACK_TYPE_AUDIO); + outputs[2].format( + PLACEHOLDER_FORMAT_AUDIO.buildUpon().setDrmInitData(secondDrmInitData).build()); + extractorOutput.endTracks(); + return Extractor.RESULT_CONTINUE; + }); + + mediaExtractorCompat.setDataSource(PLACEHOLDER_URI, /* offset= */ 0); + + assertThat(mediaExtractorCompat.getDrmInitData()).isEqualTo(firstDrmInitData); + } + // Internal methods. private void assertReadSample(int trackIndex, long timeUs, int size, byte... sampleData) { diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/MediaExtractorCompat.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/MediaExtractorCompat.java index 4e7621ed03..20782c998d 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/MediaExtractorCompat.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/MediaExtractorCompat.java @@ -35,6 +35,7 @@ import androidx.annotation.Nullable; import androidx.annotation.RequiresApi; import androidx.annotation.VisibleForTesting; import androidx.media3.common.C; +import androidx.media3.common.DrmInitData; import androidx.media3.common.Format; import androidx.media3.common.ParserException; import androidx.media3.common.util.Assertions; @@ -588,6 +589,24 @@ public final class MediaExtractorCompat { return logSessionId != null ? logSessionId : LogSessionId.LOG_SESSION_ID_NONE; } + /** + * Extracts the DRM initialization data from the available tracks, if it exists. + * + * @return The {@link DrmInitData} in the content, or {@code null} if no recognizable DRM format + * is found. + */ + @Nullable + public DrmInitData getDrmInitData() { + for (int i = 0; i < tracks.size(); i++) { + Format format = tracks.get(i).getFormat(formatHolder, noDataBuffer); + if (format.drmInitData == null) { + continue; + } + return format.drmInitData; + } + return null; + } + @VisibleForTesting(otherwise = NONE) public Allocator getAllocator() { return allocator; @@ -832,15 +851,8 @@ public final class MediaExtractorCompat { public MediaFormat createDownstreamMediaFormat( FormatHolder scratchFormatHolder, DecoderInputBuffer scratchNoDataDecoderInputBuffer) { - scratchFormatHolder.clear(); - sampleQueue.read( - scratchFormatHolder, - scratchNoDataDecoderInputBuffer, - FLAG_REQUIRE_FORMAT, - /* loadingFinished= */ false); - Format result = checkNotNull(scratchFormatHolder.format); - MediaFormat mediaFormatResult = MediaFormatUtil.createMediaFormatFromFormat(result); - scratchFormatHolder.clear(); + Format format = getFormat(scratchFormatHolder, scratchNoDataDecoderInputBuffer); + MediaFormat mediaFormatResult = MediaFormatUtil.createMediaFormatFromFormat(format); if (compatibilityTrackMimeType != null) { if (Util.SDK_INT >= 29) { mediaFormatResult.removeKey(MediaFormat.KEY_CODECS_STRING); @@ -850,6 +862,19 @@ public final class MediaExtractorCompat { return mediaFormatResult; } + private Format getFormat( + FormatHolder scratchFormatHolder, DecoderInputBuffer scratchNoDataDecoderInputBuffer) { + scratchFormatHolder.clear(); + sampleQueue.read( + scratchFormatHolder, + scratchNoDataDecoderInputBuffer, + FLAG_REQUIRE_FORMAT, + /* loadingFinished= */ false); + Format format = checkNotNull(scratchFormatHolder.format); + scratchFormatHolder.clear(); + return format; + } + public void discardFrontSample() { sampleQueue.skip(/* count= */ 1); sampleQueue.discardToRead();