Search in sources :

Example 56 with Renderer

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

the class ExoPlayerImplInternal method setForegroundModeInternal.

private void setForegroundModeInternal(boolean foregroundMode, @Nullable AtomicBoolean processedFlag) {
    if (this.foregroundMode != foregroundMode) {
        this.foregroundMode = foregroundMode;
        if (!foregroundMode) {
            for (Renderer renderer : renderers) {
                if (!isRendererEnabled(renderer) && renderersToReset.remove(renderer)) {
                    renderer.reset();
                }
            }
        }
    }
    if (processedFlag != null) {
        synchronized (this) {
            processedFlag.set(true);
            notifyAll();
        }
    }
}
Also used : TextRenderer(com.google.android.exoplayer2.text.TextRenderer)

Example 57 with Renderer

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

the class MediaPeriodQueue method getFollowingMediaPeriodInfo.

/**
 * Returns the {@link MediaPeriodInfo} for the media period following {@code mediaPeriodHolder}'s
 * media period.
 *
 * @param timeline The current timeline.
 * @param mediaPeriodHolder The media period holder.
 * @param rendererPositionUs The current renderer position in microseconds.
 * @return The following media period's info, or {@code null} if it is not yet possible to get the
 *     next media period info.
 */
@Nullable
private MediaPeriodInfo getFollowingMediaPeriodInfo(Timeline timeline, MediaPeriodHolder mediaPeriodHolder, long rendererPositionUs) {
    // TODO: This method is called repeatedly from ExoPlayerImplInternal.maybeUpdateLoadingPeriod
    // but if the timeline is not ready to provide the next period it can't return a non-null value
    // until the timeline is updated. Store whether the next timeline period is ready when the
    // timeline is updated, to avoid repeatedly checking the same timeline.
    MediaPeriodInfo mediaPeriodInfo = mediaPeriodHolder.info;
    // The expected delay until playback transitions to the new period is equal the duration of
    // media that's currently buffered (assuming no interruptions). This is used to project forward
    // the start position for transitions to new windows.
    long bufferedDurationUs = mediaPeriodHolder.getRendererOffset() + mediaPeriodInfo.durationUs - rendererPositionUs;
    if (mediaPeriodInfo.isLastInTimelinePeriod) {
        int currentPeriodIndex = timeline.getIndexOfPeriod(mediaPeriodInfo.id.periodUid);
        int nextPeriodIndex = timeline.getNextPeriodIndex(currentPeriodIndex, period, window, repeatMode, shuffleModeEnabled);
        if (nextPeriodIndex == C.INDEX_UNSET) {
            // We can't create a next period yet.
            return null;
        }
        // We either start a new period in the same window or the first period in the next window.
        long startPositionUs = 0;
        long contentPositionUs = 0;
        int nextWindowIndex = timeline.getPeriod(nextPeriodIndex, period, /* setIds= */
        true).windowIndex;
        Object nextPeriodUid = checkNotNull(period.uid);
        long windowSequenceNumber = mediaPeriodInfo.id.windowSequenceNumber;
        if (timeline.getWindow(nextWindowIndex, window).firstPeriodIndex == nextPeriodIndex) {
            // We're starting to buffer a new window. When playback transitions to this window we'll
            // want it to be from its default start position, so project the default start position
            // forward by the duration of the buffer, and start buffering from this point.
            contentPositionUs = C.TIME_UNSET;
            @Nullable Pair<Object, Long> defaultPositionUs = timeline.getPeriodPositionUs(window, period, nextWindowIndex, /* windowPositionUs= */
            C.TIME_UNSET, /* defaultPositionProjectionUs= */
            max(0, bufferedDurationUs));
            if (defaultPositionUs == null) {
                return null;
            }
            nextPeriodUid = defaultPositionUs.first;
            startPositionUs = defaultPositionUs.second;
            @Nullable MediaPeriodHolder nextMediaPeriodHolder = mediaPeriodHolder.getNext();
            if (nextMediaPeriodHolder != null && nextMediaPeriodHolder.uid.equals(nextPeriodUid)) {
                windowSequenceNumber = nextMediaPeriodHolder.info.id.windowSequenceNumber;
            } else {
                windowSequenceNumber = nextWindowSequenceNumber++;
            }
        }
        @Nullable MediaPeriodId periodId = resolveMediaPeriodIdForAds(timeline, nextPeriodUid, startPositionUs, windowSequenceNumber, window, period);
        if (contentPositionUs != C.TIME_UNSET && mediaPeriodInfo.requestedContentPositionUs != C.TIME_UNSET) {
            boolean isPrecedingPeriodAnAd = timeline.getPeriodByUid(mediaPeriodInfo.id.periodUid, period).getAdGroupCount() > 0 && period.isServerSideInsertedAdGroup(period.getRemovedAdGroupCount());
            // Handle the requested content position for period transitions within the same window.
            if (periodId.isAd() && isPrecedingPeriodAnAd) {
                // Propagate the requested position to the following ad period in the same window.
                contentPositionUs = mediaPeriodInfo.requestedContentPositionUs;
            } else if (isPrecedingPeriodAnAd) {
                // Use the requested content position of the preceding ad period as the start position.
                startPositionUs = mediaPeriodInfo.requestedContentPositionUs;
            }
        }
        return getMediaPeriodInfo(timeline, periodId, contentPositionUs, startPositionUs);
    }
    MediaPeriodId currentPeriodId = mediaPeriodInfo.id;
    timeline.getPeriodByUid(currentPeriodId.periodUid, period);
    if (currentPeriodId.isAd()) {
        int adGroupIndex = currentPeriodId.adGroupIndex;
        int adCountInCurrentAdGroup = period.getAdCountInAdGroup(adGroupIndex);
        if (adCountInCurrentAdGroup == C.LENGTH_UNSET) {
            return null;
        }
        int nextAdIndexInAdGroup = period.getNextAdIndexToPlay(adGroupIndex, currentPeriodId.adIndexInAdGroup);
        if (nextAdIndexInAdGroup < adCountInCurrentAdGroup) {
            // Play the next ad in the ad group if it's available.
            return getMediaPeriodInfoForAd(timeline, currentPeriodId.periodUid, adGroupIndex, nextAdIndexInAdGroup, mediaPeriodInfo.requestedContentPositionUs, currentPeriodId.windowSequenceNumber);
        } else {
            // Play content from the ad group position.
            long startPositionUs = mediaPeriodInfo.requestedContentPositionUs;
            if (startPositionUs == C.TIME_UNSET) {
                // If we're transitioning from an ad group to content starting from its default position,
                // project the start position forward as if this were a transition to a new window.
                @Nullable Pair<Object, Long> defaultPositionUs = timeline.getPeriodPositionUs(window, period, period.windowIndex, /* windowPositionUs= */
                C.TIME_UNSET, /* defaultPositionProjectionUs= */
                max(0, bufferedDurationUs));
                if (defaultPositionUs == null) {
                    return null;
                }
                startPositionUs = defaultPositionUs.second;
            }
            long minStartPositionUs = getMinStartPositionAfterAdGroupUs(timeline, currentPeriodId.periodUid, currentPeriodId.adGroupIndex);
            return getMediaPeriodInfoForContent(timeline, currentPeriodId.periodUid, max(minStartPositionUs, startPositionUs), mediaPeriodInfo.requestedContentPositionUs, currentPeriodId.windowSequenceNumber);
        }
    } else {
        // Play the next ad group if it's still available.
        int adIndexInAdGroup = period.getFirstAdIndexToPlay(currentPeriodId.nextAdGroupIndex);
        boolean isPlayedServerSideInsertedAd = period.isServerSideInsertedAdGroup(currentPeriodId.nextAdGroupIndex) && period.getAdState(currentPeriodId.nextAdGroupIndex, adIndexInAdGroup) == AdPlaybackState.AD_STATE_PLAYED;
        if (adIndexInAdGroup == period.getAdCountInAdGroup(currentPeriodId.nextAdGroupIndex) || isPlayedServerSideInsertedAd) {
            // The next ad group has no ads left to play or is a played SSAI ad group. Play content from
            // the end position instead.
            long startPositionUs = getMinStartPositionAfterAdGroupUs(timeline, currentPeriodId.periodUid, currentPeriodId.nextAdGroupIndex);
            return getMediaPeriodInfoForContent(timeline, currentPeriodId.periodUid, startPositionUs, /* requestedContentPositionUs= */
            mediaPeriodInfo.durationUs, currentPeriodId.windowSequenceNumber);
        }
        return getMediaPeriodInfoForAd(timeline, currentPeriodId.periodUid, currentPeriodId.nextAdGroupIndex, adIndexInAdGroup, /* contentPositionUs= */
        mediaPeriodInfo.durationUs, currentPeriodId.windowSequenceNumber);
    }
}
Also used : MediaPeriodId(com.google.android.exoplayer2.source.MediaSource.MediaPeriodId) Nullable(androidx.annotation.Nullable) Nullable(androidx.annotation.Nullable)

Example 58 with Renderer

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

the class DefaultRenderersFactory method buildVideoRenderers.

/**
 * Builds video renderers for use by the player.
 *
 * @param context The {@link Context} associated with the player.
 * @param extensionRendererMode The extension renderer mode.
 * @param mediaCodecSelector A decoder selector.
 * @param enableDecoderFallback Whether to enable fallback to lower-priority decoders if decoder
 *     initialization fails. This may result in using a decoder that is slower/less efficient than
 *     the primary decoder.
 * @param eventHandler A handler associated with the main thread's looper.
 * @param eventListener An event listener.
 * @param allowedVideoJoiningTimeMs The maximum duration for which video renderers can attempt to
 *     seamlessly join an ongoing playback, in milliseconds.
 * @param out An array to which the built renderers should be appended.
 */
protected void buildVideoRenderers(Context context, @ExtensionRendererMode int extensionRendererMode, MediaCodecSelector mediaCodecSelector, boolean enableDecoderFallback, Handler eventHandler, VideoRendererEventListener eventListener, long allowedVideoJoiningTimeMs, ArrayList<Renderer> out) {
    MediaCodecVideoRenderer videoRenderer = new MediaCodecVideoRenderer(context, getCodecAdapterFactory(), mediaCodecSelector, allowedVideoJoiningTimeMs, enableDecoderFallback, eventHandler, eventListener, MAX_DROPPED_VIDEO_FRAME_COUNT_TO_NOTIFY);
    out.add(videoRenderer);
    if (extensionRendererMode == EXTENSION_RENDERER_MODE_OFF) {
        return;
    }
    int extensionRendererIndex = out.size();
    if (extensionRendererMode == EXTENSION_RENDERER_MODE_PREFER) {
        extensionRendererIndex--;
    }
    try {
        // Full class names used for constructor args so the LINT rule triggers if any of them move.
        Class<?> clazz = Class.forName("com.google.android.exoplayer2.ext.vp9.LibvpxVideoRenderer");
        Constructor<?> constructor = clazz.getConstructor(long.class, android.os.Handler.class, com.google.android.exoplayer2.video.VideoRendererEventListener.class, int.class);
        Renderer renderer = (Renderer) constructor.newInstance(allowedVideoJoiningTimeMs, eventHandler, eventListener, MAX_DROPPED_VIDEO_FRAME_COUNT_TO_NOTIFY);
        out.add(extensionRendererIndex++, renderer);
        Log.i(TAG, "Loaded LibvpxVideoRenderer.");
    } catch (ClassNotFoundException e) {
    // Expected if the app was built without the extension.
    } catch (Exception e) {
        // The extension is present, but instantiation failed.
        throw new RuntimeException("Error instantiating VP9 extension", e);
    }
    try {
        // Full class names used for constructor args so the LINT rule triggers if any of them move.
        Class<?> clazz = Class.forName("com.google.android.exoplayer2.ext.av1.Libgav1VideoRenderer");
        Constructor<?> constructor = clazz.getConstructor(long.class, android.os.Handler.class, com.google.android.exoplayer2.video.VideoRendererEventListener.class, int.class);
        Renderer renderer = (Renderer) constructor.newInstance(allowedVideoJoiningTimeMs, eventHandler, eventListener, MAX_DROPPED_VIDEO_FRAME_COUNT_TO_NOTIFY);
        out.add(extensionRendererIndex++, renderer);
        Log.i(TAG, "Loaded Libgav1VideoRenderer.");
    } catch (ClassNotFoundException e) {
    // Expected if the app was built without the extension.
    } catch (Exception e) {
        // The extension is present, but instantiation failed.
        throw new RuntimeException("Error instantiating AV1 extension", e);
    }
}
Also used : MediaCodecVideoRenderer(com.google.android.exoplayer2.video.MediaCodecVideoRenderer) CameraMotionRenderer(com.google.android.exoplayer2.video.spherical.CameraMotionRenderer) MediaCodecAudioRenderer(com.google.android.exoplayer2.audio.MediaCodecAudioRenderer) MetadataRenderer(com.google.android.exoplayer2.metadata.MetadataRenderer) MediaCodecVideoRenderer(com.google.android.exoplayer2.video.MediaCodecVideoRenderer) TextRenderer(com.google.android.exoplayer2.text.TextRenderer)

Example 59 with Renderer

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

the class DefaultRenderersFactory method buildAudioRenderers.

/**
 * Builds audio renderers for use by the player.
 *
 * @param context The {@link Context} associated with the player.
 * @param extensionRendererMode The extension renderer mode.
 * @param mediaCodecSelector A decoder selector.
 * @param enableDecoderFallback Whether to enable fallback to lower-priority decoders if decoder
 *     initialization fails. This may result in using a decoder that is slower/less efficient than
 *     the primary decoder.
 * @param audioSink A sink to which the renderers will output.
 * @param eventHandler A handler to use when invoking event listeners and outputs.
 * @param eventListener An event listener.
 * @param out An array to which the built renderers should be appended.
 */
protected void buildAudioRenderers(Context context, @ExtensionRendererMode int extensionRendererMode, MediaCodecSelector mediaCodecSelector, boolean enableDecoderFallback, AudioSink audioSink, Handler eventHandler, AudioRendererEventListener eventListener, ArrayList<Renderer> out) {
    MediaCodecAudioRenderer audioRenderer = new MediaCodecAudioRenderer(context, getCodecAdapterFactory(), mediaCodecSelector, enableDecoderFallback, eventHandler, eventListener, audioSink);
    out.add(audioRenderer);
    if (extensionRendererMode == EXTENSION_RENDERER_MODE_OFF) {
        return;
    }
    int extensionRendererIndex = out.size();
    if (extensionRendererMode == EXTENSION_RENDERER_MODE_PREFER) {
        extensionRendererIndex--;
    }
    try {
        // Full class names used for constructor args so the LINT rule triggers if any of them move.
        Class<?> clazz = Class.forName("com.google.android.exoplayer2.ext.opus.LibopusAudioRenderer");
        Constructor<?> constructor = clazz.getConstructor(android.os.Handler.class, com.google.android.exoplayer2.audio.AudioRendererEventListener.class, com.google.android.exoplayer2.audio.AudioSink.class);
        Renderer renderer = (Renderer) constructor.newInstance(eventHandler, eventListener, audioSink);
        out.add(extensionRendererIndex++, renderer);
        Log.i(TAG, "Loaded LibopusAudioRenderer.");
    } catch (ClassNotFoundException e) {
    // Expected if the app was built without the extension.
    } catch (Exception e) {
        // The extension is present, but instantiation failed.
        throw new RuntimeException("Error instantiating Opus extension", e);
    }
    try {
        // Full class names used for constructor args so the LINT rule triggers if any of them move.
        Class<?> clazz = Class.forName("com.google.android.exoplayer2.ext.flac.LibflacAudioRenderer");
        Constructor<?> constructor = clazz.getConstructor(android.os.Handler.class, com.google.android.exoplayer2.audio.AudioRendererEventListener.class, com.google.android.exoplayer2.audio.AudioSink.class);
        Renderer renderer = (Renderer) constructor.newInstance(eventHandler, eventListener, audioSink);
        out.add(extensionRendererIndex++, renderer);
        Log.i(TAG, "Loaded LibflacAudioRenderer.");
    } catch (ClassNotFoundException e) {
    // Expected if the app was built without the extension.
    } catch (Exception e) {
        // The extension is present, but instantiation failed.
        throw new RuntimeException("Error instantiating FLAC extension", e);
    }
    try {
        // Full class names used for constructor args so the LINT rule triggers if any of them move.
        Class<?> clazz = Class.forName("com.google.android.exoplayer2.ext.ffmpeg.FfmpegAudioRenderer");
        Constructor<?> constructor = clazz.getConstructor(android.os.Handler.class, com.google.android.exoplayer2.audio.AudioRendererEventListener.class, com.google.android.exoplayer2.audio.AudioSink.class);
        Renderer renderer = (Renderer) constructor.newInstance(eventHandler, eventListener, audioSink);
        out.add(extensionRendererIndex++, renderer);
        Log.i(TAG, "Loaded FfmpegAudioRenderer.");
    } catch (ClassNotFoundException e) {
    // Expected if the app was built without the extension.
    } catch (Exception e) {
        // The extension is present, but instantiation failed.
        throw new RuntimeException("Error instantiating FFmpeg extension", e);
    }
}
Also used : MediaCodecAudioRenderer(com.google.android.exoplayer2.audio.MediaCodecAudioRenderer) CameraMotionRenderer(com.google.android.exoplayer2.video.spherical.CameraMotionRenderer) MediaCodecAudioRenderer(com.google.android.exoplayer2.audio.MediaCodecAudioRenderer) MetadataRenderer(com.google.android.exoplayer2.metadata.MetadataRenderer) MediaCodecVideoRenderer(com.google.android.exoplayer2.video.MediaCodecVideoRenderer) TextRenderer(com.google.android.exoplayer2.text.TextRenderer)

Example 60 with Renderer

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

the class ExoPlayerTest method setAndSwitchSurface.

@Test
public void setAndSwitchSurface() throws Exception {
    final List<Integer> rendererMessages = new ArrayList<>();
    Renderer videoRenderer = new FakeRenderer(C.TRACK_TYPE_VIDEO) {

        @Override
        public void handleMessage(@MessageType int messageType, @Nullable Object message) throws ExoPlaybackException {
            super.handleMessage(messageType, message);
            rendererMessages.add(messageType);
        }
    };
    ActionSchedule actionSchedule = addSurfaceSwitch(new ActionSchedule.Builder(TAG)).build();
    new ExoPlayerTestRunner.Builder(context).setRenderers(videoRenderer).setActionSchedule(actionSchedule).build().start().blockUntilActionScheduleFinished(TIMEOUT_MS).blockUntilEnded(TIMEOUT_MS);
    assertThat(Collections.frequency(rendererMessages, Renderer.MSG_SET_VIDEO_OUTPUT)).isEqualTo(2);
}
Also used : AtomicInteger(java.util.concurrent.atomic.AtomicInteger) FakeRenderer(com.google.android.exoplayer2.testutil.FakeRenderer) ActionSchedule(com.google.android.exoplayer2.testutil.ActionSchedule) TestExoPlayerBuilder(com.google.android.exoplayer2.testutil.TestExoPlayerBuilder) ArrayList(java.util.ArrayList) FakeMediaClockRenderer(com.google.android.exoplayer2.testutil.FakeMediaClockRenderer) FakeVideoRenderer(com.google.android.exoplayer2.testutil.FakeVideoRenderer) FakeRenderer(com.google.android.exoplayer2.testutil.FakeRenderer) Nullable(androidx.annotation.Nullable) 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