Merge pull request #10446 from AudricV/dl_improve_video_audio_stream_selection

Improve audio stream selection for video-only streams in the downloader
This commit is contained in:
Stypox 2023-12-07 16:48:57 +01:00 committed by GitHub
commit e784af3e2d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 42 additions and 31 deletions

View File

@ -267,8 +267,8 @@ public class DownloadDialog extends DialogFragment
if (!videoStreams.get(i).isVideoOnly()) { if (!videoStreams.get(i).isVideoOnly()) {
continue; continue;
} }
final AudioStream audioStream = SecondaryStreamHelper final AudioStream audioStream = SecondaryStreamHelper.getAudioStreamFor(
.getAudioStreamFor(audioStreams.getStreamsList(), videoStreams.get(i)); context, audioStreams.getStreamsList(), videoStreams.get(i));
if (audioStream != null) { if (audioStream != null) {
secondaryStreams.append(i, new SecondaryStreamHelper<>(audioStreams, audioStream)); secondaryStreams.append(i, new SecondaryStreamHelper<>(audioStreams, audioStream));

View File

@ -46,10 +46,10 @@ public final class ListHelper {
List.of(MediaFormat.MP3, MediaFormat.M4A, MediaFormat.WEBMA); List.of(MediaFormat.MP3, MediaFormat.M4A, MediaFormat.WEBMA);
// Use a Set for better performance // Use a Set for better performance
private static final Set<String> HIGH_RESOLUTION_LIST = Set.of("1440p", "2160p"); 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 = private static final List<AudioTrackType> AUDIO_TRACK_TYPE_RANKING =
List.of(AudioTrackType.DESCRIPTIVE, AudioTrackType.DUBBED, AudioTrackType.ORIGINAL); 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 = private static final List<AudioTrackType> AUDIO_TRACK_TYPE_RANKING_DESCRIPTIVE =
List.of(AudioTrackType.ORIGINAL, AudioTrackType.DUBBED, AudioTrackType.DESCRIPTIVE); List.of(AudioTrackType.ORIGINAL, AudioTrackType.DUBBED, AudioTrackType.DESCRIPTIVE);
@ -696,7 +696,7 @@ public final class ListHelper {
} }
} }
private static boolean isLimitingDataUsage(final Context context) { static boolean isLimitingDataUsage(@NonNull final Context context) {
return getResolutionLimit(context) != null; return getResolutionLimit(context) != null;
} }
@ -738,7 +738,7 @@ public final class ListHelper {
/** /**
* Get a {@link Comparator} to compare {@link AudioStream}s by their format and bitrate. * 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 * @param context app context
* @return Comparator * @return Comparator
@ -753,7 +753,7 @@ public final class ListHelper {
/** /**
* Get a {@link Comparator} to compare {@link AudioStream}s by their format and bitrate. * 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 defaultFormat the default format to look for
* @param limitDataUsage choose low bitrate audio stream * @param limitDataUsage choose low bitrate audio stream
@ -795,7 +795,7 @@ public final class ListHelper {
* <li>Language is English</li> * <li>Language is English</li>
* </ol> * </ol>
* *
* <p>The prefered track will be ordered last.</p> * <p>The preferred track will be ordered last.</p>
* *
* @param context App context * @param context App context
* @return Comparator * @return Comparator
@ -832,7 +832,7 @@ public final class ListHelper {
* <li>Language is English</li> * <li>Language is English</li>
* </ol> * </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 preferredLanguage Preferred audio stream language
* @param preferOriginalAudio Get the original audio track regardless of its language * @param preferOriginalAudio Get the original audio track regardless of its language

View File

@ -1,5 +1,7 @@
package org.schabi.newpipe.util; package org.schabi.newpipe.util;
import android.content.Context;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
@ -9,6 +11,7 @@ import org.schabi.newpipe.extractor.stream.Stream;
import org.schabi.newpipe.extractor.stream.VideoStream; import org.schabi.newpipe.extractor.stream.VideoStream;
import org.schabi.newpipe.util.StreamItemAdapter.StreamInfoWrapper; import org.schabi.newpipe.util.StreamItemAdapter.StreamInfoWrapper;
import java.util.Comparator;
import java.util.List; import java.util.List;
public class SecondaryStreamHelper<T extends Stream> { public class SecondaryStreamHelper<T extends Stream> {
@ -25,14 +28,19 @@ public class SecondaryStreamHelper<T extends Stream> {
} }
/** /**
* 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 audioStreams list of audio streams
* @param videoStream desired video ONLY stream * @param videoStream desired video-ONLY stream
* @return selected audio stream or null if a candidate was not found * @return the selected audio stream or null if a candidate was not found
*/ */
@Nullable @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) { @NonNull final VideoStream videoStream) {
final MediaFormat mediaFormat = videoStream.getFormat(); final MediaFormat mediaFormat = videoStream.getFormat();
if (mediaFormat == null) { if (mediaFormat == null) {
@ -41,33 +49,36 @@ public class SecondaryStreamHelper<T extends Stream> {
switch (mediaFormat) { switch (mediaFormat) {
case WEBM: case WEBM:
case MPEG_4:// ¿is mpeg-4 DASH? case MPEG_4: // Is MPEG-4 DASH?
break; break;
default: default:
return null; return null;
} }
final boolean m4v = (mediaFormat == MediaFormat.MPEG_4); final boolean m4v = mediaFormat == MediaFormat.MPEG_4;
final boolean isLimitingDataUsage = ListHelper.isLimitingDataUsage(context);
for (final AudioStream audio : audioStreams) { Comparator<AudioStream> comparator = ListHelper.getAudioFormatComparator(
if (audio.getFormat() == (m4v ? MediaFormat.M4A : MediaFormat.WEBMA)) { m4v ? MediaFormat.M4A : MediaFormat.WEBMA, isLimitingDataUsage);
return audio; int preferredAudioStreamIndex = ListHelper.getAudioIndexByHighestRank(
audioStreams, comparator);
if (preferredAudioStreamIndex == -1) {
if (m4v) {
return null;
}
comparator = ListHelper.getAudioFormatComparator(
MediaFormat.WEBMA_OPUS, isLimitingDataUsage);
preferredAudioStreamIndex = ListHelper.getAudioIndexByHighestRank(
audioStreams, comparator);
if (preferredAudioStreamIndex == -1) {
return null;
} }
} }
if (m4v) { return audioStreams.get(preferredAudioStreamIndex);
return null;
}
// retry, but this time in reverse order
for (int i = audioStreams.size() - 1; i >= 0; i--) {
final AudioStream audio = audioStreams.get(i);
if (audio.getFormat() == MediaFormat.WEBMA_OPUS) {
return audio;
}
}
return null;
} }
public T getStream() { public T getStream() {