use of androidx.media3.exoplayer.ExoPlayer in project media by androidx.
the class DefaultHlsExtractorFactory method createExtractor.
@Override
public BundledHlsMediaChunkExtractor createExtractor(Uri uri, Format format, @Nullable List<Format> muxedCaptionFormats, TimestampAdjuster timestampAdjuster, Map<String, List<String>> responseHeaders, ExtractorInput sniffingExtractorInput, PlayerId playerId) throws IOException {
@FileTypes.Type int formatInferredFileType = FileTypes.inferFileTypeFromMimeType(format.sampleMimeType);
@FileTypes.Type int responseHeadersInferredFileType = FileTypes.inferFileTypeFromResponseHeaders(responseHeaders);
@FileTypes.Type int uriInferredFileType = FileTypes.inferFileTypeFromUri(uri);
// Defines the order in which to try the extractors.
List<Integer> fileTypeOrder = new ArrayList<>(/* initialCapacity= */
DEFAULT_EXTRACTOR_ORDER.length);
addFileTypeIfValidAndNotPresent(formatInferredFileType, fileTypeOrder);
addFileTypeIfValidAndNotPresent(responseHeadersInferredFileType, fileTypeOrder);
addFileTypeIfValidAndNotPresent(uriInferredFileType, fileTypeOrder);
for (int fileType : DEFAULT_EXTRACTOR_ORDER) {
addFileTypeIfValidAndNotPresent(fileType, fileTypeOrder);
}
// Extractor to be used if the type is not recognized.
@Nullable Extractor fallBackExtractor = null;
sniffingExtractorInput.resetPeekPosition();
for (int i = 0; i < fileTypeOrder.size(); i++) {
int fileType = fileTypeOrder.get(i);
Extractor extractor = checkNotNull(createExtractorByFileType(fileType, format, muxedCaptionFormats, timestampAdjuster));
if (sniffQuietly(extractor, sniffingExtractorInput)) {
return new BundledHlsMediaChunkExtractor(extractor, format, timestampAdjuster);
}
if (fallBackExtractor == null && (fileType == formatInferredFileType || fileType == responseHeadersInferredFileType || fileType == uriInferredFileType || fileType == FileTypes.TS)) {
// If sniffing fails, fallback to the file types inferred from context. If all else fails,
// fallback to Transport Stream. See https://github.com/google/ExoPlayer/issues/8219.
fallBackExtractor = extractor;
}
}
return new BundledHlsMediaChunkExtractor(checkNotNull(fallBackExtractor), format, timestampAdjuster);
}
use of androidx.media3.exoplayer.ExoPlayer in project media by androidx.
the class DashPlaybackTest method emsgNearToPeriodBoundary.
// https://github.com/google/ExoPlayer/issues/8710
@Test
public void emsgNearToPeriodBoundary() 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/dash/emsg/sample.mpd"));
player.prepare();
player.play();
TestPlayerRunHelper.runUntilPlaybackState(player, Player.STATE_ENDED);
player.release();
DumpFileAsserts.assertOutput(applicationContext, playbackOutput, "playbackdumps/dash/emsg.dump");
}
use of androidx.media3.exoplayer.ExoPlayer in project media by androidx.
the class HlsMediaPlaylistParserTest method parseMediaPlaylist.
@Test
public void parseMediaPlaylist() throws Exception {
Uri playlistUri = Uri.parse("https://example.com/test.m3u8");
String playlistString = "#EXTM3U\n" + "#EXT-X-VERSION:3\n" + "#EXT-X-PLAYLIST-TYPE:VOD\n" + "#EXT-X-START:TIME-OFFSET=-25\n" + "#EXT-X-TARGETDURATION:8\n" + "#EXT-X-MEDIA-SEQUENCE:2679\n" + "#EXT-X-DISCONTINUITY-SEQUENCE:4\n" + "#EXT-X-ALLOW-CACHE:YES\n" + "\n" + "#EXTINF:7.975,\n" + "#EXT-X-BYTERANGE:51370@0\n" + "https://priv.example.com/fileSequence2679.ts\n" + "\n" + "#EXT-X-KEY:METHOD=AES-128," + "URI=\"https://priv.example.com/key.php?r=2680\",IV=0x1566B\n" + "#EXTINF:7.975,segment title\n" + "#EXT-X-BYTERANGE:51501@2147483648\n" + "https://priv.example.com/fileSequence2680.ts\n" + "\n" + "#EXT-X-KEY:METHOD=NONE\n" + "#EXTINF:7.941,segment title .,:/# with interesting chars\n" + // @2147535149
"#EXT-X-BYTERANGE:51501\n" + "https://priv.example.com/fileSequence2681.ts\n" + "\n" + "#EXT-X-DISCONTINUITY\n" + "#EXT-X-KEY:METHOD=AES-128,URI=\"https://priv.example.com/key.php?r=2682\"\n" + // Trailing comma is omitted.
"#EXTINF:7.975\n" + // @2147586650
"#EXT-X-BYTERANGE:51740\n" + "https://priv.example.com/fileSequence2682.ts\n" + "\n" + "#EXTINF:7.975,\n" + "https://priv.example.com/fileSequence2683.ts\n" + "\n" + // 2.002 tests correct rounding, see https://github.com/google/ExoPlayer/issues/9575.
"#EXTINF:2.002,\n" + "https://priv.example.com/fileSequence2684.ts\n" + "#EXT-X-ENDLIST";
InputStream inputStream = new ByteArrayInputStream(Util.getUtf8Bytes(playlistString));
HlsPlaylist playlist = new HlsPlaylistParser().parse(playlistUri, inputStream);
HlsMediaPlaylist mediaPlaylist = (HlsMediaPlaylist) playlist;
assertThat(mediaPlaylist.playlistType).isEqualTo(HlsMediaPlaylist.PLAYLIST_TYPE_VOD);
assertThat(mediaPlaylist.startOffsetUs).isEqualTo(mediaPlaylist.durationUs - 25000000);
assertThat(mediaPlaylist.mediaSequence).isEqualTo(2679);
assertThat(mediaPlaylist.version).isEqualTo(3);
assertThat(mediaPlaylist.hasEndTag).isTrue();
assertThat(mediaPlaylist.protectionSchemes).isNull();
assertThat(mediaPlaylist.targetDurationUs).isEqualTo(8000000);
assertThat(mediaPlaylist.partTargetDurationUs).isEqualTo(C.TIME_UNSET);
List<Segment> segments = mediaPlaylist.segments;
assertThat(segments).isNotNull();
assertThat(segments).hasSize(6);
Segment segment = segments.get(0);
assertThat(mediaPlaylist.discontinuitySequence + segment.relativeDiscontinuitySequence).isEqualTo(4);
assertThat(segment.durationUs).isEqualTo(7975000);
assertThat(segment.title).isEqualTo("");
assertThat(segment.fullSegmentEncryptionKeyUri).isNull();
assertThat(segment.encryptionIV).isNull();
assertThat(segment.byteRangeLength).isEqualTo(51370);
assertThat(segment.byteRangeOffset).isEqualTo(0);
assertThat(segment.url).isEqualTo("https://priv.example.com/fileSequence2679.ts");
segment = segments.get(1);
assertThat(segment.relativeDiscontinuitySequence).isEqualTo(0);
assertThat(segment.durationUs).isEqualTo(7975000);
assertThat(segment.title).isEqualTo("segment title");
assertThat(segment.fullSegmentEncryptionKeyUri).isEqualTo("https://priv.example.com/key.php?r=2680");
assertThat(segment.encryptionIV).isEqualTo("0x1566B");
assertThat(segment.byteRangeLength).isEqualTo(51501);
assertThat(segment.byteRangeOffset).isEqualTo(2147483648L);
assertThat(segment.url).isEqualTo("https://priv.example.com/fileSequence2680.ts");
segment = segments.get(2);
assertThat(segment.relativeDiscontinuitySequence).isEqualTo(0);
assertThat(segment.durationUs).isEqualTo(7941000);
assertThat(segment.title).isEqualTo("segment title .,:/# with interesting chars");
assertThat(segment.fullSegmentEncryptionKeyUri).isNull();
assertThat(segment.encryptionIV).isEqualTo(null);
assertThat(segment.byteRangeLength).isEqualTo(51501);
assertThat(segment.byteRangeOffset).isEqualTo(2147535149L);
assertThat(segment.url).isEqualTo("https://priv.example.com/fileSequence2681.ts");
segment = segments.get(3);
assertThat(segment.relativeDiscontinuitySequence).isEqualTo(1);
assertThat(segment.durationUs).isEqualTo(7975000);
assertThat(segment.title).isEqualTo("");
assertThat(segment.fullSegmentEncryptionKeyUri).isEqualTo("https://priv.example.com/key.php?r=2682");
// 0xA7A == 2682.
assertThat(segment.encryptionIV).isNotNull();
assertThat(segment.encryptionIV).ignoringCase().isEqualTo("A7A");
assertThat(segment.byteRangeLength).isEqualTo(51740);
assertThat(segment.byteRangeOffset).isEqualTo(2147586650L);
assertThat(segment.url).isEqualTo("https://priv.example.com/fileSequence2682.ts");
segment = segments.get(4);
assertThat(segment.relativeDiscontinuitySequence).isEqualTo(1);
assertThat(segment.durationUs).isEqualTo(7975000);
assertThat(segment.title).isEqualTo("");
assertThat(segment.fullSegmentEncryptionKeyUri).isEqualTo("https://priv.example.com/key.php?r=2682");
// 0xA7B == 2683.
assertThat(segment.encryptionIV).isNotNull();
assertThat(segment.encryptionIV).ignoringCase().isEqualTo("A7B");
assertThat(segment.byteRangeLength).isEqualTo(C.LENGTH_UNSET);
assertThat(segment.byteRangeOffset).isEqualTo(0);
assertThat(segment.url).isEqualTo("https://priv.example.com/fileSequence2683.ts");
segment = segments.get(5);
assertThat(segment.durationUs).isEqualTo(2002000);
}
use of androidx.media3.exoplayer.ExoPlayer in project media by androidx.
the class AdTagLoader method loadAdInternal.
private void loadAdInternal(AdMediaInfo adMediaInfo, AdPodInfo adPodInfo) {
if (adsManager == null) {
// Drop events after release.
if (configuration.debugModeEnabled) {
Log.d(TAG, "loadAd after release " + getAdMediaInfoString(adMediaInfo) + ", ad pod " + adPodInfo);
}
return;
}
int adGroupIndex = getAdGroupIndexForAdPod(adPodInfo);
int adIndexInAdGroup = adPodInfo.getAdPosition() - 1;
AdInfo adInfo = new AdInfo(adGroupIndex, adIndexInAdGroup);
// The ad URI may already be known, so force put to update it if needed.
adInfoByAdMediaInfo.forcePut(adMediaInfo, adInfo);
if (configuration.debugModeEnabled) {
Log.d(TAG, "loadAd " + getAdMediaInfoString(adMediaInfo));
}
if (adPlaybackState.isAdInErrorState(adGroupIndex, adIndexInAdGroup)) {
// timeout after its media load timeout.
return;
}
// The ad count may increase on successive loads of ads in the same ad pod, for example, due to
// separate requests for ad tags with multiple ads within the ad pod completing after an earlier
// ad has loaded. See also https://github.com/google/ExoPlayer/issues/7477.
AdPlaybackState.AdGroup adGroup = adPlaybackState.getAdGroup(adInfo.adGroupIndex);
adPlaybackState = adPlaybackState.withAdCount(adInfo.adGroupIndex, max(adPodInfo.getTotalAds(), adGroup.states.length));
adGroup = adPlaybackState.getAdGroup(adInfo.adGroupIndex);
for (int i = 0; i < adIndexInAdGroup; i++) {
// Any preceding ads that haven't loaded are not going to load.
if (adGroup.states[i] == AdPlaybackState.AD_STATE_UNAVAILABLE) {
adPlaybackState = adPlaybackState.withAdLoadError(adGroupIndex, /* adIndexInAdGroup= */
i);
}
}
Uri adUri = Uri.parse(adMediaInfo.getUrl());
adPlaybackState = adPlaybackState.withAdUri(adInfo.adGroupIndex, adInfo.adIndexInAdGroup, adUri);
updateAdPlaybackState();
}
use of androidx.media3.exoplayer.ExoPlayer in project media by androidx.
the class RtspMediaPeriodTest method prepareMediaPeriod_refreshesSourceInfoAndCallsOnPrepared.
@Test
public void prepareMediaPeriod_refreshesSourceInfoAndCallsOnPrepared() throws Exception {
RtpPacketStreamDump rtpPacketStreamDump = RtspTestUtils.readRtpPacketStreamDump("media/rtsp/aac-dump.json");
rtspServer = new RtspServer(new RtspServer.ResponseProvider() {
@Override
public RtspResponse getOptionsResponse() {
return new RtspResponse(/* status= */
200, new RtspHeaders.Builder().add(RtspHeaders.PUBLIC, "OPTIONS, DESCRIBE").build());
}
@Override
public RtspResponse getDescribeResponse(Uri requestedUri, RtspHeaders headers) {
return RtspTestUtils.newDescribeResponseWithSdpMessage("v=0\r\n" + "o=- 1606776316530225 1 IN IP4 127.0.0.1\r\n" + "s=Exoplayer test\r\n" + "t=0 0\r\n" + // The session is 50.46s long.
"a=range:npt=0-50.46\r\n", ImmutableList.of(rtpPacketStreamDump), requestedUri);
}
});
AtomicBoolean prepareCallbackCalled = new AtomicBoolean();
AtomicLong refreshedSourceDurationMs = new AtomicLong();
mediaPeriod = new RtspMediaPeriod(new DefaultAllocator(/* trimOnReset= */
true, C.DEFAULT_BUFFER_SEGMENT_SIZE), new TransferRtpDataChannelFactory(DEFAULT_TIMEOUT_MS), RtspTestUtils.getTestUri(rtspServer.startAndGetPortNumber()), /* listener= */
timing -> refreshedSourceDurationMs.set(timing.getDurationMs()), /* userAgent= */
"ExoPlayer:RtspPeriodTest", /* socketFactory= */
SocketFactory.getDefault(), /* debugLoggingEnabled= */
false);
mediaPeriod.prepare(new MediaPeriod.Callback() {
@Override
public void onPrepared(MediaPeriod mediaPeriod) {
prepareCallbackCalled.set(true);
}
@Override
public void onContinueLoadingRequested(MediaPeriod source) {
source.continueLoading(/* positionUs= */
0);
}
}, /* positionUs= */
0);
RobolectricUtil.runMainLooperUntil(prepareCallbackCalled::get);
mediaPeriod.release();
assertThat(refreshedSourceDurationMs.get()).isEqualTo(50_460);
}
Aggregations