/** * @param manifestLoaderErrorThrower Throws errors affecting loading of manifests. * @param manifest The initial manifest. * @param periodIndex The index of the period in the manifest. * @param adaptationSetIndex The index of the adaptation set in the period. * @param trackSelection The track selection. * @param dataSource A {@link DataSource} suitable for loading the media data. * @param elapsedRealtimeOffsetMs If known, an estimate of the instantaneous difference between * server-side unix time and {@link SystemClock#elapsedRealtime()} in milliseconds, specified * as the server's unix time minus the local elapsed time. If unknown, set to 0. * @param maxSegmentsPerLoad The maximum number of segments to combine into a single request. * Note that segments will only be combined if their {@link Uri}s are the same and if their * data ranges are adjacent. * @param enableEventMessageTrack Whether the chunks generated by the source may output an event * message track. * @param enableEventMessageTrack Whether the chunks generated by the source may output a CEA-608 * track. */ public DefaultDashChunkSource(LoaderErrorThrower manifestLoaderErrorThrower, DashManifest manifest, int periodIndex, int adaptationSetIndex, TrackSelection trackSelection, DataSource dataSource, long elapsedRealtimeOffsetMs, int maxSegmentsPerLoad, boolean enableEventMessageTrack, boolean enableCea608Track) { this.manifestLoaderErrorThrower = manifestLoaderErrorThrower; this.manifest = manifest; this.adaptationSetIndex = adaptationSetIndex; this.trackSelection = trackSelection; this.dataSource = dataSource; this.periodIndex = periodIndex; this.elapsedRealtimeOffsetMs = elapsedRealtimeOffsetMs; this.maxSegmentsPerLoad = maxSegmentsPerLoad; long periodDurationUs = manifest.getPeriodDurationUs(periodIndex); AdaptationSet adaptationSet = getAdaptationSet(); List<Representation> representations = adaptationSet.representations; representationHolders = new RepresentationHolder[trackSelection.length()]; for (int i = 0; i < representationHolders.length; i++) { Representation representation = representations.get(trackSelection.getIndexInTrackGroup(i)); representationHolders[i] = new RepresentationHolder(periodDurationUs, representation, enableEventMessageTrack, enableCea608Track, adaptationSet.type); } }
/** * @param manifestLoaderErrorThrower Throws errors affecting loading of manifests. * @param manifest The initial manifest. * @param periodIndex The index of the period in the manifest. * @param adaptationSetIndex The index of the adaptation set in the period. * @param trackSelection The track selection. * @param dataSource A {@link DataSource} suitable for loading the media data. * @param elapsedRealtimeOffsetMs If known, an estimate of the instantaneous difference between * server-side unix time and {@link SystemClock#elapsedRealtime()} in milliseconds, specified * as the server's unix time minus the local elapsed time. If unknown, set to 0. */ public DefaultDashChunkSource(LoaderErrorThrower manifestLoaderErrorThrower, DashManifest manifest, int periodIndex, int adaptationSetIndex, TrackSelection trackSelection, DataSource dataSource, long elapsedRealtimeOffsetMs) { this.manifestLoaderErrorThrower = manifestLoaderErrorThrower; this.manifest = manifest; this.adaptationSetIndex = adaptationSetIndex; this.trackSelection = trackSelection; this.dataSource = dataSource; this.periodIndex = periodIndex; this.elapsedRealtimeOffsetMs = elapsedRealtimeOffsetMs; long periodDurationUs = manifest.getPeriodDurationUs(periodIndex); List<Representation> representations = getRepresentations(); representationHolders = new RepresentationHolder[trackSelection.length()]; for (int i = 0; i < representationHolders.length; i++) { Representation representation = representations.get(trackSelection.getIndexInTrackGroup(i)); representationHolders[i] = new RepresentationHolder(periodDurationUs, representation); } }
private Chunk newMediaChunk(RepresentationHolder representationHolder, DataSource dataSource, Format trackFormat, int trackSelectionReason, Object trackSelectionData, Format sampleFormat, int segmentNum) { Representation representation = representationHolder.representation; long startTimeUs = representationHolder.getSegmentStartTimeUs(segmentNum); long endTimeUs = representationHolder.getSegmentEndTimeUs(segmentNum); RangedUri segmentUri = representationHolder.getSegmentUrl(segmentNum); DataSpec dataSpec = new DataSpec(segmentUri.getUri(), segmentUri.start, segmentUri.length, representation.getCacheKey()); if (representationHolder.extractorWrapper == null) { return new SingleSampleMediaChunk(dataSource, dataSpec, trackFormat, trackSelectionReason, trackSelectionData, startTimeUs, endTimeUs, segmentNum, trackFormat); } else { long sampleOffsetUs = -representation.presentationTimeOffsetUs; return new ContainerMediaChunk(dataSource, dataSpec, trackFormat, trackSelectionReason, trackSelectionData, startTimeUs, endTimeUs, segmentNum, sampleOffsetUs, representationHolder.extractorWrapper, sampleFormat); } }
/** * @param manifestLoaderErrorThrower Throws errors affecting loading of manifests. * @param manifest The initial manifest. * @param periodIndex The index of the period in the manifest. * @param adaptationSetIndices The indices of the adaptation sets in the period. * @param trackSelection The track selection. * @param trackType The type of the tracks in the selection. * @param dataSource A {@link DataSource} suitable for loading the media data. * @param elapsedRealtimeOffsetMs If known, an estimate of the instantaneous difference between * server-side unix time and {@link SystemClock#elapsedRealtime()} in milliseconds, specified * as the server's unix time minus the local elapsed time. If unknown, set to 0. * @param maxSegmentsPerLoad The maximum number of segments to combine into a single request. * Note that segments will only be combined if their {@link Uri}s are the same and if their * data ranges are adjacent. * @param enableEventMessageTrack Whether the chunks generated by the source may output an event * message track. * @param enableCea608Track Whether the chunks generated by the source may output a CEA-608 track. */ public DefaultDashChunkSource(LoaderErrorThrower manifestLoaderErrorThrower, DashManifest manifest, int periodIndex, int[] adaptationSetIndices, TrackSelection trackSelection, int trackType, DataSource dataSource, long elapsedRealtimeOffsetMs, int maxSegmentsPerLoad, boolean enableEventMessageTrack, boolean enableCea608Track) { this.manifestLoaderErrorThrower = manifestLoaderErrorThrower; this.manifest = manifest; this.adaptationSetIndices = adaptationSetIndices; this.trackSelection = trackSelection; this.trackType = trackType; this.dataSource = dataSource; this.periodIndex = periodIndex; this.elapsedRealtimeOffsetMs = elapsedRealtimeOffsetMs; this.maxSegmentsPerLoad = maxSegmentsPerLoad; long periodDurationUs = manifest.getPeriodDurationUs(periodIndex); liveEdgeTimeUs = C.TIME_UNSET; List<Representation> representations = getRepresentations(); representationHolders = new RepresentationHolder[trackSelection.length()]; for (int i = 0; i < representationHolders.length; i++) { Representation representation = representations.get(trackSelection.getIndexInTrackGroup(i)); representationHolders[i] = new RepresentationHolder(periodDurationUs, trackType, representation, enableEventMessageTrack, enableCea608Track); } }
/** * Loads {@link DrmInitData} for a given period in a DASH manifest. * * @param dataSource The {@link HttpDataSource} from which data should be loaded. * @param period The {@link Period}. * @return The loaded {@link DrmInitData}, or null if none is defined. * @throws IOException Thrown when there is an error while loading. * @throws InterruptedException Thrown if the thread was interrupted. */ public static DrmInitData loadDrmInitData(DataSource dataSource, Period period) throws IOException, InterruptedException { int primaryTrackType = C.TRACK_TYPE_VIDEO; Representation representation = getFirstRepresentation(period, primaryTrackType); if (representation == null) { primaryTrackType = C.TRACK_TYPE_AUDIO; representation = getFirstRepresentation(period, primaryTrackType); if (representation == null) { return null; } } DrmInitData drmInitData = representation.format.drmInitData; if (drmInitData != null) { // Prefer drmInitData obtained from the manifest over drmInitData obtained from the stream, // as per DASH IF Interoperability Recommendations V3.0, 7.5.3. return drmInitData; } Format sampleFormat = DashUtil.loadSampleFormat(dataSource, primaryTrackType, representation); return sampleFormat == null ? null : sampleFormat.drmInitData; }
/** * Downloads an offline license. * * @param dataSource The {@link HttpDataSource} to be used for download. * @param dashManifest The {@link DashManifest} of the DASH content. * @return The downloaded offline license key set id. * @throws IOException If an error occurs reading data from the stream. * @throws InterruptedException If the thread has been interrupted. * @throws DrmSessionException Thrown when there is an error during DRM session. */ public byte[] download(HttpDataSource dataSource, DashManifest dashManifest) throws IOException, InterruptedException, DrmSessionException { // Get DrmInitData // Prefer drmInitData obtained from the manifest over drmInitData obtained from the stream, // as per DASH IF Interoperability Recommendations V3.0, 7.5.3. if (dashManifest.getPeriodCount() < 1) { return null; } Period period = dashManifest.getPeriod(0); int adaptationSetIndex = period.getAdaptationSetIndex(C.TRACK_TYPE_VIDEO); if (adaptationSetIndex == C.INDEX_UNSET) { adaptationSetIndex = period.getAdaptationSetIndex(C.TRACK_TYPE_AUDIO); if (adaptationSetIndex == C.INDEX_UNSET) { return null; } } AdaptationSet adaptationSet = period.adaptationSets.get(adaptationSetIndex); if (adaptationSet.representations.isEmpty()) { return null; } Representation representation = adaptationSet.representations.get(0); DrmInitData drmInitData = representation.format.drmInitData; if (drmInitData == null) { Format sampleFormat = DashUtil.loadSampleFormat(dataSource, representation); if (sampleFormat != null) { drmInitData = sampleFormat.drmInitData; } if (drmInitData == null) { return null; } } blockingKeyRequest(DefaultDrmSessionManager.MODE_DOWNLOAD, null, drmInitData); return drmSessionManager.getOfflineLicenseKeySetId(); }
@Override public void updateManifest(DashManifest newManifest, int newPeriodIndex) { try { manifest = newManifest; periodIndex = newPeriodIndex; long periodDurationUs = manifest.getPeriodDurationUs(periodIndex); List<Representation> representations = getAdaptationSet().representations; for (int i = 0; i < representationHolders.length; i++) { Representation representation = representations.get(trackSelection.getIndexInTrackGroup(i)); representationHolders[i].updateRepresentation(periodDurationUs, representation); } } catch (BehindLiveWindowException e) { fatalError = e; } }
/** * Loads initialization data for the {@code representation} and optionally index data then * returns a {@link ChunkExtractorWrapper} which contains the output. * * @param dataSource The source from which the data should be loaded. * @param representation The representation which initialization chunk belongs to. * @param loadIndex Whether to load index data too. * @return A {@link ChunkExtractorWrapper} for the {@code representation}, or null if no * initialization or (if requested) index data exists. * @throws IOException Thrown when there is an error while loading. * @throws InterruptedException Thrown if the thread was interrupted. */ private static ChunkExtractorWrapper loadInitializationData(DataSource dataSource, Representation representation, boolean loadIndex) throws IOException, InterruptedException { RangedUri initializationUri = representation.getInitializationUri(); if (initializationUri == null) { return null; } ChunkExtractorWrapper extractorWrapper = newWrappedExtractor(representation.format); RangedUri requestUri; if (loadIndex) { RangedUri indexUri = representation.getIndexUri(); if (indexUri == null) { return null; } // It's common for initialization and index data to be stored adjacently. Attempt to merge // the two requests together to request both at once. requestUri = initializationUri.attemptMerge(indexUri, representation.baseUrl); if (requestUri == null) { loadInitializationData(dataSource, representation, extractorWrapper, initializationUri); requestUri = indexUri; } } else { requestUri = initializationUri; } loadInitializationData(dataSource, representation, extractorWrapper, requestUri); return extractorWrapper; }
private static void loadInitializationData(DataSource dataSource, Representation representation, ChunkExtractorWrapper extractorWrapper, RangedUri requestUri) throws IOException, InterruptedException { DataSpec dataSpec = new DataSpec(requestUri.resolveUri(representation.baseUrl), requestUri.start, requestUri.length, representation.getCacheKey()); InitializationChunk initializationChunk = new InitializationChunk(dataSource, dataSpec, representation.format, C.SELECTION_REASON_UNKNOWN, null /* trackSelectionData */, extractorWrapper); initializationChunk.load(); }
private static boolean hasEventMessageTrack(AdaptationSet adaptationSet) { List<Representation> representations = adaptationSet.representations; for (int i = 0; i < representations.size(); i++) { Representation representation = representations.get(i); if (!representation.inbandEventStreams.isEmpty()) { return true; } } return false; }
@Override public void updateManifest(DashManifest newManifest, int newPeriodIndex) { try { manifest = newManifest; periodIndex = newPeriodIndex; long periodDurationUs = manifest.getPeriodDurationUs(periodIndex); List<Representation> representations = getRepresentations(); for (int i = 0; i < representationHolders.length; i++) { Representation representation = representations.get(trackSelection.getIndexInTrackGroup(i)); representationHolders[i].updateRepresentation(periodDurationUs, representation); } } catch (BehindLiveWindowException e) { fatalError = e; } }
public void updateRepresentation(long newPeriodDurationUs, Representation newRepresentation) throws BehindLiveWindowException{ DashSegmentIndex oldIndex = representation.getIndex(); DashSegmentIndex newIndex = newRepresentation.getIndex(); periodDurationUs = newPeriodDurationUs; representation = newRepresentation; if (oldIndex == null) { // Segment numbers cannot shift if the index isn't defined by the manifest. return; } segmentIndex = newIndex; if (!oldIndex.isExplicit()) { // Segment numbers cannot shift if the index isn't explicit. return; } int oldIndexLastSegmentNum = oldIndex.getLastSegmentNum(periodDurationUs); long oldIndexEndTimeUs = oldIndex.getTimeUs(oldIndexLastSegmentNum) + oldIndex.getDurationUs(oldIndexLastSegmentNum, periodDurationUs); int newIndexFirstSegmentNum = newIndex.getFirstSegmentNum(); long newIndexStartTimeUs = newIndex.getTimeUs(newIndexFirstSegmentNum); if (oldIndexEndTimeUs == newIndexStartTimeUs) { // The new index continues where the old one ended, with no overlap. segmentNumShift += oldIndex.getLastSegmentNum(periodDurationUs) + 1 - newIndexFirstSegmentNum; } else if (oldIndexEndTimeUs < newIndexStartTimeUs) { // There's a gap between the old index and the new one which means we've slipped behind the // live window and can't proceed. throw new BehindLiveWindowException(); } else { // The new index overlaps with the old one. segmentNumShift += oldIndex.getSegmentNum(newIndexStartTimeUs, periodDurationUs) - newIndexFirstSegmentNum; } }
private static TrackGroupArray buildTrackGroups(Period period) { TrackGroup[] trackGroupArray = new TrackGroup[period.adaptationSets.size()]; for (int i = 0; i < period.adaptationSets.size(); i++) { AdaptationSet adaptationSet = period.adaptationSets.get(i); List<Representation> representations = adaptationSet.representations; Format[] formats = new Format[representations.size()]; for (int j = 0; j < formats.length; j++) { formats[j] = representations.get(j).format; } trackGroupArray[i] = new TrackGroup(formats); } return new TrackGroupArray(trackGroupArray); }
private ArrayList<Representation> getRepresentations() { List<AdaptationSet> manifestAdapationSets = manifest.getPeriod(periodIndex).adaptationSets; ArrayList<Representation> representations = new ArrayList<>(); for (int adaptationSetIndex : adaptationSetIndices) { representations.addAll(manifestAdapationSets.get(adaptationSetIndex).representations); } return representations; }
/** * Loads initialization data for the {@code representation} and optionally index data then * returns a {@link ChunkExtractorWrapper} which contains the output. * * @param dataSource The source from which the data should be loaded. * @param trackType The type of the representation. Typically one of the * {@link com.google.android.exoplayer2.C} {@code TRACK_TYPE_*} constants. * @param representation The representation which initialization chunk belongs to. * @param loadIndex Whether to load index data too. * @return A {@link ChunkExtractorWrapper} for the {@code representation}, or null if no * initialization or (if requested) index data exists. * @throws IOException Thrown when there is an error while loading. * @throws InterruptedException Thrown if the thread was interrupted. */ private static ChunkExtractorWrapper loadInitializationData(DataSource dataSource, int trackType, Representation representation, boolean loadIndex) throws IOException, InterruptedException { RangedUri initializationUri = representation.getInitializationUri(); if (initializationUri == null) { return null; } ChunkExtractorWrapper extractorWrapper = newWrappedExtractor(trackType, representation.format); RangedUri requestUri; if (loadIndex) { RangedUri indexUri = representation.getIndexUri(); if (indexUri == null) { return null; } // It's common for initialization and index data to be stored adjacently. Attempt to merge // the two requests together to request both at once. requestUri = initializationUri.attemptMerge(indexUri, representation.baseUrl); if (requestUri == null) { loadInitializationData(dataSource, representation, extractorWrapper, initializationUri); requestUri = indexUri; } } else { requestUri = initializationUri; } loadInitializationData(dataSource, representation, extractorWrapper, requestUri); return extractorWrapper; }
private static Representation getFirstRepresentation(Period period, int type) { int index = period.getAdaptationSetIndex(type); if (index == C.INDEX_UNSET) { return null; } List<Representation> representations = period.adaptationSets.get(index).representations; return representations.isEmpty() ? null : representations.get(0); }
/** * Returns DashSegmentIndex for given representation. */ private DashSegmentIndex getSegmentIndex(DataSource dataSource, DashManifest manifest, RepresentationKey key) throws IOException, InterruptedException { AdaptationSet adaptationSet = manifest.getPeriod(key.periodIndex).adaptationSets.get( key.adaptationSetIndex); Representation representation = adaptationSet.representations.get(key.representationIndex); DashSegmentIndex index = representation.getIndex(); if (index != null) { return index; } ChunkIndex seekMap = DashUtil.loadChunkIndex(dataSource, adaptationSet.type, representation); return seekMap == null ? null : new DashWrappingSegmentIndex(seekMap); }
private static boolean hasEventMessageTrack(List<AdaptationSet> adaptationSets, int[] adaptationSetIndices) { for (int i : adaptationSetIndices) { List<Representation> representations = adaptationSets.get(i).representations; for (int j = 0; j < representations.size(); j++) { Representation representation = representations.get(j); if (!representation.inbandEventStreams.isEmpty()) { return true; } } } return false; }
private static Representation newRepresentations(DrmInitData drmInitData) { Format format = Format.createVideoContainerFormat("id", MimeTypes.VIDEO_MP4, MimeTypes.VIDEO_H264, "", Format.NO_VALUE, 1024, 768, Format.NO_VALUE, null, 0); if (drmInitData != null) { format = format.copyWithDrmInitData(drmInitData); } return Representation.newInstance("", 0, format, "", new SingleSegmentBase()); }
public void updateRepresentation(long newPeriodDurationUs, Representation newRepresentation) throws BehindLiveWindowException{ DashSegmentIndex oldIndex = representation.getIndex(); DashSegmentIndex newIndex = newRepresentation.getIndex(); periodDurationUs = newPeriodDurationUs; representation = newRepresentation; if (oldIndex == null) { // Segment numbers cannot shift if the index isn't defined by the manifest. return; } segmentIndex = newIndex; if (!oldIndex.isExplicit()) { // Segment numbers cannot shift if the index isn't explicit. return; } int oldIndexSegmentCount = oldIndex.getSegmentCount(periodDurationUs); if (oldIndexSegmentCount == 0) { // Segment numbers cannot shift if the old index was empty. return; } int oldIndexLastSegmentNum = oldIndex.getFirstSegmentNum() + oldIndexSegmentCount - 1; long oldIndexEndTimeUs = oldIndex.getTimeUs(oldIndexLastSegmentNum) + oldIndex.getDurationUs(oldIndexLastSegmentNum, periodDurationUs); int newIndexFirstSegmentNum = newIndex.getFirstSegmentNum(); long newIndexStartTimeUs = newIndex.getTimeUs(newIndexFirstSegmentNum); if (oldIndexEndTimeUs == newIndexStartTimeUs) { // The new index continues where the old one ended, with no overlap. segmentNumShift += oldIndexLastSegmentNum + 1 - newIndexFirstSegmentNum; } else if (oldIndexEndTimeUs < newIndexStartTimeUs) { // There's a gap between the old index and the new one which means we've slipped behind the // live window and can't proceed. throw new BehindLiveWindowException(); } else { // The new index overlaps with the old one. segmentNumShift += oldIndex.getSegmentNum(newIndexStartTimeUs, periodDurationUs) - newIndexFirstSegmentNum; } }
private List<Representation> getRepresentations() { return manifest.getPeriod(periodIndex).adaptationSets.get(adaptationSetIndex).representations; }
void updateRepresentation(long newPeriodDurationUs, Representation newRepresentation) throws BehindLiveWindowException { DashSegmentIndex oldIndex = representation.getIndex(); DashSegmentIndex newIndex = newRepresentation.getIndex(); periodDurationUs = newPeriodDurationUs; representation = newRepresentation; if (oldIndex == null) { // Segment numbers cannot shift if the index isn't defined by the manifest. return; } segmentIndex = newIndex; if (!oldIndex.isExplicit()) { // Segment numbers cannot shift if the index isn't explicit. return; } int oldIndexSegmentCount = oldIndex.getSegmentCount(periodDurationUs); if (oldIndexSegmentCount == 0) { // Segment numbers cannot shift if the old index was empty. return; } int oldIndexLastSegmentNum = oldIndex.getFirstSegmentNum() + oldIndexSegmentCount - 1; long oldIndexEndTimeUs = oldIndex.getTimeUs(oldIndexLastSegmentNum) + oldIndex.getDurationUs(oldIndexLastSegmentNum, periodDurationUs); int newIndexFirstSegmentNum = newIndex.getFirstSegmentNum(); long newIndexStartTimeUs = newIndex.getTimeUs(newIndexFirstSegmentNum); if (oldIndexEndTimeUs == newIndexStartTimeUs) { // The new index continues where the old one ended, with no overlap. segmentNumShift += oldIndexLastSegmentNum + 1 - newIndexFirstSegmentNum; } else if (oldIndexEndTimeUs < newIndexStartTimeUs) { // There's a gap between the old index and the new one which means we've slipped behind the // live window and can't proceed. throw new BehindLiveWindowException(); } else { // The new index overlaps with the old one. segmentNumShift += oldIndex.getSegmentNum(newIndexStartTimeUs, periodDurationUs) - newIndexFirstSegmentNum; } }
@Override protected List<Segment> getSegments(DataSource dataSource, DashManifest manifest, RepresentationKey[] keys, boolean allowIndexLoadErrors) throws InterruptedException, IOException { ArrayList<Segment> segments = new ArrayList<>(); for (RepresentationKey key : keys) { DashSegmentIndex index; try { index = getSegmentIndex(dataSource, manifest, key); if (index == null) { // Loading succeeded but there was no index. This is always a failure. throw new DownloadException("No index for representation: " + key); } } catch (IOException e) { if (allowIndexLoadErrors) { // Loading failed, but load errors are allowed. Advance to the next key. continue; } else { throw e; } } int segmentCount = index.getSegmentCount(C.TIME_UNSET); if (segmentCount == DashSegmentIndex.INDEX_UNBOUNDED) { throw new DownloadException("Unbounded index for representation: " + key); } Period period = manifest.getPeriod(key.periodIndex); Representation representation = period.adaptationSets.get(key.adaptationSetIndex) .representations.get(key.representationIndex); long startUs = C.msToUs(period.startMs); String baseUrl = representation.baseUrl; RangedUri initializationUri = representation.getInitializationUri(); if (initializationUri != null) { addSegment(segments, startUs, baseUrl, initializationUri); } RangedUri indexUri = representation.getIndexUri(); if (indexUri != null) { addSegment(segments, startUs, baseUrl, indexUri); } int firstSegmentNum = index.getFirstSegmentNum(); int lastSegmentNum = firstSegmentNum + segmentCount - 1; for (int j = firstSegmentNum; j <= lastSegmentNum; j++) { addSegment(segments, startUs + index.getTimeUs(j), baseUrl, index.getSegmentUrl(j)); } } return segments; }
private static AdaptationSet newAdaptationSets(Representation... representations) { return new AdaptationSet(0, C.TRACK_TYPE_VIDEO, Arrays.asList(representations), null, null); }
/** * Loads initialization data for the {@code representation} and returns the sample {@link * Format}. * * @param dataSource The source from which the data should be loaded. * @param representation The representation which initialization chunk belongs to. * @return the sample {@link Format} of the given representation. * @throws IOException Thrown when there is an error while loading. * @throws InterruptedException Thrown if the thread was interrupted. */ public static Format loadSampleFormat(DataSource dataSource, Representation representation) throws IOException, InterruptedException { ChunkExtractorWrapper extractorWrapper = loadInitializationData(dataSource, representation, false); return extractorWrapper == null ? null : extractorWrapper.getSampleFormats()[0]; }
/** * Loads initialization and index data for the {@code representation} and returns the {@link * ChunkIndex}. * * @param dataSource The source from which the data should be loaded. * @param representation The representation which initialization chunk belongs to. * @return {@link ChunkIndex} of the given representation. * @throws IOException Thrown when there is an error while loading. * @throws InterruptedException Thrown if the thread was interrupted. */ public static ChunkIndex loadChunkIndex(DataSource dataSource, Representation representation) throws IOException, InterruptedException { ChunkExtractorWrapper extractorWrapper = loadInitializationData(dataSource, representation, true); return extractorWrapper == null ? null : (ChunkIndex) extractorWrapper.getSeekMap(); }
/** * Loads initialization data for the {@code representation} and returns the sample {@link Format}. * * @param dataSource The source from which the data should be loaded. * @param trackType The type of the representation. Typically one of the * {@link com.google.android.exoplayer2.C} {@code TRACK_TYPE_*} constants. * @param representation The representation which initialization chunk belongs to. * @return the sample {@link Format} of the given representation. * @throws IOException Thrown when there is an error while loading. * @throws InterruptedException Thrown if the thread was interrupted. */ public static Format loadSampleFormat(DataSource dataSource, int trackType, Representation representation) throws IOException, InterruptedException { ChunkExtractorWrapper extractorWrapper = loadInitializationData(dataSource, trackType, representation, false); return extractorWrapper == null ? null : extractorWrapper.getSampleFormats()[0]; }
/** * Loads initialization and index data for the {@code representation} and returns the {@link * ChunkIndex}. * * @param dataSource The source from which the data should be loaded. * @param trackType The type of the representation. Typically one of the * {@link com.google.android.exoplayer2.C} {@code TRACK_TYPE_*} constants. * @param representation The representation which initialization chunk belongs to. * @return The {@link ChunkIndex} of the given representation, or null if no initialization or * index data exists. * @throws IOException Thrown when there is an error while loading. * @throws InterruptedException Thrown if the thread was interrupted. */ public static ChunkIndex loadChunkIndex(DataSource dataSource, int trackType, Representation representation) throws IOException, InterruptedException { ChunkExtractorWrapper extractorWrapper = loadInitializationData(dataSource, trackType, representation, true); return extractorWrapper == null ? null : (ChunkIndex) extractorWrapper.getSeekMap(); }