@SuppressWarnings("NonAtomicVolatileUpdate") @Override public void load() throws IOException, InterruptedException { DataSpec loadDataSpec = Util.getRemainderDataSpec(dataSpec, bytesLoaded); try { // Create and open the input. long length = dataSource.open(loadDataSpec); if (length != C.LENGTH_UNSET) { length += bytesLoaded; } ExtractorInput extractorInput = new DefaultExtractorInput(dataSource, bytesLoaded, length); DefaultTrackOutput trackOutput = getTrackOutput(); trackOutput.formatWithOffset(sampleFormat, 0); // Load the sample data. int result = 0; while (result != C.RESULT_END_OF_INPUT) { bytesLoaded += result; result = trackOutput.sampleData(extractorInput, Integer.MAX_VALUE, true); } int sampleSize = bytesLoaded; trackOutput.sampleMetadata(startTimeUs, C.BUFFER_FLAG_KEY_FRAME, sampleSize, 0, null); } finally { dataSource.close(); } loadCompleted = true; }
/** * @param trackType The type of the track. One of the {@link C} {@code TRACK_TYPE_*} constants. * @param chunkSource A {@link ChunkSource} from which chunks to load are obtained. * @param callback An {@link Callback} for the stream. * @param allocator An {@link Allocator} from which allocations can be obtained. * @param positionUs The position from which to start loading media. * @param minLoadableRetryCount The minimum number of times that the source should retry a load * before propagating an error. * @param eventDispatcher A dispatcher to notify of events. */ public ChunkSampleStream(int trackType, T chunkSource, SequenceableLoader.Callback<ChunkSampleStream<T>> callback, Allocator allocator, long positionUs, int minLoadableRetryCount, EventDispatcher eventDispatcher) { this.trackType = trackType; this.chunkSource = chunkSource; this.callback = callback; this.eventDispatcher = eventDispatcher; this.minLoadableRetryCount = minLoadableRetryCount; loader = new Loader("Loader:ChunkSampleStream"); nextChunkHolder = new ChunkHolder(); mediaChunks = new LinkedList<>(); readOnlyMediaChunks = Collections.unmodifiableList(mediaChunks); sampleQueue = new DefaultTrackOutput(allocator); lastSeekPositionUs = positionUs; pendingResetPositionUs = positionUs; }
void skipData(int group, long positionUs) { DefaultTrackOutput sampleQueue = sampleQueues.valueAt(group); if (loadingFinished && positionUs > sampleQueue.getLargestQueuedTimestampUs()) { sampleQueue.skipAll(); } else { sampleQueue.skipToKeyframeBefore(positionUs, true); } }
@Override public DefaultTrackOutput track(int id, int type) { if (sampleQueues.indexOfKey(id) >= 0) { return sampleQueues.get(id); } DefaultTrackOutput trackOutput = new DefaultTrackOutput(allocator); trackOutput.setUpstreamFormatChangeListener(this); trackOutput.sourceId(upstreamChunkUid); sampleQueues.put(id, trackOutput); return trackOutput; }
void skipData(int track, long positionUs) { DefaultTrackOutput sampleQueue = sampleQueues.valueAt(track); if (loadingFinished && positionUs > sampleQueue.getLargestQueuedTimestampUs()) { sampleQueue.skipAll(); } else { sampleQueue.skipToKeyframeBefore(positionUs, true); } }
/** * Sets an offset that will be added to the timestamps (and sub-sample timestamps) of samples * subsequently written to the track outputs. */ public void setSampleOffsetUs(long sampleOffsetUs) { for (DefaultTrackOutput trackOutput : trackOutputs) { if (trackOutput != null) { trackOutput.setSampleOffsetUs(sampleOffsetUs); } } }
/** * @param primaryTrackType The type of the primary track. One of the {@link C} * {@code TRACK_TYPE_*} constants. * @param embeddedTrackTypes The types of any embedded tracks, or null. * @param chunkSource A {@link ChunkSource} from which chunks to load are obtained. * @param callback An {@link Callback} for the stream. * @param allocator An {@link Allocator} from which allocations can be obtained. * @param positionUs The position from which to start loading media. * @param minLoadableRetryCount The minimum number of times that the source should retry a load * before propagating an error. * @param eventDispatcher A dispatcher to notify of events. */ public ChunkSampleStream(int primaryTrackType, int[] embeddedTrackTypes, T chunkSource, Callback<ChunkSampleStream<T>> callback, Allocator allocator, long positionUs, int minLoadableRetryCount, EventDispatcher eventDispatcher) { this.primaryTrackType = primaryTrackType; this.embeddedTrackTypes = embeddedTrackTypes; this.chunkSource = chunkSource; this.callback = callback; this.eventDispatcher = eventDispatcher; this.minLoadableRetryCount = minLoadableRetryCount; loader = new Loader("Loader:ChunkSampleStream"); nextChunkHolder = new ChunkHolder(); mediaChunks = new LinkedList<>(); readOnlyMediaChunks = Collections.unmodifiableList(mediaChunks); int embeddedTrackCount = embeddedTrackTypes == null ? 0 : embeddedTrackTypes.length; embeddedSampleQueues = new DefaultTrackOutput[embeddedTrackCount]; embeddedTracksSelected = new boolean[embeddedTrackCount]; int[] trackTypes = new int[1 + embeddedTrackCount]; DefaultTrackOutput[] sampleQueues = new DefaultTrackOutput[1 + embeddedTrackCount]; primarySampleQueue = new DefaultTrackOutput(allocator); trackTypes[0] = primaryTrackType; sampleQueues[0] = primarySampleQueue; for (int i = 0; i < embeddedTrackCount; i++) { DefaultTrackOutput trackOutput = new DefaultTrackOutput(allocator); embeddedSampleQueues[i] = trackOutput; sampleQueues[i + 1] = trackOutput; trackTypes[i + 1] = embeddedTrackTypes[i]; } mediaChunkOutput = new BaseMediaChunkOutput(trackTypes, sampleQueues); pendingResetPositionUs = positionUs; lastSeekPositionUs = positionUs; }
/** * Releases the stream. * <p> * This method should be called when the stream is no longer required. */ public void release() { primarySampleQueue.disable(); for (DefaultTrackOutput embeddedSampleQueue : embeddedSampleQueues) { embeddedSampleQueue.disable(); } loader.release(); }
@Override public void onLoadCanceled(Chunk loadable, long elapsedRealtimeMs, long loadDurationMs, boolean released) { eventDispatcher.loadCanceled(loadable.dataSpec, loadable.type, primaryTrackType, loadable.trackFormat, loadable.trackSelectionReason, loadable.trackSelectionData, loadable.startTimeUs, loadable.endTimeUs, elapsedRealtimeMs, loadDurationMs, loadable.bytesLoaded()); if (!released) { primarySampleQueue.reset(true); for (DefaultTrackOutput embeddedSampleQueue : embeddedSampleQueues) { embeddedSampleQueue.reset(true); } callback.onContinueLoadingRequested(this); } }
@Override public DefaultTrackOutput track(int id) { if (sampleQueues.indexOfKey(id) >= 0) { return sampleQueues.get(id); } DefaultTrackOutput trackOutput = new DefaultTrackOutput(allocator); trackOutput.setUpstreamFormatChangeListener(this); trackOutput.sourceId(upstreamChunkUid); sampleQueues.put(id, trackOutput); return trackOutput; }
@SuppressWarnings("NonAtomicVolatileUpdate") @Override public final void load() throws IOException, InterruptedException { DataSpec loadDataSpec = Util.getRemainderDataSpec(dataSpec, bytesLoaded); try { // Create and open the input. ExtractorInput input = new DefaultExtractorInput(dataSource, loadDataSpec.absoluteStreamPosition, dataSource.open(loadDataSpec)); if (bytesLoaded == 0) { // Set the target to ourselves. DefaultTrackOutput trackOutput = getTrackOutput(); trackOutput.formatWithOffset(sampleFormat, sampleOffsetUs); extractorWrapper.init(this, trackOutput); } // Load and decode the sample data. try { int result = Extractor.RESULT_CONTINUE; while (result == Extractor.RESULT_CONTINUE && !loadCanceled) { result = extractorWrapper.read(input); } } finally { bytesLoaded = (int) (input.getPosition() - dataSpec.absoluteStreamPosition); } } finally { dataSource.close(); } loadCompleted = true; }
/** * @param trackTypes The track types of the individual track outputs. * @param trackOutputs The individual track outputs. */ public BaseMediaChunkOutput(int[] trackTypes, DefaultTrackOutput[] trackOutputs) { this.trackTypes = trackTypes; this.trackOutputs = trackOutputs; }
public EmbeddedSampleStream(ChunkSampleStream<T> parent, DefaultTrackOutput sampleQueue, int index) { this.parent = parent; this.sampleQueue = sampleQueue; this.index = index; }
/** * Returns the track output most recently passed to {@link #init(DefaultTrackOutput)}. */ protected final DefaultTrackOutput getTrackOutput() { return trackOutput; }
/** * Initializes the chunk for loading, setting the {@link DefaultTrackOutput} that will receive * samples as they are loaded. * * @param trackOutput The output that will receive the loaded samples. */ public void init(DefaultTrackOutput trackOutput) { this.trackOutput = trackOutput; this.firstSampleIndex = trackOutput.getWriteIndex(); }