diff --git a/app/src/main/java/org/schabi/newpipe/player/Player.java b/app/src/main/java/org/schabi/newpipe/player/Player.java index 771827c20..3cfa74ac2 100644 --- a/app/src/main/java/org/schabi/newpipe/player/Player.java +++ b/app/src/main/java/org/schabi/newpipe/player/Player.java @@ -3293,7 +3293,8 @@ public final class Player implements if (audioPlayerSelected()) { return audioResolver.resolve(info); } else { - if (isAudioOnly && !videoResolver.isVideoStreamVideoOnly()) { + if (isAudioOnly + && !videoResolver.wasLastResolvedVideoAndAudioSeparated().orElse(false)) { return audioResolver.resolve(info); } @@ -4189,8 +4190,9 @@ public final class Player implements final boolean isVideoStreamTypeAndIsVideoOnlyStreamOrNoAudioStreamsAvailable = (streamType == StreamType.VIDEO_STREAM || streamType == StreamType.LIVE_STREAM) - && (videoResolver.isVideoStreamVideoOnly() + && (videoResolver.wasLastResolvedVideoAndAudioSeparated().orElse(false) || isNullOrEmpty(info.getAudioStreams())); + if (videoRenderIndex != RENDERER_UNAVAILABLE && isVideoStreamTypeAndIsVideoOnlyStreamOrNoAudioStreamsAvailable) { final TrackGroupArray videoTrackGroupArray = Objects.requireNonNull( diff --git a/app/src/main/java/org/schabi/newpipe/player/resolver/AudioPlaybackResolver.java b/app/src/main/java/org/schabi/newpipe/player/resolver/AudioPlaybackResolver.java index 17ecac43e..29be402c5 100644 --- a/app/src/main/java/org/schabi/newpipe/player/resolver/AudioPlaybackResolver.java +++ b/app/src/main/java/org/schabi/newpipe/player/resolver/AudioPlaybackResolver.java @@ -44,9 +44,4 @@ public class AudioPlaybackResolver implements PlaybackResolver { return buildMediaSource(dataSource, audio.getUrl(), PlayerHelper.cacheKeyOf(info, audio), MediaFormat.getSuffixById(audio.getFormatId()), tag); } - - @Override - public boolean isVideoStreamVideoOnly() { - return false; - } } diff --git a/app/src/main/java/org/schabi/newpipe/player/resolver/Resolver.java b/app/src/main/java/org/schabi/newpipe/player/resolver/Resolver.java index 8bfe34896..a3e1db5b4 100644 --- a/app/src/main/java/org/schabi/newpipe/player/resolver/Resolver.java +++ b/app/src/main/java/org/schabi/newpipe/player/resolver/Resolver.java @@ -6,6 +6,4 @@ import androidx.annotation.Nullable; public interface Resolver { @Nullable Product resolve(@NonNull Source source); - - boolean isVideoStreamVideoOnly(); } diff --git a/app/src/main/java/org/schabi/newpipe/player/resolver/VideoPlaybackResolver.java b/app/src/main/java/org/schabi/newpipe/player/resolver/VideoPlaybackResolver.java index 751ef822c..8085e4b3e 100644 --- a/app/src/main/java/org/schabi/newpipe/player/resolver/VideoPlaybackResolver.java +++ b/app/src/main/java/org/schabi/newpipe/player/resolver/VideoPlaybackResolver.java @@ -21,6 +21,7 @@ import org.schabi.newpipe.util.ListHelper; import java.util.ArrayList; import java.util.List; +import java.util.Optional; import static com.google.android.exoplayer2.C.TIME_UNSET; @@ -35,7 +36,7 @@ public class VideoPlaybackResolver implements PlaybackResolver { @Nullable private String playbackQuality; - private boolean isVideoStreamVideoOnly = false; + private Boolean wasLastResolvedVideoAndAudioSeparated; public VideoPlaybackResolver(@NonNull final Context context, @NonNull final PlayerDataSource dataSource, @@ -48,83 +49,93 @@ public class VideoPlaybackResolver implements PlaybackResolver { @Override @Nullable public MediaSource resolve(@NonNull final StreamInfo info) { - isVideoStreamVideoOnly = false; - final MediaSource liveSource = maybeBuildLiveMediaSource(dataSource, info); - if (liveSource != null) { - return liveSource; - } - - final List mediaSources = new ArrayList<>(); - - // Create video stream source - final List videos = ListHelper.getSortedStreamVideosList(context, - info.getVideoStreams(), info.getVideoOnlyStreams(), false, true); - final int index; - if (videos.isEmpty()) { - index = -1; - } else if (playbackQuality == null) { - index = qualityResolver.getDefaultResolutionIndex(videos); - } else { - index = qualityResolver.getOverrideResolutionIndex(videos, getPlaybackQuality()); - } - final MediaSourceTag tag = new MediaSourceTag(info, videos, index); - @Nullable final VideoStream video = tag.getSelectedVideoStream(); - - if (video != null) { - final MediaSource streamSource = buildMediaSource(dataSource, video.getUrl(), - PlayerHelper.cacheKeyOf(info, video), - MediaFormat.getSuffixById(video.getFormatId()), tag); - mediaSources.add(streamSource); - } - - // Create optional audio stream source - final List audioStreams = info.getAudioStreams(); - final AudioStream audio = audioStreams.isEmpty() ? null : audioStreams.get( - ListHelper.getDefaultAudioFormat(context, audioStreams)); - // Use the audio stream if there is no video stream, or - // Merge with audio stream in case if video does not contain audio - if (audio != null && (video == null || video.isVideoOnly)) { - final MediaSource audioSource = buildMediaSource(dataSource, audio.getUrl(), - PlayerHelper.cacheKeyOf(info, audio), - MediaFormat.getSuffixById(audio.getFormatId()), tag); - mediaSources.add(audioSource); - isVideoStreamVideoOnly = true; - } - - // If there is no audio or video sources, then this media source cannot be played back - if (mediaSources.isEmpty()) { - return null; - } - // Below are auxiliary media sources - - // Create subtitle sources - if (info.getSubtitles() != null) { - for (final SubtitlesStream subtitle : info.getSubtitles()) { - final String mimeType = PlayerHelper.subtitleMimeTypesOf(subtitle.getFormat()); - if (mimeType == null) { - continue; - } - final MediaSource textSource = dataSource.getSampleMediaSourceFactory() - .createMediaSource( - new MediaItem.Subtitle(Uri.parse(subtitle.getUrl()), - mimeType, - PlayerHelper.captionLanguageOf(context, subtitle)), - TIME_UNSET); - mediaSources.add(textSource); + boolean isVideoAndAudioSeparated = false; + try { + final MediaSource liveSource = maybeBuildLiveMediaSource(dataSource, info); + if (liveSource != null) { + return liveSource; } - } - if (mediaSources.size() == 1) { - return mediaSources.get(0); - } else { - return new MergingMediaSource(mediaSources.toArray( - new MediaSource[0])); + final List mediaSources = new ArrayList<>(); + + // Create video stream source + final List videos = ListHelper.getSortedStreamVideosList(context, + info.getVideoStreams(), info.getVideoOnlyStreams(), false, true); + final int index; + if (videos.isEmpty()) { + index = -1; + } else if (playbackQuality == null) { + index = qualityResolver.getDefaultResolutionIndex(videos); + } else { + index = qualityResolver.getOverrideResolutionIndex(videos, getPlaybackQuality()); + } + final MediaSourceTag tag = new MediaSourceTag(info, videos, index); + @Nullable final VideoStream video = tag.getSelectedVideoStream(); + + if (video != null) { + final MediaSource streamSource = buildMediaSource(dataSource, video.getUrl(), + PlayerHelper.cacheKeyOf(info, video), + MediaFormat.getSuffixById(video.getFormatId()), tag); + mediaSources.add(streamSource); + } + + // Create optional audio stream source + final List audioStreams = info.getAudioStreams(); + final AudioStream audio = audioStreams.isEmpty() ? null : audioStreams.get( + ListHelper.getDefaultAudioFormat(context, audioStreams)); + // Use the audio stream if there is no video stream, or + // Merge with audio stream in case if video does not contain audio + if (audio != null && (video == null || video.isVideoOnly)) { + final MediaSource audioSource = buildMediaSource(dataSource, audio.getUrl(), + PlayerHelper.cacheKeyOf(info, audio), + MediaFormat.getSuffixById(audio.getFormatId()), tag); + mediaSources.add(audioSource); + isVideoAndAudioSeparated = true; + } + + // If there is no audio or video sources, then this media source cannot be played back + if (mediaSources.isEmpty()) { + return null; + } + // Below are auxiliary media sources + + // Create subtitle sources + if (info.getSubtitles() != null) { + for (final SubtitlesStream subtitle : info.getSubtitles()) { + final String mimeType = PlayerHelper.subtitleMimeTypesOf(subtitle.getFormat()); + if (mimeType == null) { + continue; + } + final MediaSource textSource = dataSource.getSampleMediaSourceFactory() + .createMediaSource( + new MediaItem.Subtitle(Uri.parse(subtitle.getUrl()), + mimeType, + PlayerHelper.captionLanguageOf(context, subtitle)), + TIME_UNSET); + mediaSources.add(textSource); + } + } + + if (mediaSources.size() == 1) { + return mediaSources.get(0); + } else { + return new MergingMediaSource(mediaSources.toArray( + new MediaSource[0])); + } + } finally { + wasLastResolvedVideoAndAudioSeparated = isVideoAndAudioSeparated; } } - @Override - public boolean isVideoStreamVideoOnly() { - return isVideoStreamVideoOnly; + /** + * Determines if the last resolved StreamInfo had separated audio and video streams + * (or only audio). + * + * @return {@link Optional#empty()} if nothing was resolved + * otherwise true or false + */ + public Optional wasLastResolvedVideoAndAudioSeparated() { + return Optional.ofNullable(wasLastResolvedVideoAndAudioSeparated); } @Nullable