private void createViews() { mediaDataSourceFactory = buildDataSourceFactory(true); mainHandler = new Handler(); window = new Timeline.Window(); if (CookieHandler.getDefault() != DEFAULT_COOKIE_MANAGER) { CookieHandler.setDefault(DEFAULT_COOKIE_MANAGER); } LayoutParams layoutParams = new LayoutParams( LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); exoPlayerView = new ExoPlayerView(getContext()); exoPlayerView.setLayoutParams(layoutParams); addView(exoPlayerView, 0, layoutParams); }
private void releasePlayer() { if (player != null) { isPaused = player.getPlayWhenReady(); shouldRestorePosition = false; playerWindow = player.getCurrentWindowIndex(); playerPosition = C.TIME_UNSET; Timeline timeline = player.getCurrentTimeline(); if (!timeline.isEmpty() && timeline.getWindow(playerWindow, window).isSeekable) { playerPosition = player.getCurrentPosition(); } player.release(); player = null; trackSelector = null; } progressHandler.removeMessages(SHOW_PROGRESS); themedReactContext.removeLifecycleEventListener(this); audioBecomingNoisyReceiver.removeListener(); }
/** * Creates a new IMA ads loader. * * @param context The context. * @param adTagUri The {@link Uri} of an ad tag compatible with the Android IMA SDK. See * https://developers.google.com/interactive-media-ads/docs/sdks/android/compatibility for * more information. * @param imaSdkSettings {@link ImaSdkSettings} used to configure the IMA SDK, or {@code null} to * use the default settings. If set, the player type and version fields may be overwritten. */ public ImaAdsLoader(Context context, Uri adTagUri, ImaSdkSettings imaSdkSettings) { this.adTagUri = adTagUri; period = new Timeline.Period(); adCallbacks = new ArrayList<>(1); imaSdkFactory = ImaSdkFactory.getInstance(); adDisplayContainer = imaSdkFactory.createAdDisplayContainer(); adDisplayContainer.setPlayer(this); if (imaSdkSettings == null) { imaSdkSettings = imaSdkFactory.createImaSdkSettings(); } imaSdkSettings.setPlayerType(IMA_SDK_SETTINGS_PLAYER_TYPE); imaSdkSettings.setPlayerVersion(IMA_SDK_SETTINGS_PLAYER_VERSION); adsLoader = imaSdkFactory.createAdsLoader(context, imaSdkSettings); adsLoader.addAdErrorListener(this); adsLoader.addAdsLoadedListener(this); fakeContentProgressElapsedRealtimeMs = C.TIME_UNSET; fakeContentProgressOffsetMs = C.TIME_UNSET; pendingContentPositionMs = C.TIME_UNSET; adGroupIndex = C.INDEX_UNSET; contentDurationMs = C.TIME_UNSET; }
private void updateNavigation() { if (!isVisible() || !isAttachedToWindow) { return; } Timeline timeline = player != null ? player.getCurrentTimeline() : null; boolean haveNonEmptyTimeline = timeline != null && !timeline.isEmpty(); boolean isSeekable = false; boolean enablePrevious = false; boolean enableNext = false; if (haveNonEmptyTimeline && !player.isPlayingAd()) { int windowIndex = player.getCurrentWindowIndex(); timeline.getWindow(windowIndex, window); isSeekable = window.isSeekable; enablePrevious = isSeekable || !window.isDynamic || player.getPreviousWindowIndex() != C.INDEX_UNSET; enableNext = window.isDynamic || player.getNextWindowIndex() != C.INDEX_UNSET; } setButtonEnabled(enablePrevious, previousButton); setButtonEnabled(enableNext, nextButton); setButtonEnabled(fastForwardMs > 0 && isSeekable, fastForwardButton); setButtonEnabled(rewindMs > 0 && isSeekable, rewindButton); if (timeBar != null) { timeBar.setEnabled(isSeekable); } }
public void previous() { Timeline timeline = player.getCurrentTimeline(); if (timeline.isEmpty()) { return; } int windowIndex = player.getCurrentWindowIndex(); timeline.getWindow(windowIndex, window); int previousWindowIndex = player.getPreviousWindowIndex(); if (previousWindowIndex != C.INDEX_UNSET && (player.getCurrentPosition() <= MAX_POSITION_FOR_SEEK_TO_PREVIOUS || (window.isDynamic && !window.isSeekable))) { seekTo(previousWindowIndex, C.TIME_UNSET); } else { seekTo(0); } }
private void seekToTimeBarPosition(long positionMs) { int windowIndex; Timeline timeline = player.getCurrentTimeline(); if (multiWindowTimeBar && !timeline.isEmpty()) { int windowCount = timeline.getWindowCount(); windowIndex = 0; while (true) { long windowDurationMs = timeline.getWindow(windowIndex, window).getDurationMs(); if (positionMs < windowDurationMs) { break; } else if (windowIndex == windowCount - 1) { // Seeking past the end of the last window should seek to the end of the timeline. positionMs = windowDurationMs; break; } positionMs -= windowDurationMs; windowIndex++; } } else { windowIndex = player.getCurrentWindowIndex(); } seekTo(windowIndex, positionMs); }
/** * 上一首 */ private void previous() { Timeline timeline = player.getCurrentTimeline(); if (timeline.isEmpty()) { return; } int windowIndex = player.getCurrentWindowIndex(); timeline.getWindow(windowIndex, window); int previousWindowIndex = timeline.getPreviousWindowIndex(windowIndex, player.getRepeatMode()); Timber.e("previousWindowIndex:" + previousWindowIndex); Timber.e("getCurrentPosition:" + player.getCurrentPosition()); Timber.e("isDynamic:" + window.isDynamic); Timber.e("isSeekable:" + window.isSeekable); Timber.e("TIME_UNSET:" + C.TIME_UNSET); Timber.e("TIME_UNSET:" + C.TIME_UNSET); if (previousWindowIndex != C.INDEX_UNSET) { player.seekTo(previousWindowIndex, C.TIME_UNSET); } else { Timber.e("seekTo(0):"); Timber.e("已经是第一首"); // player.seekTo(0); } }
/** * 下一首 */ private void next() { Timeline timeline = player.getCurrentTimeline(); if (timeline.isEmpty()) { return; } int windowIndex = player.getCurrentWindowIndex(); Timber.e("windowIndex:" + windowIndex); int nextWindowIndex = timeline.getNextWindowIndex(windowIndex, player.getRepeatMode()); Timber.e("nextWindowIndex:" + nextWindowIndex); Timber.e("isDynamic:" + window.isDynamic); Timber.e("TIME_UNSET:" + C.TIME_UNSET); if (nextWindowIndex != C.INDEX_UNSET) { player.seekTo(nextWindowIndex, C.TIME_UNSET); } else if (timeline.getWindow(windowIndex, window, false).isDynamic) { player.seekTo(windowIndex, C.TIME_UNSET); Timber.e("已经最后一首"); } }
@Override public void onTimelineChanged(Timeline timeline, Object manifest) { int periodCount = timeline.getPeriodCount(); int windowCount = timeline.getWindowCount(); Log.d(TAG, "sourceInfo [periodCount=" + periodCount + ", windowCount=" + windowCount); for (int i = 0; i < Math.min(periodCount, MAX_TIMELINE_ITEM_LINES); i++) { timeline.getPeriod(i, period); Log.d(TAG, " " + "period [" + getTimeString(period.getDurationMs()) + "]"); } if (periodCount > MAX_TIMELINE_ITEM_LINES) { Log.d(TAG, " ..."); } for (int i = 0; i < Math.min(windowCount, MAX_TIMELINE_ITEM_LINES); i++) { timeline.getWindow(i, window); Log.d(TAG, " " + "window [" + getTimeString(window.getDurationMs()) + ", " + window.isSeekable + ", " + window.isDynamic + "]"); } if (windowCount > MAX_TIMELINE_ITEM_LINES) { Log.d(TAG, " ..."); } Log.d(TAG, "]"); }
@Override public void onTimelineChanged(Timeline timeline, Object manifest) { if (timeline == null) { return; } int periodCount = timeline.getPeriodCount(); int windowCount = timeline.getWindowCount(); Log.d(TAG, "sourceInfo [periodCount=" + periodCount + ", windowCount=" + windowCount); for (int i = 0; i < Math.min(periodCount, MAX_TIMELINE_ITEM_LINES); i++) { timeline.getPeriod(i, period); Log.d(TAG, " " + "period [" + getTimeString(period.getDurationMs()) + "]"); } if (periodCount > MAX_TIMELINE_ITEM_LINES) { Log.d(TAG, " ..."); } for (int i = 0; i < Math.min(windowCount, MAX_TIMELINE_ITEM_LINES); i++) { timeline.getWindow(i, window); Log.d(TAG, " " + "window [" + getTimeString(window.getDurationMs()) + ", " + window.isSeekable + ", " + window.isDynamic + "]"); } if (windowCount > MAX_TIMELINE_ITEM_LINES) { Log.d(TAG, " ..."); } Log.d(TAG, "]"); }
/** * Creates a new clipping timeline that wraps the specified timeline. * * @param timeline The timeline to clip. * @param startUs The number of microseconds to clip from the start of {@code timeline}. * @param endUs The end position in microseconds for the clipped timeline relative to the start * of {@code timeline}, or {@link C#TIME_END_OF_SOURCE} to clip no samples from the end. */ public ClippingTimeline(Timeline timeline, long startUs, long endUs) { Assertions.checkArgument(timeline.getWindowCount() == 1); Assertions.checkArgument(timeline.getPeriodCount() == 1); Window window = timeline.getWindow(0, new Window(), false); Assertions.checkArgument(!window.isDynamic); long resolvedEndUs = endUs == C.TIME_END_OF_SOURCE ? window.durationUs : endUs; if (window.durationUs != C.TIME_UNSET) { Assertions.checkArgument(startUs == 0 || window.isSeekable); Assertions.checkArgument(resolvedEndUs <= window.durationUs); Assertions.checkArgument(startUs <= resolvedEndUs); } Period period = timeline.getPeriod(0, new Period()); Assertions.checkArgument(period.getPositionInWindowUs() == 0); this.timeline = timeline; this.startUs = startUs; this.endUs = resolvedEndUs; }
public LoopingTimeline(Timeline childTimeline, int loopCount) { this.childTimeline = childTimeline; childPeriodCount = childTimeline.getPeriodCount(); childWindowCount = childTimeline.getWindowCount(); // This is the maximum number of loops that can be performed without exceeding // MAX_EXPOSED_PERIODS periods. int maxLoopCount = MAX_EXPOSED_PERIODS / childPeriodCount; if (loopCount > maxLoopCount) { if (loopCount != Integer.MAX_VALUE) { Log.w(TAG, "Capped loops to avoid overflow: " + loopCount + " -> " + maxLoopCount); } this.loopCount = maxLoopCount; } else { this.loopCount = loopCount; } }
private void handleSourceInfoRefreshed(int sourceFirstIndex, Timeline sourceTimeline, Object sourceManifest) { // Set the timeline and manifest. timelines[sourceFirstIndex] = sourceTimeline; manifests[sourceFirstIndex] = sourceManifest; // Also set the timeline and manifest for any duplicate entries of the same source. for (int i = sourceFirstIndex + 1; i < mediaSources.length; i++) { if (mediaSources[i] == mediaSources[sourceFirstIndex]) { timelines[i] = sourceTimeline; manifests[i] = sourceManifest; } } for (Timeline timeline : timelines) { if (timeline == null) { // Don't invoke the listener until all sources have timelines. return; } } timeline = new ConcatenatedTimeline(timelines.clone()); listener.onSourceInfoRefreshed(timeline, manifests.clone()); }
public ConcatenatedTimeline(Timeline[] timelines) { int[] sourcePeriodOffsets = new int[timelines.length]; int[] sourceWindowOffsets = new int[timelines.length]; long periodCount = 0; int windowCount = 0; for (int i = 0; i < timelines.length; i++) { Timeline timeline = timelines[i]; periodCount += timeline.getPeriodCount(); Assertions.checkState(periodCount <= Integer.MAX_VALUE, "ConcatenatingMediaSource children contain too many periods"); sourcePeriodOffsets[i] = (int) periodCount; windowCount += timeline.getWindowCount(); sourceWindowOffsets[i] = windowCount; } this.timelines = timelines; this.sourcePeriodOffsets = sourcePeriodOffsets; this.sourceWindowOffsets = sourceWindowOffsets; }
private void handleSourceInfoRefreshed(int sourceIndex, Timeline timeline, Object manifest) { if (mergeError == null) { mergeError = checkTimelineMerges(timeline); } if (mergeError != null) { return; } pendingTimelineSources.remove(mediaSources[sourceIndex]); if (sourceIndex == 0) { primaryTimeline = timeline; primaryManifest = manifest; } if (pendingTimelineSources.isEmpty()) { listener.onSourceInfoRefreshed(primaryTimeline, primaryManifest); } }
private void releasePlayer() { if (player != null) { debugViewHelper.stop(); debugViewHelper = null; shouldAutoPlay = player.getPlayWhenReady(); playerWindow = player.getCurrentWindowIndex(); playerPosition = C.TIME_UNSET; Timeline timeline = player.getCurrentTimeline(); if (!timeline.isEmpty() && timeline.getWindow(playerWindow, window).isSeekable) { playerPosition = player.getCurrentPosition(); } player.release(); player = null; trackSelector = null; trackSelectionHelper = null; eventLogger = null; } }
public void pause() { if (player == null) { return; } if (player.getPlayWhenReady()) { Timeline currentTimeline = player.getCurrentTimeline(); boolean haveNonEmptyTimeline = currentTimeline != null && !currentTimeline.isEmpty(); if (haveNonEmptyTimeline && currentTimeline.getWindow(playerWindow, window).isSeekable) { playerPosition = player.getCurrentPosition(); } player.setPlayWhenReady(false); isPauseFromUser = false; } else { isPauseFromUser = true; } }
@Override public void onTimelineChanged(Timeline timeline, Object manifest) { isTimelineStatic = !timeline.isEmpty() && !timeline.getWindow(timeline.getWindowCount() - 1, window).isDynamic; if (manifest instanceof HlsManifest) { HlsManifest hlsManifest = (HlsManifest) manifest; isHls = !hlsManifest.mediaPlaylist.hasEndTag && hlsManifest.mediaPlaylist.playlistType == HlsMediaPlaylist.PLAYLIST_TYPE_UNKNOWN; Log.e("time->",stringForTime(hlsManifest.mediaPlaylist.startOffsetUs)); } updateNavigation(); updateProgress(); }
private void updateNavigation() { if (!isVisible() || !isAttachedToWindow) { return; } Timeline currentTimeline = player != null ? player.getCurrentTimeline() : null; boolean haveNonEmptyTimeline = currentTimeline != null && !currentTimeline.isEmpty(); boolean isSeekable = false; boolean enablePrevious = false; boolean enableNext = false; if (haveNonEmptyTimeline) { int currentWindowIndex = player.getCurrentWindowIndex(); currentTimeline.getWindow(currentWindowIndex, currentWindow); isSeekable = currentWindow.isSeekable; enablePrevious = currentWindowIndex > 0 || isSeekable || !currentWindow.isDynamic; enableNext = (currentWindowIndex < currentTimeline.getWindowCount() - 1) || currentWindow.isDynamic; } setButtonEnabled(enablePrevious , previousButton); setButtonEnabled(enableNext, nextButton); setButtonEnabled(fastForwardMs > 0 && isSeekable, fastForwardButton); setButtonEnabled(rewindMs > 0 && isSeekable, rewindButton); if (progressBar != null) { progressBar.setEnabled(isSeekable); } }
public ConcatenatedTimeline(Timeline[] timelines) { int[] sourcePeriodOffsets = new int[timelines.length]; int[] sourceWindowOffsets = new int[timelines.length]; int periodCount = 0; int windowCount = 0; for (int i = 0; i < timelines.length; i++) { Timeline timeline = timelines[i]; periodCount += timeline.getPeriodCount(); sourcePeriodOffsets[i] = periodCount; windowCount += timeline.getWindowCount(); sourceWindowOffsets[i] = windowCount; } this.timelines = timelines; this.sourcePeriodOffsets = sourcePeriodOffsets; this.sourceWindowOffsets = sourceWindowOffsets; }
private void updateNavigation() { if (!isVisible() || !isAttachedToWindow) { return; } Timeline currentTimeline = player != null ? player.getCurrentTimeline() : null; boolean haveTimeline = currentTimeline != null; boolean isSeekable = false; boolean enablePrevious = false; boolean enableNext = false; if (haveTimeline) { int currentWindowIndex = player.getCurrentWindowIndex(); currentTimeline.getWindow(currentWindowIndex, currentWindow); isSeekable = currentWindow.isSeekable; enablePrevious = currentWindowIndex > 0 || isSeekable || !currentWindow.isDynamic; enableNext = (currentWindowIndex < currentTimeline.getWindowCount() - 1) || currentWindow.isDynamic; } setButtonEnabled(enablePrevious , previousButton); setButtonEnabled(enableNext, nextButton); setButtonEnabled(fastForwardMs > 0 && isSeekable, fastForwardButton); setButtonEnabled(rewindMs > 0 && isSeekable, rewindButton); progressBar.setEnabled(isSeekable); }
private void updateNavigation() { if (!isVisible() || !isAttachedToWindow) { return; } Timeline currentTimeline = player != null ? player.getCurrentTimeline() : null; boolean haveTimeline = currentTimeline != null; boolean isSeekable = false; boolean enablePrevious = false; boolean enableNext = false; if (haveTimeline) { int currentWindowIndex = player.getCurrentWindowIndex(); currentTimeline.getWindow(currentWindowIndex, currentWindow); isSeekable = currentWindow.isSeekable; enablePrevious = currentWindowIndex > 0 || isSeekable || !currentWindow.isDynamic; enableNext = (currentWindowIndex < currentTimeline.getWindowCount() - 1) || currentWindow.isDynamic; } // setButtonEnabled(enablePrevious , previousButton); // setButtonEnabled(enableNext, nextButton); // setButtonEnabled(fastForwardMs > 0 && isSeekable, fastForwardButton); // setButtonEnabled(rewindMs > 0 && isSeekable, rewindButton); progressBar.setEnabled(isSeekable); }
@Override public void onTimelineChanged(Timeline timeline, Object manifest) { if (timeline.isEmpty()) { // The player is being re-prepared and this source will be released. return; } Assertions.checkArgument(timeline.getPeriodCount() == 1); this.timeline = timeline; long contentDurationUs = timeline.getPeriod(0, period).durationUs; contentDurationMs = C.usToMs(contentDurationUs); if (contentDurationUs != C.TIME_UNSET) { adPlaybackState.contentDurationUs = contentDurationUs; } updateImaStateForPlayerState(); }
@Override public void onTimelineChanged(Timeline timeline, Object manifest) { //为了兼容广告视频和多分辨设置 if (isSwitch) { isSwitch = false; isRemove = true; player.seekTo(player.getNextWindowIndex(), resumePosition); } }
public void next() { Timeline timeline = player.getCurrentTimeline(); if (timeline.isEmpty()) { return; } int windowIndex = player.getCurrentWindowIndex(); int nextWindowIndex = player.getNextWindowIndex(); if (nextWindowIndex != C.INDEX_UNSET) { seekTo(nextWindowIndex, C.TIME_UNSET); } else if (timeline.getWindow(windowIndex, window, false).isDynamic) { seekTo(windowIndex, C.TIME_UNSET); } }
/** * Returns whether the specified {@code timeline} can be shown on a multi-window time bar. * * @param timeline The {@link Timeline} to check. * @param window A scratch {@link Timeline.Window} instance. * @return Whether the specified timeline can be shown on a multi-window time bar. */ private static boolean canShowMultiWindowTimeBar(Timeline timeline, Timeline.Window window) { if (timeline.getWindowCount() > MAX_WINDOWS_FOR_MULTI_WINDOW_TIME_BAR) { return false; } int windowCount = timeline.getWindowCount(); for (int i = 0; i < windowCount; i++) { if (timeline.getWindow(i, window).durationUs == C.TIME_UNSET) { return false; } } return true; }
@Override public void onTimelineChanged(Timeline timeline, Object manifest) { updateNavigation(); updateTimeBarMode(); updateProgress(); Log.d(TAG, "onTimelineChanged:"); }
@Override public void onSourceInfoRefreshed(Timeline timeline, Object manifest) { clippingTimeline = new ClippingTimeline(timeline, startUs, endUs); sourceListener.onSourceInfoRefreshed(clippingTimeline, manifest); long startUs = clippingTimeline.startUs; long endUs = clippingTimeline.endUs == C.TIME_UNSET ? C.TIME_END_OF_SOURCE : clippingTimeline.endUs; int count = mediaPeriods.size(); for (int i = 0; i < count; i++) { mediaPeriods.get(i).setClipping(startUs, endUs); } }
@Override public void prepareSource(ExoPlayer player, boolean isTopLevelSource, final Listener listener) { childSource.prepareSource(player, false, new Listener() { @Override public void onSourceInfoRefreshed(Timeline timeline, Object manifest) { childPeriodCount = timeline.getPeriodCount(); listener.onSourceInfoRefreshed(new LoopingTimeline(timeline, loopCount), manifest); } }); }
/** * @param mediaSources The {@link MediaSource}s to concatenate. It is valid for the same * {@link MediaSource} instance to be present more than once in the array. */ public ConcatenatingMediaSource(MediaSource... mediaSources) { this.mediaSources = mediaSources; timelines = new Timeline[mediaSources.length]; manifests = new Object[mediaSources.length]; sourceIndexByMediaPeriod = new HashMap<>(); duplicateFlags = buildDuplicateFlags(mediaSources); }
@Override public void prepareSource(ExoPlayer player, boolean isTopLevelSource, Listener listener) { this.listener = listener; for (int i = 0; i < mediaSources.length; i++) { if (!duplicateFlags[i]) { final int index = i; mediaSources[i].prepareSource(player, false, new Listener() { @Override public void onSourceInfoRefreshed(Timeline timeline, Object manifest) { handleSourceInfoRefreshed(index, timeline, manifest); } }); } } }