Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve audio stream selection for video-only streams in the downloader #10446

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -267,8 +267,8 @@ private void updateSecondaryStreams() {
if (!videoStreams.get(i).isVideoOnly()) {
continue;
}
final AudioStream audioStream = SecondaryStreamHelper
.getAudioStreamFor(audioStreams.getStreamsList(), videoStreams.get(i));
final AudioStream audioStream = SecondaryStreamHelper.getAudioStreamFor(
context, audioStreams.getStreamsList(), videoStreams.get(i));

if (audioStream != null) {
secondaryStreams.append(i, new SecondaryStreamHelper<>(audioStreams, audioStream));
Expand Down
14 changes: 7 additions & 7 deletions app/src/main/java/org/schabi/newpipe/util/ListHelper.java
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,10 @@ public final class ListHelper {
List.of(MediaFormat.MP3, MediaFormat.M4A, MediaFormat.WEBMA);
// Use a Set for better performance
private static final Set<String> HIGH_RESOLUTION_LIST = Set.of("1440p", "2160p");
// Audio track types in order of priotity. 0=lowest, n=highest
// Audio track types in order of priority. 0=lowest, n=highest
private static final List<AudioTrackType> AUDIO_TRACK_TYPE_RANKING =
List.of(AudioTrackType.DESCRIPTIVE, AudioTrackType.DUBBED, AudioTrackType.ORIGINAL);
// Audio track types in order of priotity when descriptive audio is preferred.
// Audio track types in order of priority when descriptive audio is preferred.
private static final List<AudioTrackType> AUDIO_TRACK_TYPE_RANKING_DESCRIPTIVE =
List.of(AudioTrackType.ORIGINAL, AudioTrackType.DUBBED, AudioTrackType.DESCRIPTIVE);

Expand Down Expand Up @@ -689,7 +689,7 @@ private static int compareVideoStreamResolution(@NonNull final String r1,
}
}

private static boolean isLimitingDataUsage(final Context context) {
static boolean isLimitingDataUsage(@NonNull final Context context) {
return getResolutionLimit(context) != null;
}

Expand Down Expand Up @@ -731,7 +731,7 @@ public static boolean isMeteredNetwork(@NonNull final Context context) {
/**
* Get a {@link Comparator} to compare {@link AudioStream}s by their format and bitrate.
*
* <p>The prefered stream will be ordered last.</p>
* <p>The preferred stream will be ordered last.</p>
*
* @param context app context
* @return Comparator
Expand All @@ -746,7 +746,7 @@ private static Comparator<AudioStream> getAudioFormatComparator(
/**
* Get a {@link Comparator} to compare {@link AudioStream}s by their format and bitrate.
*
* <p>The prefered stream will be ordered last.</p>
* <p>The preferred stream will be ordered last.</p>
*
* @param defaultFormat the default format to look for
* @param limitDataUsage choose low bitrate audio stream
Expand Down Expand Up @@ -788,7 +788,7 @@ static Comparator<AudioStream> getAudioFormatComparator(
* <li>Language is English</li>
* </ol>
*
* <p>The prefered track will be ordered last.</p>
* <p>The preferred track will be ordered last.</p>
*
* @param context App context
* @return Comparator
Expand Down Expand Up @@ -825,7 +825,7 @@ private static Comparator<AudioStream> getAudioTrackComparator(
* <li>Language is English</li>
* </ol>
*
* <p>The prefered track will be ordered last.</p>
* <p>The preferred track will be ordered last.</p>
*
* @param preferredLanguage Preferred audio stream language
* @param preferOriginalAudio Get the original audio track regardless of its language
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package org.schabi.newpipe.util;

import android.content.Context;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

Expand All @@ -9,6 +11,7 @@
import org.schabi.newpipe.extractor.stream.VideoStream;
import org.schabi.newpipe.util.StreamItemAdapter.StreamInfoWrapper;

import java.util.Comparator;
import java.util.List;

public class SecondaryStreamHelper<T extends Stream> {
Expand All @@ -25,14 +28,19 @@ public SecondaryStreamHelper(@NonNull final StreamInfoWrapper<T> streams,
}

/**
* Find the correct audio stream for the desired video stream.
* Finds an audio stream compatible with the provided video-only stream, so that the two streams
* can be combined in a single file by the downloader. If there are multiple available audio
* streams, chooses either the highest or the lowest quality one based on
* {@link ListHelper#isLimitingDataUsage(Context)}.
*
* @param context Android context
* @param audioStreams list of audio streams
* @param videoStream desired video ONLY stream
* @return selected audio stream or null if a candidate was not found
* @param videoStream desired video-ONLY stream
* @return the selected audio stream or null if a candidate was not found
*/
@Nullable
public static AudioStream getAudioStreamFor(@NonNull final List<AudioStream> audioStreams,
public static AudioStream getAudioStreamFor(@NonNull final Context context,
@NonNull final List<AudioStream> audioStreams,
@NonNull final VideoStream videoStream) {
final MediaFormat mediaFormat = videoStream.getFormat();
if (mediaFormat == null) {
Expand All @@ -41,33 +49,36 @@ public static AudioStream getAudioStreamFor(@NonNull final List<AudioStream> aud

switch (mediaFormat) {
case WEBM:
case MPEG_4:// ¿is mpeg-4 DASH?
case MPEG_4: // Is MPEG-4 DASH?
break;
default:
return null;
}

final boolean m4v = (mediaFormat == MediaFormat.MPEG_4);
final boolean m4v = mediaFormat == MediaFormat.MPEG_4;
final boolean isLimitingDataUsage = ListHelper.isLimitingDataUsage(context);

Comparator<AudioStream> comparator = ListHelper.getAudioFormatComparator(
m4v ? MediaFormat.M4A : MediaFormat.WEBMA, isLimitingDataUsage);
int preferredAudioStreamIndex = ListHelper.getAudioIndexByHighestRank(
audioStreams, comparator);

for (final AudioStream audio : audioStreams) {
if (audio.getFormat() == (m4v ? MediaFormat.M4A : MediaFormat.WEBMA)) {
return audio;
if (preferredAudioStreamIndex == -1) {
if (m4v) {
return null;
}
}

if (m4v) {
return null;
}
comparator = ListHelper.getAudioFormatComparator(
MediaFormat.WEBMA_OPUS, isLimitingDataUsage);
preferredAudioStreamIndex = ListHelper.getAudioIndexByHighestRank(
audioStreams, comparator);

// retry, but this time in reverse order
AudricV marked this conversation as resolved.
Show resolved Hide resolved
for (int i = audioStreams.size() - 1; i >= 0; i--) {
final AudioStream audio = audioStreams.get(i);
if (audio.getFormat() == MediaFormat.WEBMA_OPUS) {
return audio;
if (preferredAudioStreamIndex == -1) {
return null;
}
}

return null;
return audioStreams.get(preferredAudioStreamIndex);
}

public T getStream() {
Expand Down
Loading