Search in sources :

Example 6 with Assertions.checkState

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

the class ProgressiveMediaPeriod method selectTracks.

@Override
public long selectTracks(@NullableType ExoTrackSelection[] selections, boolean[] mayRetainStreamFlags, @NullableType SampleStream[] streams, boolean[] streamResetFlags, long positionUs) {
    assertPrepared();
    TrackGroupArray tracks = trackState.tracks;
    boolean[] trackEnabledStates = trackState.trackEnabledStates;
    int oldEnabledTrackCount = enabledTrackCount;
    // Deselect old tracks.
    for (int i = 0; i < selections.length; i++) {
        if (streams[i] != null && (selections[i] == null || !mayRetainStreamFlags[i])) {
            int track = ((SampleStreamImpl) streams[i]).track;
            Assertions.checkState(trackEnabledStates[track]);
            enabledTrackCount--;
            trackEnabledStates[track] = false;
            streams[i] = null;
        }
    }
    // We'll always need to seek if this is a first selection to a non-zero position, or if we're
    // making a selection having previously disabled all tracks.
    boolean seekRequired = seenFirstTrackSelection ? oldEnabledTrackCount == 0 : positionUs != 0;
    // Select new tracks.
    for (int i = 0; i < selections.length; i++) {
        if (streams[i] == null && selections[i] != null) {
            ExoTrackSelection selection = selections[i];
            Assertions.checkState(selection.length() == 1);
            Assertions.checkState(selection.getIndexInTrackGroup(0) == 0);
            int track = tracks.indexOf(selection.getTrackGroup());
            Assertions.checkState(!trackEnabledStates[track]);
            enabledTrackCount++;
            trackEnabledStates[track] = true;
            streams[i] = new SampleStreamImpl(track);
            streamResetFlags[i] = true;
            // If there's still a chance of avoiding a seek, try and seek within the sample queue.
            if (!seekRequired) {
                SampleQueue sampleQueue = sampleQueues[track];
                // A seek can be avoided if we're able to seek to the current playback position in the
                // sample queue, or if we haven't read anything from the queue since the previous seek
                // (this case is common for sparse tracks such as metadata tracks). In all other cases a
                // seek is required.
                seekRequired = !sampleQueue.seekTo(positionUs, /* allowTimeBeyondBuffer= */
                true) && sampleQueue.getReadIndex() != 0;
            }
        }
    }
    if (enabledTrackCount == 0) {
        pendingDeferredRetry = false;
        notifyDiscontinuity = false;
        if (loader.isLoading()) {
            // Discard as much as we can synchronously.
            for (SampleQueue sampleQueue : sampleQueues) {
                sampleQueue.discardToEnd();
            }
            loader.cancelLoading();
        } else {
            for (SampleQueue sampleQueue : sampleQueues) {
                sampleQueue.reset();
            }
        }
    } else if (seekRequired) {
        positionUs = seekToUs(positionUs);
        // We'll need to reset renderers consuming from all streams due to the seek.
        for (int i = 0; i < streams.length; i++) {
            if (streams[i] != null) {
                streamResetFlags[i] = true;
            }
        }
    }
    seenFirstTrackSelection = true;
    return positionUs;
}
Also used : ExoTrackSelection(com.google.android.exoplayer2.trackselection.ExoTrackSelection)

Example 7 with Assertions.checkState

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

the class ChunkSampleStream method onLoadError.

@Override
public LoadErrorAction onLoadError(Chunk loadable, long elapsedRealtimeMs, long loadDurationMs, IOException error, int errorCount) {
    long bytesLoaded = loadable.bytesLoaded();
    boolean isMediaChunk = isMediaChunk(loadable);
    int lastChunkIndex = mediaChunks.size() - 1;
    boolean cancelable = bytesLoaded == 0 || !isMediaChunk || !haveReadFromMediaChunk(lastChunkIndex);
    LoadEventInfo loadEventInfo = new LoadEventInfo(loadable.loadTaskId, loadable.dataSpec, loadable.getUri(), loadable.getResponseHeaders(), elapsedRealtimeMs, loadDurationMs, bytesLoaded);
    MediaLoadData mediaLoadData = new MediaLoadData(loadable.type, primaryTrackType, loadable.trackFormat, loadable.trackSelectionReason, loadable.trackSelectionData, Util.usToMs(loadable.startTimeUs), Util.usToMs(loadable.endTimeUs));
    LoadErrorInfo loadErrorInfo = new LoadErrorInfo(loadEventInfo, mediaLoadData, error, errorCount);
    @Nullable LoadErrorAction loadErrorAction = null;
    if (chunkSource.onChunkLoadError(loadable, cancelable, loadErrorInfo, loadErrorHandlingPolicy)) {
        if (cancelable) {
            loadErrorAction = Loader.DONT_RETRY;
            if (isMediaChunk) {
                BaseMediaChunk removed = discardUpstreamMediaChunksFromIndex(lastChunkIndex);
                Assertions.checkState(removed == loadable);
                if (mediaChunks.isEmpty()) {
                    pendingResetPositionUs = lastSeekPositionUs;
                }
            }
        } else {
            Log.w(TAG, "Ignoring attempt to cancel non-cancelable load.");
        }
    }
    if (loadErrorAction == null) {
        // The load was not cancelled. Either the load must be retried or the error propagated.
        long retryDelayMs = loadErrorHandlingPolicy.getRetryDelayMsFor(loadErrorInfo);
        loadErrorAction = retryDelayMs != C.TIME_UNSET ? Loader.createRetryAction(/* resetErrorCount= */
        false, retryDelayMs) : Loader.DONT_RETRY_FATAL;
    }
    boolean canceled = !loadErrorAction.isRetry();
    mediaSourceEventDispatcher.loadError(loadEventInfo, loadable.type, primaryTrackType, loadable.trackFormat, loadable.trackSelectionReason, loadable.trackSelectionData, loadable.startTimeUs, loadable.endTimeUs, error, canceled);
    if (canceled) {
        loadingChunk = null;
        loadErrorHandlingPolicy.onLoadTaskConcluded(loadable.loadTaskId);
        callback.onContinueLoadingRequested(this);
    }
    return loadErrorAction;
}
Also used : LoadEventInfo(com.google.android.exoplayer2.source.LoadEventInfo) MediaLoadData(com.google.android.exoplayer2.source.MediaLoadData) LoadErrorInfo(com.google.android.exoplayer2.upstream.LoadErrorHandlingPolicy.LoadErrorInfo) Nullable(androidx.annotation.Nullable) LoadErrorAction(com.google.android.exoplayer2.upstream.Loader.LoadErrorAction)

Example 8 with Assertions.checkState

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

the class TsExtractor method seek.

@Override
public void seek(long position, long timeUs) {
    Assertions.checkState(mode != MODE_HLS);
    int timestampAdjustersCount = timestampAdjusters.size();
    for (int i = 0; i < timestampAdjustersCount; i++) {
        TimestampAdjuster timestampAdjuster = timestampAdjusters.get(i);
        // If the timestamp adjuster has not yet established a timestamp offset, we need to reset its
        // expected first sample timestamp to be the new seek position. Without this, the timestamp
        // adjuster would incorrectly establish its timestamp offset assuming that the first sample
        // after this seek corresponds to the start of the stream (or a previous seek position, if
        // there was one).
        boolean resetTimestampAdjuster = timestampAdjuster.getTimestampOffsetUs() == C.TIME_UNSET;
        if (!resetTimestampAdjuster) {
            long adjusterFirstSampleTimestampUs = timestampAdjuster.getFirstSampleTimestampUs();
            // Also reset the timestamp adjuster if its offset was calculated based on a non-zero
            // position in the stream (other than the position being seeked to), since in this case the
            // offset may not be accurate.
            resetTimestampAdjuster = adjusterFirstSampleTimestampUs != C.TIME_UNSET && adjusterFirstSampleTimestampUs != 0 && adjusterFirstSampleTimestampUs != timeUs;
        }
        if (resetTimestampAdjuster) {
            timestampAdjuster.reset(timeUs);
        }
    }
    if (timeUs != 0 && tsBinarySearchSeeker != null) {
        tsBinarySearchSeeker.setSeekTargetUs(timeUs);
    }
    tsPacketBuffer.reset(/* limit= */
    0);
    continuityCounters.clear();
    for (int i = 0; i < tsPayloadReaders.size(); i++) {
        tsPayloadReaders.valueAt(i).seek();
    }
    bytesSinceLastSync = 0;
}
Also used : TimestampAdjuster(com.google.android.exoplayer2.util.TimestampAdjuster)

Example 9 with Assertions.checkState

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

the class WavHeaderReader method readFormat.

/**
 * Reads and returns a {@code WavFormat}.
 *
 * @param input Input stream to read the WAV format from. The position should point to the byte
 *     following the ds64 chunk if present, or to the byte following the WAVE tag otherwise.
 * @throws IOException If reading from the input fails.
 * @return A new {@code WavFormat} read from {@code input}.
 */
public static WavFormat readFormat(ExtractorInput input) throws IOException {
    // Allocate a scratch buffer large enough to store the format chunk.
    ParsableByteArray scratch = new ParsableByteArray(16);
    // Skip chunks until we find the format chunk.
    ChunkHeader chunkHeader = skipToChunk(/* chunkId= */
    WavUtil.FMT_FOURCC, input, scratch);
    Assertions.checkState(chunkHeader.size >= 16);
    input.peekFully(scratch.getData(), 0, 16);
    scratch.setPosition(0);
    int audioFormatType = scratch.readLittleEndianUnsignedShort();
    int numChannels = scratch.readLittleEndianUnsignedShort();
    int frameRateHz = scratch.readLittleEndianUnsignedIntToInt();
    int averageBytesPerSecond = scratch.readLittleEndianUnsignedIntToInt();
    int blockSize = scratch.readLittleEndianUnsignedShort();
    int bitsPerSample = scratch.readLittleEndianUnsignedShort();
    int bytesLeft = (int) chunkHeader.size - 16;
    byte[] extraData;
    if (bytesLeft > 0) {
        extraData = new byte[bytesLeft];
        input.peekFully(extraData, 0, bytesLeft);
    } else {
        extraData = Util.EMPTY_BYTE_ARRAY;
    }
    input.skipFully((int) (input.getPeekPosition() - input.getPosition()));
    return new WavFormat(audioFormatType, numChannels, frameRateHz, averageBytesPerSecond, blockSize, bitsPerSample, extraData);
}
Also used : ParsableByteArray(com.google.android.exoplayer2.util.ParsableByteArray)

Example 10 with Assertions.checkState

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

the class WebViewSubtitleOutput method updateWebView.

private void updateWebView() {
    StringBuilder html = new StringBuilder();
    html.append(Util.formatInvariant("<body><div style='" + "-webkit-user-select:none;" + "position:fixed;" + "top:0;" + "bottom:0;" + "left:0;" + "right:0;" + "color:%s;" + "font-size:%s;" + "line-height:%.2f;" + "text-shadow:%s;" + "'>", HtmlUtils.toCssRgba(style.foregroundColor), convertTextSizeToCss(defaultTextSizeType, defaultTextSize), CSS_LINE_HEIGHT, convertCaptionStyleToCssTextShadow(style)));
    Map<String, String> cssRuleSets = new HashMap<>();
    cssRuleSets.put(HtmlUtils.cssAllClassDescendantsSelector(DEFAULT_BACKGROUND_CSS_CLASS), Util.formatInvariant("background-color:%s;", HtmlUtils.toCssRgba(style.backgroundColor)));
    for (int i = 0; i < textCues.size(); i++) {
        Cue cue = textCues.get(i);
        float positionPercent = (cue.position != Cue.DIMEN_UNSET) ? (cue.position * 100) : 50;
        int positionAnchorTranslatePercent = anchorTypeToTranslatePercent(cue.positionAnchor);
        String lineValue;
        boolean lineMeasuredFromEnd = false;
        int lineAnchorTranslatePercent = 0;
        if (cue.line != Cue.DIMEN_UNSET) {
            switch(cue.lineType) {
                case Cue.LINE_TYPE_NUMBER:
                    if (cue.line >= 0) {
                        lineValue = Util.formatInvariant("%.2fem", cue.line * CSS_LINE_HEIGHT);
                    } else {
                        lineValue = Util.formatInvariant("%.2fem", (-cue.line - 1) * CSS_LINE_HEIGHT);
                        lineMeasuredFromEnd = true;
                    }
                    break;
                case Cue.LINE_TYPE_FRACTION:
                case Cue.TYPE_UNSET:
                default:
                    lineValue = Util.formatInvariant("%.2f%%", cue.line * 100);
                    lineAnchorTranslatePercent = cue.verticalType == Cue.VERTICAL_TYPE_RL ? -anchorTypeToTranslatePercent(cue.lineAnchor) : anchorTypeToTranslatePercent(cue.lineAnchor);
            }
        } else {
            lineValue = Util.formatInvariant("%.2f%%", (1.0f - bottomPaddingFraction) * 100);
            lineAnchorTranslatePercent = -100;
        }
        String size = cue.size != Cue.DIMEN_UNSET ? Util.formatInvariant("%.2f%%", cue.size * 100) : "fit-content";
        String textAlign = convertAlignmentToCss(cue.textAlignment);
        String writingMode = convertVerticalTypeToCss(cue.verticalType);
        String cueTextSizeCssPx = convertTextSizeToCss(cue.textSizeType, cue.textSize);
        String windowCssColor = HtmlUtils.toCssRgba(cue.windowColorSet ? cue.windowColor : style.windowColor);
        String positionProperty;
        String lineProperty;
        switch(cue.verticalType) {
            case Cue.VERTICAL_TYPE_LR:
                lineProperty = lineMeasuredFromEnd ? "right" : "left";
                positionProperty = "top";
                break;
            case Cue.VERTICAL_TYPE_RL:
                lineProperty = lineMeasuredFromEnd ? "left" : "right";
                positionProperty = "top";
                break;
            case Cue.TYPE_UNSET:
            default:
                lineProperty = lineMeasuredFromEnd ? "bottom" : "top";
                positionProperty = "left";
        }
        String sizeProperty;
        int horizontalTranslatePercent;
        int verticalTranslatePercent;
        if (cue.verticalType == Cue.VERTICAL_TYPE_LR || cue.verticalType == Cue.VERTICAL_TYPE_RL) {
            sizeProperty = "height";
            horizontalTranslatePercent = lineAnchorTranslatePercent;
            verticalTranslatePercent = positionAnchorTranslatePercent;
        } else {
            sizeProperty = "width";
            horizontalTranslatePercent = positionAnchorTranslatePercent;
            verticalTranslatePercent = lineAnchorTranslatePercent;
        }
        SpannedToHtmlConverter.HtmlAndCss htmlAndCss = SpannedToHtmlConverter.convert(cue.text, getContext().getResources().getDisplayMetrics().density);
        for (String cssSelector : cssRuleSets.keySet()) {
            @Nullable String previousCssDeclarationBlock = cssRuleSets.put(cssSelector, cssRuleSets.get(cssSelector));
            Assertions.checkState(previousCssDeclarationBlock == null || previousCssDeclarationBlock.equals(cssRuleSets.get(cssSelector)));
        }
        html.append(Util.formatInvariant("<div style='" + "position:absolute;" + "z-index:%s;" + "%s:%.2f%%;" + "%s:%s;" + "%s:%s;" + "text-align:%s;" + "writing-mode:%s;" + "font-size:%s;" + "background-color:%s;" + "transform:translate(%s%%,%s%%)" + "%s;" + "'>", /* z-index */
        i, positionProperty, positionPercent, lineProperty, lineValue, sizeProperty, size, textAlign, writingMode, cueTextSizeCssPx, windowCssColor, horizontalTranslatePercent, verticalTranslatePercent, getBlockShearTransformFunction(cue))).append(Util.formatInvariant("<span class='%s'>", DEFAULT_BACKGROUND_CSS_CLASS));
        if (cue.multiRowAlignment != null) {
            html.append(Util.formatInvariant("<span style='display:inline-block; text-align:%s;'>", convertAlignmentToCss(cue.multiRowAlignment))).append(htmlAndCss.html).append("</span>");
        } else {
            html.append(htmlAndCss.html);
        }
        html.append("</span>").append("</div>");
    }
    html.append("</div></body></html>");
    StringBuilder htmlHead = new StringBuilder();
    htmlHead.append("<html><head><style>");
    for (String cssSelector : cssRuleSets.keySet()) {
        htmlHead.append(cssSelector).append("{").append(cssRuleSets.get(cssSelector)).append("}");
    }
    htmlHead.append("</style></head>");
    html.insert(0, htmlHead.toString());
    webView.loadData(Base64.encodeToString(html.toString().getBytes(Charsets.UTF_8), Base64.NO_PADDING), "text/html", "base64");
}
Also used : Cue(com.google.android.exoplayer2.text.Cue) HashMap(java.util.HashMap) Nullable(androidx.annotation.Nullable)

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