public void testSegmentIndexInitializationOnVod() { DashChunkSource chunkSource = new DashChunkSource(buildVodMpd(), DefaultDashTrackSelector.newVideoInstance(null, false, false), mock(DataSource.class), null); chunkSource.prepare(); chunkSource.enable(0); List<MediaChunk> queue = new ArrayList<>(); ChunkOperationHolder out = new ChunkOperationHolder(); // request first chunk; should get back initialization chunk chunkSource.getChunkOperation(queue, 0, out); assertNotNull(out.chunk); assertNotNull(((InitializationChunk) out.chunk).dataSpec); }
@Override public void disable(List<? extends MediaChunk> queue) { formatEvaluator.disable(); if (manifestFetcher != null) { manifestFetcher.disable(); } seekRange = null; }
@Override public void disable(List<? extends MediaChunk> queue) { formatEvaluator.disable(); if (manifestFetcher != null) { manifestFetcher.disable(); } }
private static MediaChunk newMediaChunk(Format formatInfo, Uri uri, String cacheKey, ChunkExtractorWrapper extractorWrapper, DrmInitData drmInitData, DataSource dataSource, int chunkIndex, boolean isLast, long chunkStartTimeUs, long chunkEndTimeUs, int trigger, MediaFormat mediaFormat) { long offset = 0; DataSpec dataSpec = new DataSpec(uri, offset, -1, cacheKey); // In SmoothStreaming each chunk contains sample timestamps relative to the start of the chunk. // To convert them the absolute timestamps, we need to set sampleOffsetUs to -chunkStartTimeUs. return new ContainerMediaChunk(dataSource, dataSpec, trigger, formatInfo, chunkStartTimeUs, chunkEndTimeUs, chunkIndex, isLast, chunkStartTimeUs, extractorWrapper, mediaFormat, drmInitData, true); }
@Override public void disable(List<? extends MediaChunk> queue) { if (enabledTrack.isAdaptive()) { adaptiveFormatEvaluator.disable(); } if (manifestFetcher != null) { manifestFetcher.disable(); } periodHolders.clear(); evaluation.format = null; availableRange = null; fatalError = null; enabledTrack = null; }
@Override public void disable(List<? extends MediaChunk> queue) { if (enabledTrack.isAdaptive()) { adaptiveFormatEvaluator.disable(); } if (manifestFetcher != null) { manifestFetcher.disable(); } evaluation.format = null; fatalError = null; }
private static MediaChunk newMediaChunk(Format formatInfo, Uri uri, String cacheKey, ChunkExtractorWrapper extractorWrapper, DrmInitData drmInitData, DataSource dataSource, int chunkIndex, long chunkStartTimeUs, long chunkEndTimeUs, int trigger, MediaFormat mediaFormat, int adaptiveMaxWidth, int adaptiveMaxHeight) { long offset = 0; DataSpec dataSpec = new DataSpec(uri, offset, -1, cacheKey); // In SmoothStreaming each chunk contains sample timestamps relative to the start of the chunk. // To convert them the absolute timestamps, we need to set sampleOffsetUs to -chunkStartTimeUs. return new ContainerMediaChunk(dataSource, dataSpec, trigger, formatInfo, chunkStartTimeUs, chunkEndTimeUs, chunkIndex, chunkStartTimeUs, extractorWrapper, mediaFormat, adaptiveMaxWidth, adaptiveMaxHeight, drmInitData, true, Chunk.NO_PARENT_ID); }
private static void checkLiveEdgeConsistency(MediaPresentationDescription mpd, long liveEdgeLatencyMs, long seekPositionMs, long availableRangeStartMs, long availableRangeEndMs, long chunkStartTimeMs, long chunkEndTimeMs) { DashChunkSource chunkSource = buildDashChunkSource(mpd, true, liveEdgeLatencyMs); List<MediaChunk> queue = new ArrayList<>(); ChunkOperationHolder out = new ChunkOperationHolder(); checkLiveEdgeConsistency(chunkSource, queue, out, seekPositionMs, availableRangeStartMs, availableRangeEndMs, chunkStartTimeMs, chunkEndTimeMs); }
private static void checkLiveEdgeConsistency(DashChunkSource chunkSource, List<MediaChunk> queue, ChunkOperationHolder out, long seekPositionMs, long availableRangeStartMs, long availableRangeEndMs, long chunkStartTimeMs, long chunkEndTimeMs) { chunkSource.getChunkOperation(queue, seekPositionMs * 1000, out); TimeRange availableRange = chunkSource.getAvailableRange(); checkAvailableRange(availableRange, availableRangeStartMs * 1000, availableRangeEndMs * 1000); if (chunkStartTimeMs < availableRangeEndMs) { assertNotNull(out.chunk); assertEquals(chunkStartTimeMs * 1000, ((MediaChunk) out.chunk).startTimeUs); assertEquals(chunkEndTimeMs * 1000, ((MediaChunk) out.chunk).endTimeUs); } else { assertNull(out.chunk); } }
@Override public void disable(List<? extends MediaChunk> queue) { evaluator.disable(); if (manifestFetcher != null) { manifestFetcher.disable(); } }
private static MediaChunk newMediaChunk(Format formatInfo, Uri uri, String cacheKey, Extractor extractor, Map<UUID, byte[]> psshInfo, DataSource dataSource, int chunkIndex, boolean isLast, long chunkStartTimeUs, long nextChunkStartTimeUs, int trigger) { int nextChunkIndex = isLast ? -1 : chunkIndex + 1; long nextStartTimeUs = isLast ? -1 : nextChunkStartTimeUs; long offset = 0; DataSpec dataSpec = new DataSpec(uri, offset, -1, cacheKey); // In SmoothStreaming each chunk contains sample timestamps relative to the start of the chunk. // To convert them the absolute timestamps, we need to set sampleOffsetUs to -chunkStartTimeUs. return new Mp4MediaChunk(dataSource, dataSpec, formatInfo, trigger, chunkStartTimeUs, nextStartTimeUs, nextChunkIndex, extractor, psshInfo, false, -chunkStartTimeUs); }
private static MediaChunk newMediaChunk(Format formatInfo, Uri uri, String cacheKey, Extractor extractor, Map<UUID, byte[]> psshInfo, DataSource dataSource, int chunkIndex, boolean isLast, long chunkStartTimeUs, long nextChunkStartTimeUs, int trigger) { int nextChunkIndex = isLast ? -1 : chunkIndex + 1; long nextStartTimeUs = isLast ? -1 : nextChunkStartTimeUs; long offset = 0; DataSpec dataSpec = new DataSpec(uri, offset, -1, cacheKey); // In SmoothStreaming each chunk contains sample timestamps relative to the start of the chunk. // To convert them the absolute timestamps, we need to set sampleOffsetUs to -chunkStartTimeUs. return new ContainerMediaChunk(dataSource, dataSpec, formatInfo, trigger, chunkStartTimeUs, nextStartTimeUs, nextChunkIndex, extractor, psshInfo, false, -chunkStartTimeUs); }
@Override public final void getChunkOperation(List<? extends MediaChunk> queue, long seekPositionUs, long playbackPositionUs, ChunkOperationHolder out) { evaluation.queueSize = queue.size(); formatEvaluator.evaluate(queue, playbackPositionUs, formats, evaluation); SmoothStreamingFormat selectedFormat = (SmoothStreamingFormat) evaluation.format; out.queueSize = evaluation.queueSize; if (selectedFormat == null) { out.chunk = null; return; } else if (out.queueSize == queue.size() && out.chunk != null && out.chunk.format.id.equals(evaluation.format.id)) { // We already have a chunk, and the evaluation hasn't changed either the format or the size // of the queue. Do nothing. return; } int nextChunkIndex; if (queue.isEmpty()) { nextChunkIndex = streamElement.getChunkIndex(seekPositionUs); } else { nextChunkIndex = queue.get(out.queueSize - 1).nextChunkIndex; } if (nextChunkIndex == -1) { out.chunk = null; return; } boolean isLastChunk = nextChunkIndex == streamElement.chunkCount - 1; String requestUrl = streamElement.buildRequestUrl(selectedFormat.trackIndex, nextChunkIndex); Uri uri = Uri.parse(baseUrl + '/' + requestUrl); Chunk mediaChunk = newMediaChunk(selectedFormat, uri, null, extractors.get(Integer.parseInt(selectedFormat.id)), dataSource, nextChunkIndex, isLastChunk, streamElement.getStartTimeUs(nextChunkIndex), isLastChunk ? -1 : streamElement.getStartTimeUs(nextChunkIndex + 1), 0); out.chunk = mediaChunk; }
private static MediaChunk newMediaChunk(Format formatInfo, Uri uri, String cacheKey, Extractor extractor, DataSource dataSource, int chunkIndex, boolean isLast, long chunkStartTimeUs, long nextChunkStartTimeUs, int trigger) { int nextChunkIndex = isLast ? -1 : chunkIndex + 1; long nextStartTimeUs = isLast ? -1 : nextChunkStartTimeUs; long offset = 0; DataSpec dataSpec = new DataSpec(uri, offset, -1, cacheKey); // In SmoothStreaming each chunk contains sample timestamps relative to the start of the chunk. // To convert them the absolute timestamps, we need to set sampleOffsetUs to -chunkStartTimeUs. return new Mp4MediaChunk(dataSource, dataSpec, formatInfo, trigger, chunkStartTimeUs, nextStartTimeUs, nextChunkIndex, extractor, false, -chunkStartTimeUs); }
private void checkLiveEdgeLatency(DashChunkSource chunkSource, List<MediaChunk> queue, ChunkOperationHolder out, long seekPositionMs, long seekRangeStartMs, long seekRangeEndMs, long chunkStartTimeMs, long chunkEndTimeMs) { chunkSource.getChunkOperation(queue, seekPositionMs * 1000, 0, out); TimeRange seekRange = chunkSource.getSeekRange(); assertNotNull(out.chunk); checkSeekRange(seekRange, seekRangeStartMs * 1000, seekRangeEndMs * 1000); assertEquals(chunkStartTimeMs * 1000, ((MediaChunk) out.chunk).startTimeUs); assertEquals(chunkEndTimeMs * 1000, ((MediaChunk) out.chunk).endTimeUs); }
private void checkLiveEdgeLatency(MediaPresentationDescription mpd, long periodStartMs, long liveEdgeLatencyMs, long seekPositionMs, long seekRangeStartMs, long seekRangeEndMs, long chunkStartTimeMs, long chunkEndTimeMs) { DashChunkSource chunkSource = setupDashChunkSource(mpd, periodStartMs, liveEdgeLatencyMs); List<MediaChunk> queue = new ArrayList<>(); ChunkOperationHolder out = new ChunkOperationHolder(); checkLiveEdgeLatency(chunkSource, queue, out, seekPositionMs, seekRangeStartMs, seekRangeEndMs, chunkStartTimeMs, chunkEndTimeMs); }
@Override public void disable(List<? extends MediaChunk> queue) { if (manifestFetcher != null) { manifestFetcher.disable(); } }
@Override public void disable(List<? extends MediaChunk> queue) { evaluator.disable(); }
@Override public final void getChunkOperation(List<? extends MediaChunk> queue, long seekPositionUs, long playbackPositionUs, ChunkOperationHolder out) { evaluation.queueSize = queue.size(); if (evaluation.format == null || !lastChunkWasInitialization) { evaluator.evaluate(queue, playbackPositionUs, formats, evaluation); } Format selectedFormat = evaluation.format; out.queueSize = evaluation.queueSize; if (selectedFormat == null) { out.chunk = null; return; } else if (out.queueSize == queue.size() && out.chunk != null && out.chunk.format.id.equals(selectedFormat.id)) { // We already have a chunk, and the evaluation hasn't changed either the format or the size // of the queue. Leave unchanged. return; } Representation selectedRepresentation = representations.get(selectedFormat.id); Extractor extractor = extractors.get(selectedRepresentation.format.id); RangedUri pendingInitializationUri = null; RangedUri pendingIndexUri = null; if (extractor.getFormat() == null) { pendingInitializationUri = selectedRepresentation.getInitializationUri(); } if (!segmentIndexes.containsKey(selectedRepresentation.format.id)) { pendingIndexUri = selectedRepresentation.getIndexUri(); } if (pendingInitializationUri != null || pendingIndexUri != null) { // We have initialization and/or index requests to make. Chunk initializationChunk = newInitializationChunk(pendingInitializationUri, pendingIndexUri, selectedRepresentation, extractor, dataSource, evaluation.trigger); lastChunkWasInitialization = true; out.chunk = initializationChunk; return; } int nextSegmentNum; DashSegmentIndex segmentIndex = segmentIndexes.get(selectedRepresentation.format.id); if (queue.isEmpty()) { nextSegmentNum = segmentIndex.getSegmentNum(seekPositionUs); } else { nextSegmentNum = queue.get(out.queueSize - 1).nextChunkIndex; } if (nextSegmentNum == -1) { out.chunk = null; return; } Chunk nextMediaChunk = newMediaChunk(selectedRepresentation, segmentIndex, extractor, dataSource, nextSegmentNum, evaluation.trigger); lastChunkWasInitialization = false; out.chunk = nextMediaChunk; }
@Override public void disable(List<? extends MediaChunk> queue) { // Do nothing. }