public static PeriodSeekInfo createPeriodSeekInfo( com.google.android.exoplayer2.source.dash.manifest.Period period, long durationUs) { int adaptationSetCount = period.adaptationSets.size(); long availableStartTimeUs = 0; long availableEndTimeUs = Long.MAX_VALUE; boolean isIndexExplicit = false; for (int i = 0; i < adaptationSetCount; i++) { DashSegmentIndex index = period.adaptationSets.get(i).representations.get(0).getIndex(); if (index == null) { return new PeriodSeekInfo(true, 0, durationUs); } int firstSegmentNum = index.getFirstSegmentNum(); int lastSegmentNum = index.getLastSegmentNum(durationUs); isIndexExplicit |= index.isExplicit(); long adaptationSetAvailableStartTimeUs = index.getTimeUs(firstSegmentNum); availableStartTimeUs = Math.max(availableStartTimeUs, adaptationSetAvailableStartTimeUs); if (lastSegmentNum != DashSegmentIndex.INDEX_UNBOUNDED) { long adaptationSetAvailableEndTimeUs = index.getTimeUs(lastSegmentNum) + index.getDurationUs(lastSegmentNum, durationUs); availableEndTimeUs = Math.min(availableEndTimeUs, adaptationSetAvailableEndTimeUs); } else { // The available end time is unmodified, because this index is unbounded. } } return new PeriodSeekInfo(isIndexExplicit, availableStartTimeUs, availableEndTimeUs); }
/** * 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 Period getPeriod(int periodIndex, Period period, boolean setIdentifiers) { Assertions.checkIndex(periodIndex, 0, manifest.getPeriodCount()); Object id = setIdentifiers ? manifest.getPeriod(periodIndex).id : null; Object uid = setIdentifiers ? firstPeriodId + Assertions.checkIndex(periodIndex, 0, manifest.getPeriodCount()) : null; return period.set(id, uid, 0, manifest.getPeriodDurationUs(periodIndex), C.msToUs(manifest.getPeriod(periodIndex).startMs - manifest.getPeriod(0).startMs) - offsetInFirstPeriodUs); }
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 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); }
@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; }
public void testLoadDrmInitDataFromManifest() throws Exception { Period period = newPeriod(newAdaptationSets(newRepresentations(newDrmInitData()))); DrmInitData drmInitData = DashUtil.loadDrmInitData(DummyDataSource.INSTANCE, period); assertEquals(newDrmInitData(), drmInitData); }
public void testLoadDrmInitDataMissing() throws Exception { Period period = newPeriod(newAdaptationSets(newRepresentations(null /* no init data */))); DrmInitData drmInitData = DashUtil.loadDrmInitData(DummyDataSource.INSTANCE, period); assertNull(drmInitData); }
public void testLoadDrmInitDataNoRepresentations() throws Exception { Period period = newPeriod(newAdaptationSets(/* no representation */)); DrmInitData drmInitData = DashUtil.loadDrmInitData(DummyDataSource.INSTANCE, period); assertNull(drmInitData); }
public void testLoadDrmInitDataNoAdaptationSets() throws Exception { Period period = newPeriod(/* no adaptation set */); DrmInitData drmInitData = DashUtil.loadDrmInitData(DummyDataSource.INSTANCE, period); assertNull(drmInitData); }
private static Period newPeriod(AdaptationSet... adaptationSets) { return new Period("", 0, Arrays.asList(adaptationSets)); }