androidx / media

Jetpack Media3 support libraries for media use cases, including ExoPlayer, an extensible media player for Android
https://developer.android.com/media/media3
Apache License 2.0
1.75k stars 417 forks source link

Track display issues in PlayerView with adaptive audio and text tracks from HLS #1666

Open JaroslavHerber opened 3 months ago

JaroslavHerber commented 3 months ago

By default, if a m3u channel has subtitles, the exoplayer selects and displays automatically the first subtitle. Why not "off" by default? There should be a method to turn off this default behavior, without hacking the DefaultTrackSelector.

Btw. I tried this, but the player still displays the first subtitle track by default. What am I missing?

DefaultTrackSelector oTrackSelector = new DefaultTrackSelector(this);

DefaultTrackSelector.Parameters parameters = oTrackSelector
    .buildUponParameters()
    .setPreferredTextLanguage(null) // This ensures no text track is selected by default
    .setSelectUndeterminedTextLanguage(false) // Do not select any text track if the language is undetermined
    .build();

oTrackSelector.setParameters(parameters);

oPlayer = new ExoPlayer.Builder(this, oRenderersFactory)
    .setTrackSelector(oTrackSelector)
    .setMediaSourceFactory(oMediaSourceFactory)
    .build();
tonihei commented 3 months ago

It's likely that the subtitle you see is 'on' by default because it's marked as 'forced' or similar by the media itself and turning it on is following the spec. If you share the stream you are trying to play, we can have a look and see if there is a setting to turn off the behavior. It's likely https://developer.android.com/reference/androidx/media3/common/TrackSelectionParameters.Builder#setIgnoredTextSelectionFlags(int) can help with ignoring the forced flags.

JaroslavHerber commented 3 months ago

Thank you very much :)

Here is the public stream:

#EXTINF:-1 tvg-id="HR.de" tvg-name="HRFernsehen.de" status="timeout" group-title="HR",hr-fernsehen (1080p)
https://hrhls.akamaized.net/hls/live/2024525/hrhls/index.m3u8

(The video might show geo-blocking hint, but the subtitles are still working in this channel)

I also noticed, that every track (subtitles or audio) are displayed twice or more in the selector. The audio tracks are confusing: image

tonihei commented 3 months ago

Thanks for sharing the stream.

The HLS playlist has DEFAULT=YES for both subtitle tracks and according to the HLS spec: "If the value is YES, then the client SHOULD play this Rendition of the content in the absence of information from the user indicating a different choice."

So selecting this track by default without user interaction is technically correct. If you don't want this and control the content creation, I'd suggest to fix the playlist file itself. Using TrackSelectionParameters.Builder.setIgnoredTextSelectionFlags(C.SELECTION_FLAG_DEFAULT) also works as expected by ignoring this flag in the media.

I also noticed, that every track (subtitles or audio) are displayed twice or more in the selector. The audio tracks are confusing

There seem to be a few things going on here:

I'll mark this issue as a bug for these issues, the main question around showing the subtitles by default is working as intended for this playlist as explained above.

JaroslavHerber commented 3 weeks ago
  • The audio track name provider is not using the NAME tag provided by the playlist that help to distinguish them (e.g. "Klare Sprache")

I think the issue here is the priority of languageAndRole over Label in DefaultTrackNameProvider.buildLanguageOrLabelString(Format format)

private String buildLanguageOrLabelString(Format format) {
    String languageAndRole =
        joinWithSeparator(buildLanguageString(format), buildRoleString(format));
    return TextUtils.isEmpty(languageAndRole) ? buildLabelString(format) : languageAndRole;
  }

So the label is only used if languageAndRole is empty. Maybe we can mix languageAndRole and Label? The current logic with languageAndRole is sure the best choice if the channel offers different language-AudioTracks. But in the upper case we have just one language (German) with some variation-AudioTracks.

If me mix them, we can get this: image

Here is the code:

private String buildLanguageOrLabelString(Format format) {
    String Label = buildLabelString(format);
    String Language = buildLanguageString(format);
    String Role = buildRoleString(format);

    String languageAndRole = Role;
    if( !Label.equals(Language) ) {
      languageAndRole = joinWithSeparator(Language, Role);
    }

    String returnString = Label;
    if( !TextUtils.isEmpty(languageAndRole) ) {
      returnString += " (" + languageAndRole + ")";
    }

    return returnString;
  }