/** * @param baseUri The playlist's base uri. * @param variants The available variants. * @param dataSource A {@link DataSource} suitable for loading the media data. * @param timestampAdjusterProvider A provider of {@link TimestampAdjuster} instances. If * multiple {@link HlsChunkSource}s are used for a single playback, they should all share the * same provider. */ public HlsChunkSource(String baseUri, HlsMasterPlaylist.HlsUrl[] variants, DataSource dataSource, TimestampAdjusterProvider timestampAdjusterProvider) { this.baseUri = baseUri; this.variants = variants; this.dataSource = dataSource; this.timestampAdjusterProvider = timestampAdjusterProvider; playlistParser = new HlsPlaylistParser(); variantPlaylists = new HlsMediaPlaylist[variants.length]; variantLastPlaylistLoadTimesMs = new long[variants.length]; Format[] variantFormats = new Format[variants.length]; int[] initialTrackSelection = new int[variants.length]; for (int i = 0; i < variants.length; i++) { variantFormats[i] = variants[i].format; initialTrackSelection[i] = i; } trackGroup = new TrackGroup(variantFormats); trackSelection = new InitializationTrackSelection(trackGroup, initialTrackSelection); }
@Override public boolean continueLoading(long positionUs) { if (loadingFinished || loader.isLoading()) { return false; } chunkSource.getNextChunk(mediaChunks.isEmpty() ? null : mediaChunks.getLast(), pendingResetPositionUs != C.TIME_UNSET ? pendingResetPositionUs : positionUs, nextChunkHolder); boolean endOfStream = nextChunkHolder.endOfStream; Chunk loadable = nextChunkHolder.chunk; HlsMasterPlaylist.HlsUrl playlistToLoad = nextChunkHolder.playlist; nextChunkHolder.clear(); if (endOfStream) { loadingFinished = true; return true; } if (loadable == null) { if (playlistToLoad != null) { callback.onPlaylistRefreshRequired(playlistToLoad); } return false; } if (isMediaChunk(loadable)) { pendingResetPositionUs = C.TIME_UNSET; HlsMediaChunk mediaChunk = (HlsMediaChunk) loadable; mediaChunk.init(this); mediaChunks.add(mediaChunk); } long elapsedRealtimeMs = loader.startLoading(loadable, this, minLoadableRetryCount); eventDispatcher.loadStarted(loadable.dataSpec, loadable.type, trackType, loadable.trackFormat, loadable.trackSelectionReason, loadable.trackSelectionData, loadable.startTimeUs, loadable.endTimeUs, elapsedRealtimeMs); return true; }
private HlsSampleStreamWrapper buildSampleStreamWrapper(int trackType, String baseUri, HlsMasterPlaylist.HlsUrl[] variants, Format muxedAudioFormat, Format muxedCaptionFormat) { DataSource dataSource = dataSourceFactory.createDataSource(); HlsChunkSource defaultChunkSource = new HlsChunkSource(baseUri, variants, dataSource, timestampAdjusterProvider); return new HlsSampleStreamWrapper(trackType, this, defaultChunkSource, allocator, preparePositionUs, muxedAudioFormat, muxedCaptionFormat, minLoadableRetryCount, eventDispatcher); }
private static boolean variantHasExplicitCodecWithPrefix(HlsMasterPlaylist.HlsUrl variant, String prefix) { String codecs = variant.format.codecs; if (TextUtils.isEmpty(codecs)) { return false; } String[] codecArray = codecs.split("(\\s*,\\s*)|(\\s*$)"); for (String codec : codecArray) { if (codec.startsWith(prefix)) { return true; } } return false; }
@Override protected HlsMasterPlaylist getManifest(DataSource dataSource, Uri uri) throws IOException { HlsPlaylist hlsPlaylist = loadManifest(dataSource, uri); if (hlsPlaylist instanceof HlsMasterPlaylist) { return (HlsMasterPlaylist) hlsPlaylist; } else { return HlsMasterPlaylist.createSingleVariantMasterPlaylist(hlsPlaylist.baseUri); } }
@Override protected List<Segment> getAllSegments(DataSource dataSource, HlsMasterPlaylist manifest, boolean allowIndexLoadErrors) throws InterruptedException, IOException { ArrayList<String> urls = new ArrayList<>(); extractUrls(manifest.variants, urls); extractUrls(manifest.audios, urls); extractUrls(manifest.subtitles, urls); return getSegments(dataSource, manifest, urls.toArray(new String[urls.size()]), allowIndexLoadErrors); }
/** * @param masterPlaylist The master playlist. * @param mediaPlaylist The media playlist. */ HlsManifest(HlsMasterPlaylist masterPlaylist, HlsMediaPlaylist mediaPlaylist) { this.masterPlaylist = masterPlaylist; this.mediaPlaylist = mediaPlaylist; }
@Override public boolean continueLoading(long positionUs) { if (loadingFinished || loader.isLoading()) { return false; } HlsMediaChunk previousChunk; long loadPositionUs; if (isPendingReset()) { previousChunk = null; loadPositionUs = pendingResetPositionUs; } else { previousChunk = mediaChunks.getLast(); loadPositionUs = previousChunk.endTimeUs; } chunkSource.getNextChunk(previousChunk, positionUs, loadPositionUs, nextChunkHolder); boolean endOfStream = nextChunkHolder.endOfStream; Chunk loadable = nextChunkHolder.chunk; HlsMasterPlaylist.HlsUrl playlistToLoad = nextChunkHolder.playlist; nextChunkHolder.clear(); if (endOfStream) { pendingResetPositionUs = C.TIME_UNSET; loadingFinished = true; return true; } if (loadable == null) { if (playlistToLoad != null) { callback.onPlaylistRefreshRequired(playlistToLoad); } return false; } if (isMediaChunk(loadable)) { pendingResetPositionUs = C.TIME_UNSET; HlsMediaChunk mediaChunk = (HlsMediaChunk) loadable; mediaChunk.init(this); mediaChunks.add(mediaChunk); } long elapsedRealtimeMs = loader.startLoading(loadable, this, minLoadableRetryCount); eventDispatcher.loadStarted(loadable.dataSpec, loadable.type, trackType, loadable.trackFormat, loadable.trackSelectionReason, loadable.trackSelectionData, loadable.startTimeUs, loadable.endTimeUs, elapsedRealtimeMs); return true; }
public void testDownloadManifest() throws Exception { HlsMasterPlaylist manifest = hlsDownloader.getManifest(); assertNotNull(manifest); assertCachedData(cache, fakeDataSet, MASTER_PLAYLIST_URI); }
/** * Called to schedule a {@link #continueLoading(long)} call when the playlist referred by the * given url changes. */ void onPlaylistRefreshRequired(HlsMasterPlaylist.HlsUrl playlistUrl);