Search in sources :

Example 16 with Renderer

use of com.google.android.exoplayer2.Renderer in project ExoPlayer by google.

the class DefaultMediaClock method onRendererEnabled.

/**
 * Notifies the media clock that a renderer has been enabled. Starts using the media clock of the
 * provided renderer if available.
 *
 * @param renderer The renderer which has been enabled.
 * @throws ExoPlaybackException If the renderer provides a media clock and another renderer media
 *     clock is already provided.
 */
public void onRendererEnabled(Renderer renderer) throws ExoPlaybackException {
    @Nullable MediaClock rendererMediaClock = renderer.getMediaClock();
    if (rendererMediaClock != null && rendererMediaClock != rendererClock) {
        if (rendererClock != null) {
            throw ExoPlaybackException.createForUnexpected(new IllegalStateException("Multiple renderer media clocks enabled."));
        }
        this.rendererClock = rendererMediaClock;
        this.rendererClockSource = renderer;
        rendererClock.setPlaybackParameters(standaloneClock.getPlaybackParameters());
    }
}
Also used : MediaClock(com.google.android.exoplayer2.util.MediaClock) StandaloneMediaClock(com.google.android.exoplayer2.util.StandaloneMediaClock) Nullable(androidx.annotation.Nullable)

Example 17 with Renderer

use of com.google.android.exoplayer2.Renderer in project ExoPlayer by google.

the class DefaultMediaClock method syncClocks.

private void syncClocks(boolean isReadingAhead) {
    if (shouldUseStandaloneClock(isReadingAhead)) {
        isUsingStandaloneClock = true;
        if (standaloneClockIsStarted) {
            standaloneClock.start();
        }
        return;
    }
    // We are either already using the renderer clock or switching from the standalone to the
    // renderer clock, so it must be non-null.
    MediaClock rendererClock = Assertions.checkNotNull(this.rendererClock);
    long rendererClockPositionUs = rendererClock.getPositionUs();
    if (isUsingStandaloneClock) {
        // Ensure enabling the renderer clock doesn't jump backwards in time.
        if (rendererClockPositionUs < standaloneClock.getPositionUs()) {
            standaloneClock.stop();
            return;
        }
        isUsingStandaloneClock = false;
        if (standaloneClockIsStarted) {
            standaloneClock.start();
        }
    }
    // Continuously sync stand-alone clock to renderer clock so that it can take over if needed.
    standaloneClock.resetPosition(rendererClockPositionUs);
    PlaybackParameters playbackParameters = rendererClock.getPlaybackParameters();
    if (!playbackParameters.equals(standaloneClock.getPlaybackParameters())) {
        standaloneClock.setPlaybackParameters(playbackParameters);
        listener.onPlaybackParametersChanged(playbackParameters);
    }
}
Also used : MediaClock(com.google.android.exoplayer2.util.MediaClock) StandaloneMediaClock(com.google.android.exoplayer2.util.StandaloneMediaClock)

Example 18 with Renderer

use of com.google.android.exoplayer2.Renderer in project ExoPlayer by google.

the class TextRenderer method render.

@Override
public void render(long positionUs, long elapsedRealtimeUs) {
    if (isCurrentStreamFinal() && finalStreamEndPositionUs != C.TIME_UNSET && positionUs >= finalStreamEndPositionUs) {
        releaseBuffers();
        outputStreamEnded = true;
    }
    if (outputStreamEnded) {
        return;
    }
    if (nextSubtitle == null) {
        checkNotNull(decoder).setPositionUs(positionUs);
        try {
            nextSubtitle = checkNotNull(decoder).dequeueOutputBuffer();
        } catch (SubtitleDecoderException e) {
            handleDecoderError(e);
            return;
        }
    }
    if (getState() != STATE_STARTED) {
        return;
    }
    boolean textRendererNeedsUpdate = false;
    if (subtitle != null) {
        // We're iterating through the events in a subtitle. Set textRendererNeedsUpdate if we
        // advance to the next event.
        long subtitleNextEventTimeUs = getNextEventTime();
        while (subtitleNextEventTimeUs <= positionUs) {
            nextSubtitleEventIndex++;
            subtitleNextEventTimeUs = getNextEventTime();
            textRendererNeedsUpdate = true;
        }
    }
    if (nextSubtitle != null) {
        SubtitleOutputBuffer nextSubtitle = this.nextSubtitle;
        if (nextSubtitle.isEndOfStream()) {
            if (!textRendererNeedsUpdate && getNextEventTime() == Long.MAX_VALUE) {
                if (decoderReplacementState == REPLACEMENT_STATE_WAIT_END_OF_STREAM) {
                    replaceDecoder();
                } else {
                    releaseBuffers();
                    outputStreamEnded = true;
                }
            }
        } else if (nextSubtitle.timeUs <= positionUs) {
            // Advance to the next subtitle. Sync the next event index and trigger an update.
            if (subtitle != null) {
                subtitle.release();
            }
            nextSubtitleEventIndex = nextSubtitle.getNextEventTimeIndex(positionUs);
            subtitle = nextSubtitle;
            this.nextSubtitle = null;
            textRendererNeedsUpdate = true;
        }
    }
    if (textRendererNeedsUpdate) {
        // If textRendererNeedsUpdate then subtitle must be non-null.
        checkNotNull(subtitle);
        // textRendererNeedsUpdate is set and we're playing. Update the renderer.
        updateOutput(subtitle.getCues(positionUs));
    }
    if (decoderReplacementState == REPLACEMENT_STATE_WAIT_END_OF_STREAM) {
        return;
    }
    try {
        while (!inputStreamEnded) {
            @Nullable SubtitleInputBuffer nextInputBuffer = this.nextInputBuffer;
            if (nextInputBuffer == null) {
                nextInputBuffer = checkNotNull(decoder).dequeueInputBuffer();
                if (nextInputBuffer == null) {
                    return;
                }
                this.nextInputBuffer = nextInputBuffer;
            }
            if (decoderReplacementState == REPLACEMENT_STATE_SIGNAL_END_OF_STREAM) {
                nextInputBuffer.setFlags(C.BUFFER_FLAG_END_OF_STREAM);
                checkNotNull(decoder).queueInputBuffer(nextInputBuffer);
                this.nextInputBuffer = null;
                decoderReplacementState = REPLACEMENT_STATE_WAIT_END_OF_STREAM;
                return;
            }
            // Try and read the next subtitle from the source.
            @ReadDataResult int result = readSource(formatHolder, nextInputBuffer, /* readFlags= */
            0);
            if (result == C.RESULT_BUFFER_READ) {
                if (nextInputBuffer.isEndOfStream()) {
                    inputStreamEnded = true;
                    waitingForKeyFrame = false;
                } else {
                    @Nullable Format format = formatHolder.format;
                    if (format == null) {
                        // We haven't received a format yet.
                        return;
                    }
                    nextInputBuffer.subsampleOffsetUs = format.subsampleOffsetUs;
                    nextInputBuffer.flip();
                    waitingForKeyFrame &= !nextInputBuffer.isKeyFrame();
                }
                if (!waitingForKeyFrame) {
                    checkNotNull(decoder).queueInputBuffer(nextInputBuffer);
                    this.nextInputBuffer = null;
                }
            } else if (result == C.RESULT_NOTHING_READ) {
                return;
            }
        }
    } catch (SubtitleDecoderException e) {
        handleDecoderError(e);
    }
}
Also used : Format(com.google.android.exoplayer2.Format) ReadDataResult(com.google.android.exoplayer2.source.SampleStream.ReadDataResult) Nullable(androidx.annotation.Nullable)

Example 19 with Renderer

use of com.google.android.exoplayer2.Renderer in project ExoPlayer by google.

the class ExoPlayerTest method playShortDurationPeriods.

/**
 * Tests playback of periods with very short duration.
 */
@Test
public void playShortDurationPeriods() throws Exception {
    // TimelineWindowDefinition.DEFAULT_WINDOW_DURATION_US / 100 = 1000 us per period.
    Timeline timeline = new FakeTimeline(new TimelineWindowDefinition(/* periodCount= */
    100, /* id= */
    0));
    FakeRenderer renderer = new FakeRenderer(C.TRACK_TYPE_VIDEO);
    ExoPlayer player = new TestExoPlayerBuilder(context).setRenderers(renderer).build();
    Player.Listener mockPlayerListener = mock(Player.Listener.class);
    player.addListener(mockPlayerListener);
    player.setMediaSource(new FakeMediaSource(timeline, ExoPlayerTestRunner.VIDEO_FORMAT));
    player.prepare();
    player.play();
    runUntilPlaybackState(player, Player.STATE_ENDED);
    InOrder inOrder = inOrder(mockPlayerListener);
    inOrder.verify(mockPlayerListener).onTimelineChanged(argThat(noUid(placeholderTimeline)), eq(Player.TIMELINE_CHANGE_REASON_PLAYLIST_CHANGED));
    inOrder.verify(mockPlayerListener).onTimelineChanged(argThat(noUid(timeline)), eq(Player.TIMELINE_CHANGE_REASON_SOURCE_UPDATE));
    inOrder.verify(mockPlayerListener, times(99)).onPositionDiscontinuity(any(), any(), eq(Player.DISCONTINUITY_REASON_AUTO_TRANSITION));
    assertThat(renderer.getFormatsRead()).hasSize(100);
    assertThat(renderer.sampleBufferReadCount).isEqualTo(100);
    assertThat(renderer.isEnded).isTrue();
}
Also used : FakeRenderer(com.google.android.exoplayer2.testutil.FakeRenderer) Listener(com.google.android.exoplayer2.Player.Listener) NoUidTimeline(com.google.android.exoplayer2.testutil.NoUidTimeline) SinglePeriodTimeline(com.google.android.exoplayer2.source.SinglePeriodTimeline) FakeTimeline(com.google.android.exoplayer2.testutil.FakeTimeline) InOrder(org.mockito.InOrder) FakeMediaSource(com.google.android.exoplayer2.testutil.FakeMediaSource) FakeTimeline(com.google.android.exoplayer2.testutil.FakeTimeline) TimelineWindowDefinition(com.google.android.exoplayer2.testutil.FakeTimeline.TimelineWindowDefinition) TestExoPlayerBuilder(com.google.android.exoplayer2.testutil.TestExoPlayerBuilder) Test(org.junit.Test)

Example 20 with Renderer

use of com.google.android.exoplayer2.Renderer in project ExoPlayer by google.

the class ExoPlayerTest method allActivatedTrackSelectionAreReleasedWhenTrackSelectionsAreReused.

@Test
public void allActivatedTrackSelectionAreReleasedWhenTrackSelectionsAreReused() throws Exception {
    MediaSource mediaSource = new FakeMediaSource(new FakeTimeline(), ExoPlayerTestRunner.VIDEO_FORMAT, ExoPlayerTestRunner.AUDIO_FORMAT);
    FakeRenderer videoRenderer = new FakeRenderer(C.TRACK_TYPE_VIDEO);
    FakeRenderer audioRenderer = new FakeRenderer(C.TRACK_TYPE_AUDIO);
    final FakeTrackSelector trackSelector = new FakeTrackSelector(/* mayReuseTrackSelection= */
    true);
    ActionSchedule disableTrackAction = new ActionSchedule.Builder(TAG).pause().waitForPlaybackState(Player.STATE_READY).disableRenderer(0).play().build();
    new ExoPlayerTestRunner.Builder(context).setMediaSources(mediaSource).setRenderers(videoRenderer, audioRenderer).setTrackSelector(trackSelector).setActionSchedule(disableTrackAction).build().start().blockUntilEnded(TIMEOUT_MS);
    List<FakeTrackSelection> createdTrackSelections = trackSelector.getAllTrackSelections();
    int numSelectionsEnabled = 0;
    // Assert that all tracks selection are disabled at the end of the playback.
    for (FakeTrackSelection trackSelection : createdTrackSelections) {
        assertThat(trackSelection.isEnabled).isFalse();
        numSelectionsEnabled += trackSelection.enableCount;
    }
    // There are 2 renderers, and track selections are made twice. The second time one renderer is
    // disabled, and the selector re-uses the previous selection for the enabled renderer. So we
    // expect two track selections, one of which will have been enabled twice.
    assertThat(createdTrackSelections).hasSize(2);
    assertThat(numSelectionsEnabled).isEqualTo(3);
}
Also used : FakeRenderer(com.google.android.exoplayer2.testutil.FakeRenderer) FakeTrackSelection(com.google.android.exoplayer2.testutil.FakeTrackSelection) ServerSideAdInsertionMediaSource(com.google.android.exoplayer2.source.ads.ServerSideAdInsertionMediaSource) FakeAdaptiveMediaSource(com.google.android.exoplayer2.testutil.FakeAdaptiveMediaSource) MaskingMediaSource(com.google.android.exoplayer2.source.MaskingMediaSource) ConcatenatingMediaSource(com.google.android.exoplayer2.source.ConcatenatingMediaSource) MediaSource(com.google.android.exoplayer2.source.MediaSource) CompositeMediaSource(com.google.android.exoplayer2.source.CompositeMediaSource) ClippingMediaSource(com.google.android.exoplayer2.source.ClippingMediaSource) FakeMediaSource(com.google.android.exoplayer2.testutil.FakeMediaSource) FakeMediaSource(com.google.android.exoplayer2.testutil.FakeMediaSource) FakeTrackSelector(com.google.android.exoplayer2.testutil.FakeTrackSelector) ActionSchedule(com.google.android.exoplayer2.testutil.ActionSchedule) FakeTimeline(com.google.android.exoplayer2.testutil.FakeTimeline) ExoPlayerTestRunner(com.google.android.exoplayer2.testutil.ExoPlayerTestRunner) Test(org.junit.Test)

Aggregations

Test (org.junit.Test)36 FakeRenderer (com.google.android.exoplayer2.testutil.FakeRenderer)27 Nullable (androidx.annotation.Nullable)25 FakeMediaSource (com.google.android.exoplayer2.testutil.FakeMediaSource)25 FakeTimeline (com.google.android.exoplayer2.testutil.FakeTimeline)25 TestExoPlayerBuilder (com.google.android.exoplayer2.testutil.TestExoPlayerBuilder)24 TextRenderer (com.google.android.exoplayer2.text.TextRenderer)21 TrackGroupArray (com.google.android.exoplayer2.source.TrackGroupArray)19 ArrayList (java.util.ArrayList)18 SinglePeriodTimeline (com.google.android.exoplayer2.source.SinglePeriodTimeline)17 NoUidTimeline (com.google.android.exoplayer2.testutil.NoUidTimeline)17 MediaSource (com.google.android.exoplayer2.source.MediaSource)16 TrackGroup (com.google.android.exoplayer2.source.TrackGroup)16 ActionSchedule (com.google.android.exoplayer2.testutil.ActionSchedule)16 Format (com.google.android.exoplayer2.Format)15 Listener (com.google.android.exoplayer2.Player.Listener)15 ExoPlayerTestRunner (com.google.android.exoplayer2.testutil.ExoPlayerTestRunner)15 TimelineWindowDefinition (com.google.android.exoplayer2.testutil.FakeTimeline.TimelineWindowDefinition)14 InOrder (org.mockito.InOrder)14 ConcatenatingMediaSource (com.google.android.exoplayer2.source.ConcatenatingMediaSource)13