-Added documentations for play queue components.

This commit is contained in:
John Zhen M 2017-09-28 19:37:04 -07:00 committed by John Zhen Mo
parent 80f3e3c3b6
commit c75c2d0f21
8 changed files with 179 additions and 34 deletions

View file

@ -27,6 +27,7 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.media.AudioManager;
import android.media.audiofx.AudioEffect;
@ -34,6 +35,7 @@ import android.net.Uri;
import android.preference.PreferenceManager;
import android.support.annotation.Nullable;
import android.text.TextUtils;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.View;
@ -70,6 +72,7 @@ import com.google.android.exoplayer2.upstream.cache.LeastRecentlyUsedCacheEvicto
import com.google.android.exoplayer2.upstream.cache.SimpleCache;
import com.google.android.exoplayer2.util.Util;
import com.nostra13.universalimageloader.core.ImageLoader;
import com.nostra13.universalimageloader.core.assist.ImageSize;
import com.nostra13.universalimageloader.core.listener.SimpleImageLoadingListener;
import org.schabi.newpipe.Downloader;

View file

@ -64,7 +64,6 @@ import org.schabi.newpipe.extractor.services.youtube.YoutubeStreamExtractor;
import org.schabi.newpipe.extractor.stream.StreamInfo;
import org.schabi.newpipe.player.old.PlayVideoActivity;
import org.schabi.newpipe.player.playback.MediaSourceManager;
import org.schabi.newpipe.playlist.PlayQueueItem;
import org.schabi.newpipe.playlist.SinglePlayQueue;
import org.schabi.newpipe.report.ErrorActivity;
import org.schabi.newpipe.report.UserAction;

View file

@ -65,6 +65,7 @@ import org.schabi.newpipe.extractor.MediaFormat;
import org.schabi.newpipe.extractor.stream.StreamInfo;
import org.schabi.newpipe.extractor.stream.VideoStream;
import org.schabi.newpipe.playlist.PlayQueue;
import org.schabi.newpipe.playlist.PlayQueueItem;
import org.schabi.newpipe.playlist.SinglePlayQueue;
import org.schabi.newpipe.util.AnimationUtils;
import org.schabi.newpipe.util.ListHelper;
@ -395,20 +396,25 @@ public abstract class VideoPlayer extends BasePlayer implements SimpleExoPlayer.
final Format format = group.getFormat(trackIndex);
final boolean isSetCurrent = selectedTrackGroup.indexOf(format) != -1;
// If the source is extracted (e.g. mp4), then we use the resolution contained in the stream
if (group.length == 1 && videoTrackGroups.length == availableStreams.size()) {
popupMenu.getMenu().add(qualityPopupMenuGroupId, acc, Menu.NONE, MediaFormat.getNameById(stream.format) + " " + stream.resolution + " (" + format.width + "x" + format.height + ")");
// If the source is non-adaptive (extractor source), then we use the resolution contained in the stream
if (isSetCurrent) qualityTextView.setText(stream.resolution);
final String menuItem = MediaFormat.getNameById(stream.format) + " " +
stream.resolution + " (" + format.width + "x" + format.height + ")";
popupMenu.getMenu().add(qualityPopupMenuGroupId, acc, Menu.NONE, menuItem);
} else {
// Otherwise, we have a DASH source, which contains multiple formats and
// Otherwise, we have an adaptive source, which contains multiple formats and
// thus have no inherent quality format
if (isSetCurrent) qualityTextView.setText(resolutionStringOf(format));
final MediaFormat mediaFormat = MediaFormat.getFromMimeType(format.sampleMimeType);
final String mediaName = mediaFormat == null ? format.sampleMimeType : mediaFormat.name;
final String resolution = resolutionStringOf(format);
popupMenu.getMenu().add(qualityPopupMenuGroupId, acc, Menu.NONE, mediaName + " " + resolution);
if (isSetCurrent) qualityTextView.setText(resolution);
final String menuItem = mediaName + " " + format.width + "x" + format.height;
popupMenu.getMenu().add(qualityPopupMenuGroupId, acc, Menu.NONE, menuItem);
}
trackGroupInfos.add(new TrackGroupInfo(trackIndex, groupIndex, MediaFormat.getNameById(stream.format), stream.resolution, format));
acc++;
}

View file

@ -19,6 +19,15 @@ import io.reactivex.disposables.Disposable;
import io.reactivex.functions.Consumer;
import io.reactivex.schedulers.Schedulers;
/**
* DeferredMediaSource is specifically designed to allow external control over when
* the source metadata are loaded while being compatible with ExoPlayer's playlists.
*
* This media source follows the structure of how NewPipeExtractor's
* {@link org.schabi.newpipe.extractor.stream.StreamInfoItem} is converted into
* {@link org.schabi.newpipe.extractor.stream.StreamInfo}. Once conversion is complete,
* this media source behaves identically as any other native media sources.
* */
public final class DeferredMediaSource implements MediaSource {
private final String TAG = "DeferredMediaSource@" + Integer.toHexString(hashCode());
@ -30,6 +39,9 @@ public final class DeferredMediaSource implements MediaSource {
public final static int STATE_DISPOSED = 3;
public interface Callback {
/**
* Player-specific MediaSource resolution from given StreamInfo.
* */
MediaSource sourceOf(final StreamInfo info);
}
@ -51,6 +63,9 @@ public final class DeferredMediaSource implements MediaSource {
this.state = STATE_INIT;
}
/**
* Parameters are kept in the class for delayed preparation.
* */
@Override
public void prepareSource(ExoPlayer exoPlayer, boolean isTopLevelSource, Listener listener) {
this.exoPlayer = exoPlayer;
@ -62,6 +77,17 @@ public final class DeferredMediaSource implements MediaSource {
return state;
}
/**
* Externally controlled loading. This method fully prepares the source to be used
* like any other native MediaSource.
*
* Ideally, this should be called after this source has entered PREPARED state and
* called once only.
*
* If loading fails here, an error will be propagated out and result in a
* {@link com.google.android.exoplayer2.ExoPlaybackException}, which is delegated
* out to the player.
* */
public synchronized void load() {
if (state != STATE_PREPARED || stream == null || loader != null) return;
Log.d(TAG, "Loading: [" + stream.getTitle() + "] with url: " + stream.getUrl());

View file

@ -60,22 +60,37 @@ public class MediaSourceManager implements DeferredMediaSource.Callback {
.subscribe(getReactor());
}
/*//////////////////////////////////////////////////////////////////////////
// DeferredMediaSource listener
//////////////////////////////////////////////////////////////////////////*/
@Override
public MediaSource sourceOf(StreamInfo info) {
return playbackListener.sourceOf(info);
}
/*//////////////////////////////////////////////////////////////////////////
// Exposed Methods
//////////////////////////////////////////////////////////////////////////*/
/*
* Returns the media source index of the currently playing stream.
* */
/**
* Returns the media source index of the currently playing stream.
* */
public int getCurrentSourceIndex() {
return sourceToQueueIndex.indexOf(playQueue.getIndex());
}
/**
* Returns the play queue index of a given media source playlist index.
* */
public int getQueueIndexOf(final int sourceIndex) {
if (sourceIndex < 0 || sourceIndex >= sourceToQueueIndex.size()) return -1;
return sourceToQueueIndex.get(sourceIndex);
}
/**
* Dispose the manager and releases all message buses and loaders.
* */
public void dispose() {
if (playQueueReactor != null) playQueueReactor.cancel();
if (syncReactor != null) syncReactor.dispose();
@ -90,6 +105,9 @@ public class MediaSourceManager implements DeferredMediaSource.Callback {
playQueue = null;
}
/**
* Loads the current playing stream and the streams within its WINDOW_SIZE bound.
* */
public void load() {
// The current item has higher priority
final int currentIndex = playQueue.getIndex();
@ -140,6 +158,7 @@ public class MediaSourceManager implements DeferredMediaSource.Callback {
remove(removeEvent.index());
break;
}
// Reset the sources if the index to remove is the current playing index
case INIT:
case REORDER:
tryBlock();
@ -249,8 +268,12 @@ public class MediaSourceManager implements DeferredMediaSource.Callback {
// Media Source List Manipulation
//////////////////////////////////////////////////////////////////////////*/
// Insert source into playlist with position in respect to the play queue
// If the play queue index already exists, then the insert is ignored
/**
* Inserts a source into {@link DynamicConcatenatingMediaSource} with position
* in respect to the play queue.
*
* If the play queue index already exists, then the insert is ignored.
* */
private void insert(final int queueIndex, final DeferredMediaSource source) {
if (queueIndex < 0) return;
@ -262,6 +285,11 @@ public class MediaSourceManager implements DeferredMediaSource.Callback {
}
}
/**
* Removes a source from {@link DynamicConcatenatingMediaSource} with the given play queue index.
*
* If the play queue index does not exist, the removal is ignored.
* */
private void remove(final int queueIndex) {
if (queueIndex < 0) return;
@ -276,9 +304,4 @@ public class MediaSourceManager implements DeferredMediaSource.Callback {
sourceToQueueIndex.set(i, sourceToQueueIndex.get(i) - 1);
}
}
@Override
public MediaSource sourceOf(StreamInfo info) {
return playbackListener.sourceOf(info);
}
}