diff --git a/libraries/exoplayer_hls/src/test/java/androidx/media3/exoplayer/hls/e2etest/HlsPlaybackTest.java b/libraries/exoplayer_hls/src/test/java/androidx/media3/exoplayer/hls/e2etest/HlsPlaybackTest.java new file mode 100644 index 0000000000..7fd7b5a231 --- /dev/null +++ b/libraries/exoplayer_hls/src/test/java/androidx/media3/exoplayer/hls/e2etest/HlsPlaybackTest.java @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package androidx.media3.exoplayer.hls.e2etest; + +import android.content.Context; +import android.graphics.SurfaceTexture; +import android.view.Surface; +import androidx.media3.common.MediaItem; +import androidx.media3.common.Player; +import androidx.media3.exoplayer.ExoPlayer; +import androidx.media3.test.utils.CapturingRenderersFactory; +import androidx.media3.test.utils.DumpFileAsserts; +import androidx.media3.test.utils.FakeClock; +import androidx.media3.test.utils.robolectric.PlaybackOutput; +import androidx.media3.test.utils.robolectric.ShadowMediaCodecConfig; +import androidx.media3.test.utils.robolectric.TestPlayerRunHelper; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; +import org.junit.Ignore; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +/** End-to-end tests using HLS samples. */ +@RunWith(AndroidJUnit4.class) +public final class HlsPlaybackTest { + + @Rule + public ShadowMediaCodecConfig mediaCodecConfig = + ShadowMediaCodecConfig.forAllSupportedMimeTypes(); + + @Test + @Ignore( + "Disabled until subtitles are reliably asserted in robolectric tests [internal b/174661563].") + public void webvttSubtitles() throws Exception { + Context applicationContext = ApplicationProvider.getApplicationContext(); + CapturingRenderersFactory capturingRenderersFactory = + new CapturingRenderersFactory(applicationContext); + ExoPlayer player = + new ExoPlayer.Builder(applicationContext, capturingRenderersFactory) + .setClock(new FakeClock(/* isAutoAdvancing= */ true)) + .build(); + player.setVideoSurface(new Surface(new SurfaceTexture(/* texName= */ 1))); + PlaybackOutput playbackOutput = PlaybackOutput.register(player, capturingRenderersFactory); + + player.setMediaItem(MediaItem.fromUri("asset:///media/hls/webvtt/multivariant_playlist.m3u8")); + player.prepare(); + player.play(); + TestPlayerRunHelper.runUntilPlaybackState(player, Player.STATE_ENDED); + player.release(); + + DumpFileAsserts.assertOutput( + applicationContext, playbackOutput, "playbackdumps/hls/one_sec_with_subs.dump"); + } +} diff --git a/libraries/test_data/src/test/assets/media/hls/webvtt/english_subs.vtt b/libraries/test_data/src/test/assets/media/hls/webvtt/english_subs.vtt new file mode 100644 index 0000000000..bcd0d70e33 --- /dev/null +++ b/libraries/test_data/src/test/assets/media/hls/webvtt/english_subs.vtt @@ -0,0 +1,7 @@ +WEBVTT # This comment is allowed + +00:00.567 --> 00:00.801 +This is the first subtitle. + +00:00.667 --> 00:00.951 +This is the second subtitle. diff --git a/libraries/test_data/src/test/assets/media/hls/webvtt/media_playlist.m3u8 b/libraries/test_data/src/test/assets/media/hls/webvtt/media_playlist.m3u8 new file mode 100644 index 0000000000..c81a0b52a1 --- /dev/null +++ b/libraries/test_data/src/test/assets/media/hls/webvtt/media_playlist.m3u8 @@ -0,0 +1,8 @@ +#EXTM3U +#EXT-X-VERSION:3 +#EXT-X-TARGETDURATION:1 +#EXT-X-MEDIA-SEQUENCE:0 +#EXT-X-PLAYLIST-TYPE:VOD +#EXTINF:1.001000, +sample.mp4 +#EXT-X-ENDLIST diff --git a/libraries/test_data/src/test/assets/media/hls/webvtt/multivariant_playlist.m3u8 b/libraries/test_data/src/test/assets/media/hls/webvtt/multivariant_playlist.m3u8 new file mode 100644 index 0000000000..d3d17ed895 --- /dev/null +++ b/libraries/test_data/src/test/assets/media/hls/webvtt/multivariant_playlist.m3u8 @@ -0,0 +1,7 @@ +#EXTM3U +#EXT-X-INDEPENDENT-SEGMENTS + +#EXT-X-MEDIA:TYPE=SUBTITLES,GROUP-ID="subs",NAME="English",LANGUAGE="en",DEFAULT=YES,URI="playlist_vtt.m3u8" + +#EXT-X-STREAM-INF:BANDWIDTH=718000,CODECS="avc1.64001f",SUBTITLES="subs" +media_playlist.m3u8 diff --git a/libraries/test_data/src/test/assets/media/hls/webvtt/playlist_vtt.m3u8 b/libraries/test_data/src/test/assets/media/hls/webvtt/playlist_vtt.m3u8 new file mode 100644 index 0000000000..c0a6edaafc --- /dev/null +++ b/libraries/test_data/src/test/assets/media/hls/webvtt/playlist_vtt.m3u8 @@ -0,0 +1,7 @@ +#EXTM3U +#EXT-X-VERSION:3 +#EXT-X-TARGETDURATION:1 +#EXT-X-MEDIA-SEQUENCE:0 +#EXTINF:1.001000, +english_subs.vtt +#EXT-X-ENDLIST diff --git a/libraries/test_data/src/test/assets/media/hls/webvtt/sample.mp4 b/libraries/test_data/src/test/assets/media/hls/webvtt/sample.mp4 new file mode 100644 index 0000000000..7f456f85f9 Binary files /dev/null and b/libraries/test_data/src/test/assets/media/hls/webvtt/sample.mp4 differ diff --git a/libraries/test_data/src/test/assets/playbackdumps/hls/one_sec_with_subs.dump b/libraries/test_data/src/test/assets/playbackdumps/hls/one_sec_with_subs.dump new file mode 100644 index 0000000000..467a7fddd6 --- /dev/null +++ b/libraries/test_data/src/test/assets/playbackdumps/hls/one_sec_with_subs.dump @@ -0,0 +1,268 @@ +MediaCodecAdapter (exotest.video.avc): + inputBuffers: + count = 31 + input buffer #0: + timeUs = 1000000000000 + contents = length 36692, hash D216076E + input buffer #1: + timeUs = 1000000066733 + contents = length 5312, hash D45D3CA0 + input buffer #2: + timeUs = 1000000033366 + contents = length 599, hash 1BE7812D + input buffer #3: + timeUs = 1000000200200 + contents = length 7735, hash 4490F110 + input buffer #4: + timeUs = 1000000133466 + contents = length 987, hash 560B5036 + input buffer #5: + timeUs = 1000000100100 + contents = length 673, hash ED7CD8C7 + input buffer #6: + timeUs = 1000000166833 + contents = length 523, hash 3020DF50 + input buffer #7: + timeUs = 1000000333666 + contents = length 6061, hash 736C72B2 + input buffer #8: + timeUs = 1000000266933 + contents = length 992, hash FE132F23 + input buffer #9: + timeUs = 1000000233566 + contents = length 623, hash 5B2C1816 + input buffer #10: + timeUs = 1000000300300 + contents = length 421, hash 742E69C1 + input buffer #11: + timeUs = 1000000433766 + contents = length 4899, hash F72F86A1 + input buffer #12: + timeUs = 1000000400400 + contents = length 568, hash 519A8E50 + input buffer #13: + timeUs = 1000000367033 + contents = length 620, hash 3990AA39 + input buffer #14: + timeUs = 1000000567233 + contents = length 5450, hash F06EC4AA + input buffer #15: + timeUs = 1000000500500 + contents = length 1051, hash 92DFA63A + input buffer #16: + timeUs = 1000000467133 + contents = length 874, hash 69587FB4 + input buffer #17: + timeUs = 1000000533866 + contents = length 781, hash 36BE495B + input buffer #18: + timeUs = 1000000700700 + contents = length 4725, hash AC0C8CD3 + input buffer #19: + timeUs = 1000000633966 + contents = length 1022, hash 5D8BFF34 + input buffer #20: + timeUs = 1000000600600 + contents = length 790, hash 99413A99 + input buffer #21: + timeUs = 1000000667333 + contents = length 610, hash 5E129290 + input buffer #22: + timeUs = 1000000834166 + contents = length 2751, hash 769974CB + input buffer #23: + timeUs = 1000000767433 + contents = length 745, hash B78A477A + input buffer #24: + timeUs = 1000000734066 + contents = length 621, hash CF741E7A + input buffer #25: + timeUs = 1000000800800 + contents = length 505, hash 1DB4894E + input buffer #26: + timeUs = 1000000967633 + contents = length 1268, hash C15348DC + input buffer #27: + timeUs = 1000000900900 + contents = length 880, hash C2DE85D0 + input buffer #28: + timeUs = 1000000867533 + contents = length 530, hash C98BC6A8 + input buffer #29: + timeUs = 1000000934266 + contents = length 568, hash 4FE5C8EA + input buffer #30: + timeUs = 0 + flags = 4 + contents = length 0, hash 1 + outputBuffers: + count = 30 + output buffer #0: + timeUs = 1000000000000 + size = 36692 + rendered = true + output buffer #1: + timeUs = 1000000066733 + size = 5312 + rendered = true + output buffer #2: + timeUs = 1000000033366 + size = 599 + rendered = true + output buffer #3: + timeUs = 1000000200200 + size = 7735 + rendered = true + output buffer #4: + timeUs = 1000000133466 + size = 987 + rendered = true + output buffer #5: + timeUs = 1000000100100 + size = 673 + rendered = true + output buffer #6: + timeUs = 1000000166833 + size = 523 + rendered = true + output buffer #7: + timeUs = 1000000333666 + size = 6061 + rendered = true + output buffer #8: + timeUs = 1000000266933 + size = 992 + rendered = true + output buffer #9: + timeUs = 1000000233566 + size = 623 + rendered = true + output buffer #10: + timeUs = 1000000300300 + size = 421 + rendered = true + output buffer #11: + timeUs = 1000000433766 + size = 4899 + rendered = true + output buffer #12: + timeUs = 1000000400400 + size = 568 + rendered = true + output buffer #13: + timeUs = 1000000367033 + size = 620 + rendered = true + output buffer #14: + timeUs = 1000000567233 + size = 5450 + rendered = true + output buffer #15: + timeUs = 1000000500500 + size = 1051 + rendered = true + output buffer #16: + timeUs = 1000000467133 + size = 874 + rendered = true + output buffer #17: + timeUs = 1000000533866 + size = 781 + rendered = true + output buffer #18: + timeUs = 1000000700700 + size = 4725 + rendered = true + output buffer #19: + timeUs = 1000000633966 + size = 1022 + rendered = true + output buffer #20: + timeUs = 1000000600600 + size = 790 + rendered = true + output buffer #21: + timeUs = 1000000667333 + size = 610 + rendered = true + output buffer #22: + timeUs = 1000000834166 + size = 2751 + rendered = true + output buffer #23: + timeUs = 1000000767433 + size = 745 + rendered = true + output buffer #24: + timeUs = 1000000734066 + size = 621 + rendered = true + output buffer #25: + timeUs = 1000000800800 + size = 505 + rendered = true + output buffer #26: + timeUs = 1000000967633 + size = 1268 + rendered = true + output buffer #27: + timeUs = 1000000900900 + size = 880 + rendered = true + output buffer #28: + timeUs = 1000000867533 + size = 530 + rendered = true + output buffer #29: + timeUs = 1000000934266 + size = 568 + rendered = true +TextOutput: + Subtitle[0]: + presentationTimeUs = 0 + Cues = [] + Subtitle[1]: + presentationTimeUs = 567000 + Cue[0]: + text = This is the first subtitle. + textAlignment = ALIGN_CENTER + line = -1.0 + lineType = 1 + lineAnchor = 0 + position = 0.5 + positionAnchor = 1 + size = 1.0 + Subtitle[2]: + presentationTimeUs = 667000 + Cue[0]: + text = This is the first subtitle. + textAlignment = ALIGN_CENTER + line = -1.0 + lineType = 1 + lineAnchor = 0 + position = 0.5 + positionAnchor = 1 + size = 1.0 + Cue[1]: + text = This is the second subtitle. + textAlignment = ALIGN_CENTER + line = -2.0 + lineType = 1 + lineAnchor = 0 + position = 0.5 + positionAnchor = 1 + size = 1.0 + Subtitle[3]: + presentationTimeUs = 801000 + Cue[0]: + text = This is the second subtitle. + textAlignment = ALIGN_CENTER + line = -1.0 + lineType = 1 + lineAnchor = 0 + position = 0.5 + positionAnchor = 1 + size = 1.0 + Subtitle[4]: + presentationTimeUs = 951000 + Cues = []