Search in sources :

Example 6 with DataSource

use of com.google.android.exoplayer2.upstream.DataSource in project ExoPlayer by google.

the class HlsMediaChunk method loadMedia.

private void loadMedia() throws IOException, InterruptedException {
    // If we previously fed part of this chunk to the extractor, we need to skip it this time. For
    // encrypted content we need to skip the data by reading it through the source, so as to ensure
    // correct decryption of the remainder of the chunk. For clear content, we can request the
    // remainder of the chunk directly.
    DataSpec loadDataSpec;
    boolean skipLoadedBytes;
    if (isEncrypted) {
        loadDataSpec = dataSpec;
        skipLoadedBytes = bytesLoaded != 0;
    } else {
        loadDataSpec = Util.getRemainderDataSpec(dataSpec, bytesLoaded);
        skipLoadedBytes = false;
    }
    if (!isMasterTimestampSource) {
        timestampAdjuster.waitUntilInitialized();
    } else if (timestampAdjuster.getFirstSampleTimestampUs() == TimestampAdjuster.DO_NOT_OFFSET) {
        // We're the master and we haven't set the desired first sample timestamp yet.
        timestampAdjuster.setFirstSampleTimestampUs(startTimeUs);
    }
    try {
        ExtractorInput input = new DefaultExtractorInput(dataSource, loadDataSpec.absoluteStreamPosition, dataSource.open(loadDataSpec));
        if (extractor == null) {
            // Media segment format is packed audio.
            long id3Timestamp = peekId3PrivTimestamp(input);
            extractor = buildPackedAudioExtractor(id3Timestamp != C.TIME_UNSET ? timestampAdjuster.adjustTsTimestamp(id3Timestamp) : startTimeUs);
        }
        if (skipLoadedBytes) {
            input.skipFully(bytesLoaded);
        }
        try {
            int result = Extractor.RESULT_CONTINUE;
            while (result == Extractor.RESULT_CONTINUE && !loadCanceled) {
                result = extractor.read(input, null);
            }
        } finally {
            bytesLoaded = (int) (input.getPosition() - dataSpec.absoluteStreamPosition);
        }
    } finally {
        Util.closeQuietly(dataSource);
    }
    loadCompleted = true;
}
Also used : ExtractorInput(com.google.android.exoplayer2.extractor.ExtractorInput) DefaultExtractorInput(com.google.android.exoplayer2.extractor.DefaultExtractorInput) DataSpec(com.google.android.exoplayer2.upstream.DataSpec) DefaultExtractorInput(com.google.android.exoplayer2.extractor.DefaultExtractorInput)

Example 7 with DataSource

use of com.google.android.exoplayer2.upstream.DataSource in project ExoPlayer by google.

the class DefaultDashChunkSource method newInitializationChunk.

private static Chunk newInitializationChunk(RepresentationHolder representationHolder, DataSource dataSource, Format trackFormat, int trackSelectionReason, Object trackSelectionData, RangedUri initializationUri, RangedUri indexUri) {
    RangedUri requestUri;
    String baseUrl = representationHolder.representation.baseUrl;
    if (initializationUri != 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, baseUrl);
        if (requestUri == null) {
            requestUri = initializationUri;
        }
    } else {
        requestUri = indexUri;
    }
    DataSpec dataSpec = new DataSpec(requestUri.resolveUri(baseUrl), requestUri.start, requestUri.length, representationHolder.representation.getCacheKey());
    return new InitializationChunk(dataSource, dataSpec, trackFormat, trackSelectionReason, trackSelectionData, representationHolder.extractorWrapper);
}
Also used : InitializationChunk(com.google.android.exoplayer2.source.chunk.InitializationChunk) RangedUri(com.google.android.exoplayer2.source.dash.manifest.RangedUri) DataSpec(com.google.android.exoplayer2.upstream.DataSpec)

Example 8 with DataSource

use of com.google.android.exoplayer2.upstream.DataSource in project ExoPlayer by google.

the class DefaultDashChunkSource method getNextChunk.

@Override
public final void getNextChunk(MediaChunk previous, long playbackPositionUs, ChunkHolder out) {
    if (fatalError != null) {
        return;
    }
    long bufferedDurationUs = previous != null ? (previous.endTimeUs - playbackPositionUs) : 0;
    trackSelection.updateSelectedTrack(bufferedDurationUs);
    RepresentationHolder representationHolder = representationHolders[trackSelection.getSelectedIndex()];
    Representation selectedRepresentation = representationHolder.representation;
    DashSegmentIndex segmentIndex = representationHolder.segmentIndex;
    RangedUri pendingInitializationUri = null;
    RangedUri pendingIndexUri = null;
    if (representationHolder.extractorWrapper.getSampleFormats() == null) {
        pendingInitializationUri = selectedRepresentation.getInitializationUri();
    }
    if (segmentIndex == null) {
        pendingIndexUri = selectedRepresentation.getIndexUri();
    }
    if (pendingInitializationUri != null || pendingIndexUri != null) {
        // We have initialization and/or index requests to make.
        out.chunk = newInitializationChunk(representationHolder, dataSource, trackSelection.getSelectedFormat(), trackSelection.getSelectionReason(), trackSelection.getSelectionData(), pendingInitializationUri, pendingIndexUri);
        return;
    }
    long nowUs = getNowUnixTimeUs();
    int availableSegmentCount = representationHolder.getSegmentCount();
    if (availableSegmentCount == 0) {
        // The index doesn't define any segments.
        out.endOfStream = !manifest.dynamic || (periodIndex < manifest.getPeriodCount() - 1);
        return;
    }
    int firstAvailableSegmentNum = representationHolder.getFirstSegmentNum();
    int lastAvailableSegmentNum;
    if (availableSegmentCount == DashSegmentIndex.INDEX_UNBOUNDED) {
        // The index is itself unbounded. We need to use the current time to calculate the range of
        // available segments.
        long liveEdgeTimeUs = nowUs - manifest.availabilityStartTime * 1000;
        long periodStartUs = manifest.getPeriod(periodIndex).startMs * 1000;
        long liveEdgeTimeInPeriodUs = liveEdgeTimeUs - periodStartUs;
        if (manifest.timeShiftBufferDepth != C.TIME_UNSET) {
            long bufferDepthUs = manifest.timeShiftBufferDepth * 1000;
            firstAvailableSegmentNum = Math.max(firstAvailableSegmentNum, representationHolder.getSegmentNum(liveEdgeTimeInPeriodUs - bufferDepthUs));
        }
        // getSegmentNum(liveEdgeTimestampUs) will not be completed yet, so subtract one to get the
        // index of the last completed segment.
        lastAvailableSegmentNum = representationHolder.getSegmentNum(liveEdgeTimeInPeriodUs) - 1;
    } else {
        lastAvailableSegmentNum = firstAvailableSegmentNum + availableSegmentCount - 1;
    }
    int segmentNum;
    if (previous == null) {
        segmentNum = Util.constrainValue(representationHolder.getSegmentNum(playbackPositionUs), firstAvailableSegmentNum, lastAvailableSegmentNum);
    } else {
        segmentNum = previous.getNextChunkIndex();
        if (segmentNum < firstAvailableSegmentNum) {
            // This is before the first chunk in the current manifest.
            fatalError = new BehindLiveWindowException();
            return;
        }
    }
    if (segmentNum > lastAvailableSegmentNum || (missingLastSegment && segmentNum >= lastAvailableSegmentNum)) {
        // This is beyond the last chunk in the current manifest.
        out.endOfStream = !manifest.dynamic || (periodIndex < manifest.getPeriodCount() - 1);
        return;
    }
    int maxSegmentCount = Math.min(maxSegmentsPerLoad, lastAvailableSegmentNum - segmentNum + 1);
    out.chunk = newMediaChunk(representationHolder, dataSource, trackSelection.getSelectedFormat(), trackSelection.getSelectionReason(), trackSelection.getSelectionData(), segmentNum, maxSegmentCount);
}
Also used : BehindLiveWindowException(com.google.android.exoplayer2.source.BehindLiveWindowException) RangedUri(com.google.android.exoplayer2.source.dash.manifest.RangedUri) Representation(com.google.android.exoplayer2.source.dash.manifest.Representation)

Example 9 with DataSource

use of com.google.android.exoplayer2.upstream.DataSource in project ExoPlayer by google.

the class DefaultDashChunkSource method newMediaChunk.

private static Chunk newMediaChunk(RepresentationHolder representationHolder, DataSource dataSource, Format trackFormat, int trackSelectionReason, Object trackSelectionData, int firstSegmentNum, int maxSegmentCount) {
    Representation representation = representationHolder.representation;
    long startTimeUs = representationHolder.getSegmentStartTimeUs(firstSegmentNum);
    RangedUri segmentUri = representationHolder.getSegmentUrl(firstSegmentNum);
    String baseUrl = representation.baseUrl;
    if (representationHolder.extractorWrapper == null) {
        long endTimeUs = representationHolder.getSegmentEndTimeUs(firstSegmentNum);
        DataSpec dataSpec = new DataSpec(segmentUri.resolveUri(baseUrl), segmentUri.start, segmentUri.length, representation.getCacheKey());
        return new SingleSampleMediaChunk(dataSource, dataSpec, trackFormat, trackSelectionReason, trackSelectionData, startTimeUs, endTimeUs, firstSegmentNum, representationHolder.trackType, trackFormat);
    } else {
        int segmentCount = 1;
        for (int i = 1; i < maxSegmentCount; i++) {
            RangedUri nextSegmentUri = representationHolder.getSegmentUrl(firstSegmentNum + i);
            RangedUri mergedSegmentUri = segmentUri.attemptMerge(nextSegmentUri, baseUrl);
            if (mergedSegmentUri == null) {
                // Unable to merge segment fetches because the URIs do not merge.
                break;
            }
            segmentUri = mergedSegmentUri;
            segmentCount++;
        }
        long endTimeUs = representationHolder.getSegmentEndTimeUs(firstSegmentNum + segmentCount - 1);
        DataSpec dataSpec = new DataSpec(segmentUri.resolveUri(baseUrl), segmentUri.start, segmentUri.length, representation.getCacheKey());
        long sampleOffsetUs = -representation.presentationTimeOffsetUs;
        return new ContainerMediaChunk(dataSource, dataSpec, trackFormat, trackSelectionReason, trackSelectionData, startTimeUs, endTimeUs, firstSegmentNum, segmentCount, sampleOffsetUs, representationHolder.extractorWrapper);
    }
}
Also used : SingleSampleMediaChunk(com.google.android.exoplayer2.source.chunk.SingleSampleMediaChunk) RangedUri(com.google.android.exoplayer2.source.dash.manifest.RangedUri) DataSpec(com.google.android.exoplayer2.upstream.DataSpec) Representation(com.google.android.exoplayer2.source.dash.manifest.Representation) ContainerMediaChunk(com.google.android.exoplayer2.source.chunk.ContainerMediaChunk)

Example 10 with DataSource

use of com.google.android.exoplayer2.upstream.DataSource in project ExoPlayer by google.

the class SingleSampleMediaChunk method load.

@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);
        BaseMediaChunkOutput output = getOutput();
        output.setSampleOffsetUs(0);
        TrackOutput trackOutput = output.track(0, trackType);
        trackOutput.format(sampleFormat);
        // 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 {
        Util.closeQuietly(dataSource);
    }
    loadCompleted = true;
}
Also used : ExtractorInput(com.google.android.exoplayer2.extractor.ExtractorInput) DefaultExtractorInput(com.google.android.exoplayer2.extractor.DefaultExtractorInput) DataSpec(com.google.android.exoplayer2.upstream.DataSpec) DefaultExtractorInput(com.google.android.exoplayer2.extractor.DefaultExtractorInput) TrackOutput(com.google.android.exoplayer2.extractor.TrackOutput)

Aggregations

DataSpec (com.google.android.exoplayer2.upstream.DataSpec)12 DefaultExtractorInput (com.google.android.exoplayer2.extractor.DefaultExtractorInput)5 ExtractorInput (com.google.android.exoplayer2.extractor.ExtractorInput)5 RangedUri (com.google.android.exoplayer2.source.dash.manifest.RangedUri)4 Representation (com.google.android.exoplayer2.source.dash.manifest.Representation)3 Extractor (com.google.android.exoplayer2.extractor.Extractor)2 BehindLiveWindowException (com.google.android.exoplayer2.source.BehindLiveWindowException)2 ChunkExtractorWrapper (com.google.android.exoplayer2.source.chunk.ChunkExtractorWrapper)2 ContainerMediaChunk (com.google.android.exoplayer2.source.chunk.ContainerMediaChunk)2 InitializationChunk (com.google.android.exoplayer2.source.chunk.InitializationChunk)2 DataSource (com.google.android.exoplayer2.upstream.DataSource)2 DataSourceInputStream (com.google.android.exoplayer2.upstream.DataSourceInputStream)2 Uri (android.net.Uri)1 Handler (android.os.Handler)1 MediaMetadataCompat (android.support.v4.media.MediaMetadataCompat)1 DefaultLoadControl (com.google.android.exoplayer2.DefaultLoadControl)1 Format (com.google.android.exoplayer2.Format)1 AudioAttributes (com.google.android.exoplayer2.audio.AudioAttributes)1 DefaultExtractorsFactory (com.google.android.exoplayer2.extractor.DefaultExtractorsFactory)1 ExtractorsFactory (com.google.android.exoplayer2.extractor.ExtractorsFactory)1