Search in sources :

Example 21 with Assertions.checkState

use of com.google.android.exoplayer2.util.Assertions.checkState in project ExoPlayer by google.

the class FakeDataSource method open.

@Override
public final long open(DataSpec dataSpec) throws IOException {
    Assertions.checkState(!openCalled);
    openCalled = true;
    // DataSpec requires a matching close call even if open fails.
    uri = dataSpec.uri;
    openedDataSpecs.add(dataSpec);
    transferInitializing(dataSpec);
    FakeData fakeData = fakeDataSet.getData(dataSpec.uri.toString());
    if (fakeData == null) {
        throw new IOException("Data not found: " + dataSpec.uri);
    }
    this.fakeData = fakeData;
    long totalLength = 0;
    for (Segment segment : fakeData.getSegments()) {
        totalLength += segment.length;
    }
    if (totalLength == 0) {
        throw new IOException("Data is empty: " + dataSpec.uri);
    }
    if (dataSpec.position > totalLength) {
        throw new DataSourceException(PlaybackException.ERROR_CODE_IO_READ_POSITION_OUT_OF_RANGE);
    }
    // Scan through the segments, configuring them for the current read.
    boolean findingCurrentSegmentIndex = true;
    currentSegmentIndex = 0;
    int scannedLength = 0;
    for (Segment segment : fakeData.getSegments()) {
        segment.bytesRead = (int) min(max(0, dataSpec.position - scannedLength), segment.length);
        scannedLength += segment.length;
        findingCurrentSegmentIndex &= segment.isErrorSegment() ? segment.exceptionCleared : (!segment.isActionSegment() && segment.bytesRead == segment.length);
        if (findingCurrentSegmentIndex) {
            currentSegmentIndex++;
        }
    }
    sourceOpened = true;
    transferStarted(dataSpec);
    // Configure bytesRemaining, and return.
    if (dataSpec.length == C.LENGTH_UNSET) {
        bytesRemaining = totalLength - dataSpec.position;
        return fakeData.isSimulatingUnknownLength() ? C.LENGTH_UNSET : bytesRemaining;
    } else {
        bytesRemaining = dataSpec.length;
        return bytesRemaining;
    }
}
Also used : DataSourceException(com.google.android.exoplayer2.upstream.DataSourceException) FakeData(com.google.android.exoplayer2.testutil.FakeDataSet.FakeData) IOException(java.io.IOException) Segment(com.google.android.exoplayer2.testutil.FakeDataSet.FakeData.Segment)

Example 22 with Assertions.checkState

use of com.google.android.exoplayer2.util.Assertions.checkState in project ExoPlayer by google.

the class FakeDataSource method close.

@Override
public final void close() {
    Assertions.checkState(openCalled);
    openCalled = false;
    uri = null;
    if (fakeData != null && currentSegmentIndex < fakeData.getSegments().size()) {
        Segment current = fakeData.getSegments().get(currentSegmentIndex);
        if (current.isErrorSegment() && current.exceptionThrown) {
            current.exceptionCleared = true;
        }
    }
    if (sourceOpened) {
        sourceOpened = false;
        transferEnded();
    }
    fakeData = null;
    onClosed();
}
Also used : Segment(com.google.android.exoplayer2.testutil.FakeDataSet.FakeData.Segment)

Example 23 with Assertions.checkState

use of com.google.android.exoplayer2.util.Assertions.checkState in project ExoPlayer by google.

the class FakeRenderer method render.

@Override
public void render(long positionUs, long elapsedRealtimeUs) throws ExoPlaybackException {
    if (isEnded) {
        return;
    }
    playbackPositionUs = positionUs;
    while (true) {
        if (!hasPendingBuffer) {
            FormatHolder formatHolder = getFormatHolder();
            buffer.clear();
            @ReadDataResult int result = readSource(formatHolder, buffer, /* readFlags= */
            0);
            if (result == C.RESULT_FORMAT_READ) {
                DrmSession.replaceSession(currentDrmSession, formatHolder.drmSession);
                currentDrmSession = formatHolder.drmSession;
                Format format = Assertions.checkNotNull(formatHolder.format);
                if (MimeTypes.getTrackType(format.sampleMimeType) != getTrackType()) {
                    throw ExoPlaybackException.createForRenderer(new IllegalStateException(Util.formatInvariant("Format track type (%s) doesn't match renderer track type (%s).", MimeTypes.getTrackType(format.sampleMimeType), getTrackType())), getName(), getIndex(), format, C.FORMAT_UNSUPPORTED_TYPE, /* isRecoverable= */
                    false, PlaybackException.ERROR_CODE_DECODING_FORMAT_UNSUPPORTED);
                }
                formatsRead.add(format);
                onFormatChanged(format);
            } else if (result == C.RESULT_BUFFER_READ) {
                if (buffer.isEndOfStream()) {
                    isEnded = true;
                    return;
                }
                hasPendingBuffer = true;
            } else {
                Assertions.checkState(result == C.RESULT_NOTHING_READ);
                return;
            }
        }
        if (hasPendingBuffer) {
            if (!shouldProcessBuffer(buffer.timeUs, positionUs)) {
                return;
            }
            lastSamplePositionUs = buffer.timeUs;
            sampleBufferReadCount++;
            hasPendingBuffer = false;
        }
    }
}
Also used : Format(com.google.android.exoplayer2.Format) ReadDataResult(com.google.android.exoplayer2.source.SampleStream.ReadDataResult) FormatHolder(com.google.android.exoplayer2.FormatHolder)

Example 24 with Assertions.checkState

use of com.google.android.exoplayer2.util.Assertions.checkState in project ExoPlayer by google.

the class HlsSampleStreamWrapper method buildTracksFromSampleStreams.

/**
 * Builds tracks that are exposed by this {@link HlsSampleStreamWrapper} instance, as well as
 * internal data-structures required for operation.
 *
 * <p>Tracks in HLS are complicated. A HLS multivariant playlist contains a number of "variants".
 * Each variant stream typically contains muxed video, audio and (possibly) additional audio,
 * metadata and caption tracks. We wish to allow the user to select between an adaptive track that
 * spans all variants, as well as each individual variant. If multiple audio tracks are present
 * within each variant then we wish to allow the user to select between those also.
 *
 * <p>To do this, tracks are constructed as follows. The {@link HlsChunkSource} exposes (N+1)
 * tracks, where N is the number of variants defined in the HLS multivariant playlist. These
 * consist of one adaptive track defined to span all variants and a track for each individual
 * variant. The adaptive track is initially selected. The extractor is then prepared to discover
 * the tracks inside of each variant stream. The two sets of tracks are then combined by this
 * method to create a third set, which is the set exposed by this {@link HlsSampleStreamWrapper}:
 *
 * <ul>
 *   <li>The extractor tracks are inspected to infer a "primary" track type. If a video track is
 *       present then it is always the primary type. If not, audio is the primary type if present.
 *       Else text is the primary type if present. Else there is no primary type.
 *   <li>If there is exactly one extractor track of the primary type, it's expanded into (N+1)
 *       exposed tracks, all of which correspond to the primary extractor track and each of which
 *       corresponds to a different chunk source track. Selecting one of these tracks has the
 *       effect of switching the selected track on the chunk source.
 *   <li>All other extractor tracks are exposed directly. Selecting one of these tracks has the
 *       effect of selecting an extractor track, leaving the selected track on the chunk source
 *       unchanged.
 * </ul>
 */
@EnsuresNonNull({ "trackGroups", "optionalTrackGroups", "trackGroupToSampleQueueIndex" })
private void buildTracksFromSampleStreams() {
    // Iterate through the extractor tracks to discover the "primary" track type, and the index
    // of the single track of this type.
    int primaryExtractorTrackType = C.TRACK_TYPE_NONE;
    int primaryExtractorTrackIndex = C.INDEX_UNSET;
    int extractorTrackCount = sampleQueues.length;
    for (int i = 0; i < extractorTrackCount; i++) {
        @Nullable String sampleMimeType = Assertions.checkStateNotNull(sampleQueues[i].getUpstreamFormat()).sampleMimeType;
        int trackType;
        if (MimeTypes.isVideo(sampleMimeType)) {
            trackType = C.TRACK_TYPE_VIDEO;
        } else if (MimeTypes.isAudio(sampleMimeType)) {
            trackType = C.TRACK_TYPE_AUDIO;
        } else if (MimeTypes.isText(sampleMimeType)) {
            trackType = C.TRACK_TYPE_TEXT;
        } else {
            trackType = C.TRACK_TYPE_NONE;
        }
        if (getTrackTypeScore(trackType) > getTrackTypeScore(primaryExtractorTrackType)) {
            primaryExtractorTrackType = trackType;
            primaryExtractorTrackIndex = i;
        } else if (trackType == primaryExtractorTrackType && primaryExtractorTrackIndex != C.INDEX_UNSET) {
            // We have multiple tracks of the primary type. We only want an index if there only exists a
            // single track of the primary type, so unset the index again.
            primaryExtractorTrackIndex = C.INDEX_UNSET;
        }
    }
    TrackGroup chunkSourceTrackGroup = chunkSource.getTrackGroup();
    int chunkSourceTrackCount = chunkSourceTrackGroup.length;
    // Instantiate the necessary internal data-structures.
    primaryTrackGroupIndex = C.INDEX_UNSET;
    trackGroupToSampleQueueIndex = new int[extractorTrackCount];
    for (int i = 0; i < extractorTrackCount; i++) {
        trackGroupToSampleQueueIndex[i] = i;
    }
    // Construct the set of exposed track groups.
    TrackGroup[] trackGroups = new TrackGroup[extractorTrackCount];
    for (int i = 0; i < extractorTrackCount; i++) {
        Format sampleFormat = Assertions.checkStateNotNull(sampleQueues[i].getUpstreamFormat());
        if (i == primaryExtractorTrackIndex) {
            Format[] formats = new Format[chunkSourceTrackCount];
            for (int j = 0; j < chunkSourceTrackCount; j++) {
                Format playlistFormat = chunkSourceTrackGroup.getFormat(j);
                if (primaryExtractorTrackType == C.TRACK_TYPE_AUDIO && muxedAudioFormat != null) {
                    playlistFormat = playlistFormat.withManifestFormatInfo(muxedAudioFormat);
                }
                // If there's only a single variant (chunkSourceTrackCount == 1) then we can safely
                // retain all fields from sampleFormat. Else we need to use deriveFormat to retain only
                // the fields that will be the same for all variants.
                formats[j] = chunkSourceTrackCount == 1 ? sampleFormat.withManifestFormatInfo(playlistFormat) : deriveFormat(playlistFormat, sampleFormat, /* propagateBitrates= */
                true);
            }
            trackGroups[i] = new TrackGroup(uid, formats);
            primaryTrackGroupIndex = i;
        } else {
            @Nullable Format playlistFormat = primaryExtractorTrackType == C.TRACK_TYPE_VIDEO && MimeTypes.isAudio(sampleFormat.sampleMimeType) ? muxedAudioFormat : null;
            String muxedTrackGroupId = uid + ":muxed:" + (i < primaryExtractorTrackIndex ? i : i - 1);
            trackGroups[i] = new TrackGroup(muxedTrackGroupId, deriveFormat(playlistFormat, sampleFormat, /* propagateBitrates= */
            false));
        }
    }
    this.trackGroups = createTrackGroupArrayWithDrmInfo(trackGroups);
    Assertions.checkState(optionalTrackGroups == null);
    optionalTrackGroups = Collections.emptySet();
}
Also used : Format(com.google.android.exoplayer2.Format) TrackGroup(com.google.android.exoplayer2.source.TrackGroup) Nullable(androidx.annotation.Nullable) EnsuresNonNull(org.checkerframework.checker.nullness.qual.EnsuresNonNull)

Example 25 with Assertions.checkState

use of com.google.android.exoplayer2.util.Assertions.checkState in project ExoPlayer by google.

the class HlsSampleStreamWrapper method onLoadError.

@Override
public LoadErrorAction onLoadError(Chunk loadable, long elapsedRealtimeMs, long loadDurationMs, IOException error, int errorCount) {
    boolean isMediaChunk = isMediaChunk(loadable);
    if (isMediaChunk && !((HlsMediaChunk) loadable).isPublished() && error instanceof HttpDataSource.InvalidResponseCodeException) {
        int responseCode = ((HttpDataSource.InvalidResponseCodeException) error).responseCode;
        if (responseCode == 410 || responseCode == 404) {
            // streams with HTTP 410 (Gone) also.
            return Loader.RETRY;
        }
    }
    long bytesLoaded = loadable.bytesLoaded();
    boolean exclusionSucceeded = false;
    LoadEventInfo loadEventInfo = new LoadEventInfo(loadable.loadTaskId, loadable.dataSpec, loadable.getUri(), loadable.getResponseHeaders(), elapsedRealtimeMs, loadDurationMs, bytesLoaded);
    MediaLoadData mediaLoadData = new MediaLoadData(loadable.type, trackType, loadable.trackFormat, loadable.trackSelectionReason, loadable.trackSelectionData, Util.usToMs(loadable.startTimeUs), Util.usToMs(loadable.endTimeUs));
    LoadErrorInfo loadErrorInfo = new LoadErrorInfo(loadEventInfo, mediaLoadData, error, errorCount);
    LoadErrorAction loadErrorAction;
    @Nullable LoadErrorHandlingPolicy.FallbackSelection fallbackSelection = loadErrorHandlingPolicy.getFallbackSelectionFor(createFallbackOptions(chunkSource.getTrackSelection()), loadErrorInfo);
    if (fallbackSelection != null && fallbackSelection.type == LoadErrorHandlingPolicy.FALLBACK_TYPE_TRACK) {
        exclusionSucceeded = chunkSource.maybeExcludeTrack(loadable, fallbackSelection.exclusionDurationMs);
    }
    if (exclusionSucceeded) {
        if (isMediaChunk && bytesLoaded == 0) {
            HlsMediaChunk removed = mediaChunks.remove(mediaChunks.size() - 1);
            Assertions.checkState(removed == loadable);
            if (mediaChunks.isEmpty()) {
                pendingResetPositionUs = lastSeekPositionUs;
            } else {
                Iterables.getLast(mediaChunks).invalidateExtractor();
            }
        }
        loadErrorAction = Loader.DONT_RETRY;
    } else /* did not exclude */
    {
        long retryDelayMs = loadErrorHandlingPolicy.getRetryDelayMsFor(loadErrorInfo);
        loadErrorAction = retryDelayMs != C.TIME_UNSET ? Loader.createRetryAction(/* resetErrorCount= */
        false, retryDelayMs) : Loader.DONT_RETRY_FATAL;
    }
    boolean wasCanceled = !loadErrorAction.isRetry();
    mediaSourceEventDispatcher.loadError(loadEventInfo, loadable.type, trackType, loadable.trackFormat, loadable.trackSelectionReason, loadable.trackSelectionData, loadable.startTimeUs, loadable.endTimeUs, error, wasCanceled);
    if (wasCanceled) {
        loadingChunk = null;
        loadErrorHandlingPolicy.onLoadTaskConcluded(loadable.loadTaskId);
    }
    if (exclusionSucceeded) {
        if (!prepared) {
            continueLoading(lastSeekPositionUs);
        } else {
            callback.onContinueLoadingRequested(this);
        }
    }
    return loadErrorAction;
}
Also used : MediaLoadData(com.google.android.exoplayer2.source.MediaLoadData) LoadErrorInfo(com.google.android.exoplayer2.upstream.LoadErrorHandlingPolicy.LoadErrorInfo) LoadErrorHandlingPolicy(com.google.android.exoplayer2.upstream.LoadErrorHandlingPolicy) LoadEventInfo(com.google.android.exoplayer2.source.LoadEventInfo) HttpDataSource(com.google.android.exoplayer2.upstream.HttpDataSource) Nullable(androidx.annotation.Nullable) LoadErrorAction(com.google.android.exoplayer2.upstream.Loader.LoadErrorAction)

Aggregations

Nullable (androidx.annotation.Nullable)12 Format (com.google.android.exoplayer2.Format)4 Player (com.google.android.exoplayer2.Player)4 FormatHolder (com.google.android.exoplayer2.FormatHolder)3 Timeline (com.google.android.exoplayer2.Timeline)3 LoadEventInfo (com.google.android.exoplayer2.source.LoadEventInfo)3 ReadDataResult (com.google.android.exoplayer2.source.SampleStream.ReadDataResult)3 TrackGroup (com.google.android.exoplayer2.source.TrackGroup)3 Segment (com.google.android.exoplayer2.testutil.FakeDataSet.FakeData.Segment)3 ExoTrackSelection (com.google.android.exoplayer2.trackselection.ExoTrackSelection)3 TrackSelection (com.google.android.exoplayer2.trackselection.TrackSelection)3 ParsableByteArray (com.google.android.exoplayer2.util.ParsableByteArray)3 SuppressLint (android.annotation.SuppressLint)2 Uri (android.net.Uri)2 GLSurfaceView (android.opengl.GLSurfaceView)2 SurfaceView (android.view.SurfaceView)2 TextureView (android.view.TextureView)2 DecoderException (com.google.android.exoplayer2.decoder.DecoderException)2 SchemeData (com.google.android.exoplayer2.drm.DrmInitData.SchemeData)2 Extractor (com.google.android.exoplayer2.extractor.Extractor)2