Merge pull request #8150 from karyogamy/caption-fix
Fix caption auto-selection not reflected in player GUI
This commit is contained in:
commit
3fb5073feb
3 changed files with 74 additions and 53 deletions
|
@ -62,7 +62,6 @@ import static org.schabi.newpipe.player.helper.PlayerHelper.savePlaybackParamete
|
|||
import static org.schabi.newpipe.util.ListHelper.getPopupResolutionIndex;
|
||||
import static org.schabi.newpipe.util.ListHelper.getResolutionIndex;
|
||||
import static org.schabi.newpipe.util.Localization.assureCorrectAppLanguage;
|
||||
import static org.schabi.newpipe.util.Localization.containsCaseInsensitive;
|
||||
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
||||
|
||||
import android.animation.Animator;
|
||||
|
@ -130,6 +129,7 @@ import androidx.recyclerview.widget.RecyclerView;
|
|||
import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.DefaultRenderersFactory;
|
||||
import com.google.android.exoplayer2.ExoPlayer;
|
||||
import com.google.android.exoplayer2.Format;
|
||||
import com.google.android.exoplayer2.PlaybackException;
|
||||
import com.google.android.exoplayer2.PlaybackParameters;
|
||||
import com.google.android.exoplayer2.Player.PositionInfo;
|
||||
|
@ -137,8 +137,6 @@ import com.google.android.exoplayer2.RenderersFactory;
|
|||
import com.google.android.exoplayer2.Timeline;
|
||||
import com.google.android.exoplayer2.TracksInfo;
|
||||
import com.google.android.exoplayer2.source.MediaSource;
|
||||
import com.google.android.exoplayer2.source.TrackGroup;
|
||||
import com.google.android.exoplayer2.source.TrackGroupArray;
|
||||
import com.google.android.exoplayer2.text.Cue;
|
||||
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector;
|
||||
import com.google.android.exoplayer2.trackselection.MappingTrackSelector;
|
||||
|
@ -212,7 +210,6 @@ import org.schabi.newpipe.util.external_communication.ShareUtils;
|
|||
import org.schabi.newpipe.views.ExpandableSurfaceView;
|
||||
import org.schabi.newpipe.views.player.PlayerFastSeekOverlay;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
@ -2530,7 +2527,7 @@ public final class Player implements
|
|||
Log.d(TAG, "ExoPlayer - onTracksChanged(), "
|
||||
+ "track group size = " + tracksInfo.getTrackGroupInfos().size());
|
||||
}
|
||||
onTextTracksChanged();
|
||||
onTextTracksChanged(tracksInfo);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -3516,17 +3513,7 @@ public final class Player implements
|
|||
return;
|
||||
}
|
||||
captionPopupMenu.getMenu().removeGroup(POPUP_MENU_ID_CAPTION);
|
||||
|
||||
final String userPreferredLanguage =
|
||||
prefs.getString(context.getString(R.string.caption_user_set_key), null);
|
||||
/*
|
||||
* only search for autogenerated cc as fallback
|
||||
* if "(auto-generated)" was not already selected
|
||||
* we are only looking for "(" instead of "(auto-generated)" to hopefully get all
|
||||
* internationalized variants such as "(automatisch-erzeugt)" and so on
|
||||
*/
|
||||
boolean searchForAutogenerated = userPreferredLanguage != null
|
||||
&& !userPreferredLanguage.contains("(");
|
||||
captionPopupMenu.setOnDismissListener(this);
|
||||
|
||||
// Add option for turning off caption
|
||||
final MenuItem captionOffItem = captionPopupMenu.getMenu().add(POPUP_MENU_ID_CAPTION,
|
||||
|
@ -3549,30 +3536,42 @@ public final class Player implements
|
|||
captionItem.setOnMenuItemClickListener(menuItem -> {
|
||||
final int textRendererIndex = getCaptionRendererIndex();
|
||||
if (textRendererIndex != RENDERER_UNAVAILABLE) {
|
||||
// DefaultTrackSelector will select for text tracks in the following order.
|
||||
// When multiple tracks share the same rank, a random track will be chosen.
|
||||
// 1. ANY track exactly matching preferred language name
|
||||
// 2. ANY track exactly matching preferred language stem
|
||||
// 3. ROLE_FLAG_CAPTION track matching preferred language stem
|
||||
// 4. ROLE_FLAG_DESCRIBES_MUSIC_AND_SOUND track matching preferred language stem
|
||||
// This means if a caption track of preferred language is not available,
|
||||
// then an auto-generated track of that language will be chosen automatically.
|
||||
trackSelector.setParameters(trackSelector.buildUponParameters()
|
||||
.setPreferredTextLanguage(captionLanguage)
|
||||
.setPreferredTextLanguages(captionLanguage,
|
||||
PlayerHelper.captionLanguageStemOf(captionLanguage))
|
||||
.setPreferredTextRoleFlags(C.ROLE_FLAG_CAPTION)
|
||||
.setRendererDisabled(textRendererIndex, false));
|
||||
prefs.edit().putString(context.getString(R.string.caption_user_set_key),
|
||||
captionLanguage).apply();
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
// apply caption language from previous user preference
|
||||
if (userPreferredLanguage != null
|
||||
&& (captionLanguage.equals(userPreferredLanguage)
|
||||
|| (searchForAutogenerated && captionLanguage.startsWith(userPreferredLanguage))
|
||||
|| (userPreferredLanguage.contains("(") && captionLanguage.startsWith(
|
||||
userPreferredLanguage.substring(0, userPreferredLanguage.indexOf('(')))))) {
|
||||
final List<String> selectedPreferredLanguages =
|
||||
trackSelector.getParameters().preferredTextLanguages;
|
||||
final String userPreferredLanguage =
|
||||
prefs.getString(context.getString(R.string.caption_user_set_key), null);
|
||||
final int textRendererIndex = getCaptionRendererIndex();
|
||||
if (textRendererIndex != RENDERER_UNAVAILABLE) {
|
||||
|
||||
if (userPreferredLanguage != null
|
||||
&& !selectedPreferredLanguages.contains(userPreferredLanguage)
|
||||
&& textRendererIndex != RENDERER_UNAVAILABLE) {
|
||||
trackSelector.setParameters(trackSelector.buildUponParameters()
|
||||
.setPreferredTextLanguage(captionLanguage)
|
||||
.setPreferredTextLanguages(userPreferredLanguage,
|
||||
PlayerHelper.captionLanguageStemOf(userPreferredLanguage))
|
||||
.setPreferredTextRoleFlags(C.ROLE_FLAG_CAPTION)
|
||||
.setRendererDisabled(textRendererIndex, false));
|
||||
}
|
||||
searchForAutogenerated = false;
|
||||
}
|
||||
}
|
||||
captionPopupMenu.setOnDismissListener(this);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -3668,41 +3667,43 @@ public final class Player implements
|
|||
binding.subtitleView.setStyle(captionStyle);
|
||||
}
|
||||
|
||||
private void onTextTracksChanged() {
|
||||
final int textRenderer = getCaptionRendererIndex();
|
||||
|
||||
private void onTextTracksChanged(@NonNull final TracksInfo currentTrackInfo) {
|
||||
if (binding == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (trackSelector.getCurrentMappedTrackInfo() == null
|
||||
|| textRenderer == RENDERER_UNAVAILABLE) {
|
||||
|| !currentTrackInfo.isTypeSupportedOrEmpty(C.TRACK_TYPE_TEXT)) {
|
||||
binding.captionTextView.setVisibility(View.GONE);
|
||||
return;
|
||||
}
|
||||
|
||||
final TrackGroupArray textTracks = trackSelector.getCurrentMappedTrackInfo()
|
||||
.getTrackGroups(textRenderer);
|
||||
|
||||
// Extract all loaded languages
|
||||
final List<String> availableLanguages = new ArrayList<>(textTracks.length);
|
||||
for (int i = 0; i < textTracks.length; i++) {
|
||||
final TrackGroup textTrack = textTracks.get(i);
|
||||
if (textTrack.length > 0) {
|
||||
availableLanguages.add(textTrack.getFormat(0).language);
|
||||
}
|
||||
}
|
||||
final List<TracksInfo.TrackGroupInfo> textTracks = currentTrackInfo
|
||||
.getTrackGroupInfos()
|
||||
.stream()
|
||||
.filter(trackGroupInfo -> C.TRACK_TYPE_TEXT == trackGroupInfo.getTrackType())
|
||||
.collect(Collectors.toList());
|
||||
final List<String> availableLanguages = textTracks.stream()
|
||||
.map(TracksInfo.TrackGroupInfo::getTrackGroup)
|
||||
.filter(textTrack -> textTrack.length > 0)
|
||||
.map(textTrack -> textTrack.getFormat(0).language)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
// Find selected text track
|
||||
final Optional<Format> selectedTracks = textTracks.stream()
|
||||
.filter(TracksInfo.TrackGroupInfo::isSelected)
|
||||
.filter(info -> info.getTrackGroup().length >= 1)
|
||||
.map(info -> info.getTrackGroup().getFormat(0))
|
||||
.findFirst();
|
||||
|
||||
// Normalize mismatching language strings
|
||||
final String preferredLanguage = trackSelector.getParameters()
|
||||
.preferredTextLanguages.stream().findFirst().orElse(null);
|
||||
// Build UI
|
||||
buildCaptionMenu(availableLanguages);
|
||||
if (trackSelector.getParameters().getRendererDisabled(textRenderer)
|
||||
|| preferredLanguage == null || (!availableLanguages.contains(preferredLanguage)
|
||||
&& !containsCaseInsensitive(availableLanguages, preferredLanguage))) {
|
||||
if (trackSelector.getParameters().getRendererDisabled(getCaptionRendererIndex())
|
||||
|| !selectedTracks.isPresent()) {
|
||||
binding.captionTextView.setText(R.string.caption_none);
|
||||
} else {
|
||||
binding.captionTextView.setText(preferredLanguage);
|
||||
binding.captionTextView.setText(selectedTracks.get().language);
|
||||
}
|
||||
binding.captionTextView.setVisibility(
|
||||
availableLanguages.isEmpty() ? View.GONE : View.VISIBLE);
|
||||
|
|
|
@ -144,6 +144,21 @@ public final class PlayerHelper {
|
|||
? " (" + context.getString(R.string.caption_auto_generated) + ")" : "");
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static String captionLanguageStemOf(@NonNull final String language) {
|
||||
if (!language.contains("(") || !language.contains(")")) {
|
||||
return language;
|
||||
}
|
||||
|
||||
if (language.startsWith("(")) {
|
||||
// language text is right-to-left
|
||||
final String[] parts = language.split("\\)");
|
||||
return parts[parts.length - 1].trim();
|
||||
}
|
||||
|
||||
return language.split("\\(")[0].trim();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static String resizeTypeOf(@NonNull final Context context,
|
||||
@ResizeMode final int resizeMode) {
|
||||
|
|
|
@ -6,6 +6,7 @@ import android.net.Uri;
|
|||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.MediaItem;
|
||||
import com.google.android.exoplayer2.source.MediaSource;
|
||||
import com.google.android.exoplayer2.source.MergingMediaSource;
|
||||
|
@ -116,9 +117,13 @@ public class VideoPlaybackResolver implements PlaybackResolver {
|
|||
if (mimeType == null) {
|
||||
continue;
|
||||
}
|
||||
final @C.RoleFlags int textRoleFlag = subtitle.isAutoGenerated()
|
||||
? C.ROLE_FLAG_DESCRIBES_MUSIC_AND_SOUND
|
||||
: C.ROLE_FLAG_CAPTION;
|
||||
final MediaItem.SubtitleConfiguration textMediaItem =
|
||||
new MediaItem.SubtitleConfiguration.Builder(Uri.parse(subtitle.getUrl()))
|
||||
.setMimeType(mimeType)
|
||||
.setRoleFlags(textRoleFlag)
|
||||
.setLanguage(PlayerHelper.captionLanguageOf(context, subtitle))
|
||||
.build();
|
||||
final MediaSource textSource = dataSource
|
||||
|
|
Loading…
Reference in a new issue