diff --git a/extensions/shared/library/src/main/java/app/revanced/extension/shared/settings/preference/AbstractPreferenceFragment.java b/extensions/shared/library/src/main/java/app/revanced/extension/shared/settings/preference/AbstractPreferenceFragment.java index 67eeb0b71..6e0e8957b 100644 --- a/extensions/shared/library/src/main/java/app/revanced/extension/shared/settings/preference/AbstractPreferenceFragment.java +++ b/extensions/shared/library/src/main/java/app/revanced/extension/shared/settings/preference/AbstractPreferenceFragment.java @@ -53,7 +53,7 @@ public abstract class AbstractPreferenceFragment extends PreferenceFragment { * Set by subclasses if Strings cannot be added as a resource. */ @Nullable - protected static String restartDialogTitle, restartDialogMessage, restartDialogButtonText, confirmDialogTitle; + protected static CharSequence restartDialogTitle, restartDialogMessage, restartDialogButtonText, confirmDialogTitle; private final SharedPreferences.OnSharedPreferenceChangeListener listener = (sharedPreferences, str) -> { try { @@ -125,10 +125,13 @@ public abstract class AbstractPreferenceFragment extends PreferenceFragment { showingUserDialogMessage = true; + CharSequence message = BulletPointPreference.formatIntoBulletPoints( + Objects.requireNonNull(setting.userDialogMessage).toString()); + Pair dialogPair = CustomDialog.create( context, confirmDialogTitle, // Title. - Objects.requireNonNull(setting.userDialogMessage).toString(), // No message. + message, null, // No EditText. null, // OK button text. () -> { diff --git a/extensions/shared/library/src/main/java/app/revanced/extension/shared/settings/preference/BulletPointPreference.java b/extensions/shared/library/src/main/java/app/revanced/extension/shared/settings/preference/BulletPointPreference.java index 204697228..ee3f02fc8 100644 --- a/extensions/shared/library/src/main/java/app/revanced/extension/shared/settings/preference/BulletPointPreference.java +++ b/extensions/shared/library/src/main/java/app/revanced/extension/shared/settings/preference/BulletPointPreference.java @@ -15,7 +15,15 @@ import android.util.AttributeSet; @SuppressWarnings({"unused", "deprecation"}) public class BulletPointPreference extends Preference { - public static SpannedString formatIntoBulletPoints(CharSequence source) { + /** + * Replaces bullet points with styled spans. + */ + public static CharSequence formatIntoBulletPoints(CharSequence source) { + final char bulletPoint = '•'; + if (TextUtils.indexOf(source, bulletPoint) < 0) { + return source; // Nothing to do. + } + SpannableStringBuilder builder = new SpannableStringBuilder(source); int lineStart = 0; @@ -26,7 +34,7 @@ public class BulletPointPreference extends Preference { if (lineEnd < 0) lineEnd = length; // Apply BulletSpan only if the line starts with the '•' character. - if (lineEnd > lineStart && builder.charAt(lineStart) == '•') { + if (lineEnd > lineStart && builder.charAt(lineStart) == bulletPoint) { int deleteEnd = lineStart + 1; // remove the bullet itself // If there's a single space right after the bullet, remove that too. diff --git a/extensions/shared/library/src/main/java/app/revanced/extension/shared/spoof/requests/PlayerRoutes.java b/extensions/shared/library/src/main/java/app/revanced/extension/shared/spoof/requests/PlayerRoutes.java index ef5907b01..cfc811d75 100644 --- a/extensions/shared/library/src/main/java/app/revanced/extension/shared/spoof/requests/PlayerRoutes.java +++ b/extensions/shared/library/src/main/java/app/revanced/extension/shared/spoof/requests/PlayerRoutes.java @@ -42,11 +42,8 @@ final class PlayerRoutes { JSONObject context = new JSONObject(); AppLanguage language = SpoofVideoStreamsPatch.getLanguageOverride(); - if (language == null || clientType == ANDROID_VR_1_43_32) { + if (language == null) { // Force original audio has not overrode the language. - // Or if YT has fallen over to the last unauthenticated client (VR 1.43), then - // always use the app language because forcing an audio stream of specific languages - // can sometimes fail so it's better to try and load something rather than nothing. language = BaseSettings.SPOOF_VIDEO_STREAMS_LANGUAGE.get(); } //noinspection ExtractMethodRecommender diff --git a/extensions/shared/library/src/main/java/app/revanced/extension/shared/ui/CustomDialog.java b/extensions/shared/library/src/main/java/app/revanced/extension/shared/ui/CustomDialog.java index 43a698ed1..1b65bea32 100644 --- a/extensions/shared/library/src/main/java/app/revanced/extension/shared/ui/CustomDialog.java +++ b/extensions/shared/library/src/main/java/app/revanced/extension/shared/ui/CustomDialog.java @@ -58,10 +58,10 @@ public class CustomDialog { * @param dismissDialogOnNeutralClick If the dialog should be dismissed when the Neutral button is clicked. * @return The Dialog and its main LinearLayout container. */ - public static Pair create(Context context, String title, CharSequence message, - @Nullable EditText editText, String okButtonText, + public static Pair create(Context context, CharSequence title, CharSequence message, + @Nullable EditText editText, CharSequence okButtonText, Runnable onOkClick, Runnable onCancelClick, - @Nullable String neutralButtonText, + @Nullable CharSequence neutralButtonText, @Nullable Runnable onNeutralClick, boolean dismissDialogOnNeutralClick) { Logger.printDebug(() -> "Creating custom dialog with title: " + title); @@ -85,9 +85,9 @@ public class CustomDialog { * @param onNeutralClick Action to perform when the Neutral button is clicked, or null if no Neutral button is needed. * @param dismissDialogOnNeutralClick If the dialog should be dismissed when the Neutral button is clicked. */ - private CustomDialog(Context context, String title, CharSequence message, @Nullable EditText editText, - String okButtonText, Runnable onOkClick, Runnable onCancelClick, - @Nullable String neutralButtonText, @Nullable Runnable onNeutralClick, + private CustomDialog(Context context, CharSequence title, CharSequence message, @Nullable EditText editText, + CharSequence okButtonText, Runnable onOkClick, Runnable onCancelClick, + @Nullable CharSequence neutralButtonText, @Nullable Runnable onNeutralClick, boolean dismissDialogOnNeutralClick) { this.context = context; this.dialog = new Dialog(context); @@ -139,7 +139,7 @@ public class CustomDialog { * * @param title The title text to display. */ - private void addTitle(String title) { + private void addTitle(CharSequence title) { if (TextUtils.isEmpty(title)) return; TextView titleView = new TextView(context); @@ -232,8 +232,8 @@ public class CustomDialog { * @param onNeutralClick Action for the Neutral button click, or null if no Neutral button. * @param dismissDialogOnNeutralClick If the dialog should dismiss on Neutral button click. */ - private void addButtons(String okButtonText, Runnable onOkClick, Runnable onCancelClick, - @Nullable String neutralButtonText, @Nullable Runnable onNeutralClick, + private void addButtons(CharSequence okButtonText, Runnable onOkClick, Runnable onCancelClick, + @Nullable CharSequence neutralButtonText, @Nullable Runnable onNeutralClick, boolean dismissDialogOnNeutralClick) { // Button container. LinearLayout buttonContainer = new LinearLayout(context); @@ -280,7 +280,7 @@ public class CustomDialog { * @param dismissDialog If the dialog should dismiss when the button is clicked. * @return The created Button. */ - private Button createButton(String text, Runnable onClick, boolean isOkButton, boolean dismissDialog) { + private Button createButton(CharSequence text, Runnable onClick, boolean isOkButton, boolean dismissDialog) { Button button = new Button(context, null, 0); button.setText(text); button.setTextSize(14); diff --git a/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/DisableHdrPatch.java b/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/DisableVideoCodecsPatch.java similarity index 71% rename from extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/DisableHdrPatch.java rename to extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/DisableVideoCodecsPatch.java index d89bf72f5..5e4dd06f6 100644 --- a/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/DisableHdrPatch.java +++ b/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/DisableVideoCodecsPatch.java @@ -5,7 +5,7 @@ import android.view.Display; import app.revanced.extension.youtube.settings.Settings; @SuppressWarnings("unused") -public class DisableHdrPatch { +public class DisableVideoCodecsPatch { /** * Injection point. @@ -15,5 +15,12 @@ public class DisableHdrPatch { ? new int[0] : capabilities.getSupportedHdrTypes(); } + + /** + * Injection point. + */ + public static boolean allowVP9() { + return !Settings.FORCE_AVC_CODEC.get(); + } } diff --git a/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/ForceOriginalAudioPatch.java b/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/ForceOriginalAudioPatch.java index 290928f98..8836e7b32 100644 --- a/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/ForceOriginalAudioPatch.java +++ b/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/ForceOriginalAudioPatch.java @@ -15,7 +15,8 @@ public class ForceOriginalAudioPatch { */ public static void setPreferredLanguage() { if (Settings.FORCE_ORIGINAL_AUDIO.get() - && SpoofVideoStreamsPatch.spoofingToClientWithNoMultiAudioStreams()) { + && SpoofVideoStreamsPatch.spoofingToClientWithNoMultiAudioStreams() + && !Settings.SPOOF_VIDEO_STREAMS_CLIENT_TYPE.get().useAuth) { // If client spoofing does not use authentication and lacks multi-audio streams, // then can use any language code for the request and if that requested language is // not available YT uses the original audio language. Authenticated requests ignore diff --git a/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/spoof/SpoofVideoStreamsPatch.java b/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/spoof/SpoofVideoStreamsPatch.java index 2af74b2a0..da200ef67 100644 --- a/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/spoof/SpoofVideoStreamsPatch.java +++ b/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/spoof/SpoofVideoStreamsPatch.java @@ -18,7 +18,22 @@ public class SpoofVideoStreamsPatch { * Injection point. */ public static void setClientOrderToUse() { - List availableClients = List.of( + final boolean forceAVC = Settings.FORCE_AVC_CODEC.get(); + + // VR 1.61 uses VP9/AV1, and cannot force AVC. + ClientType client = Settings.SPOOF_VIDEO_STREAMS_CLIENT_TYPE.get(); + if (forceAVC && client == ANDROID_VR_1_61_48) { + client = ANDROID_VR_1_43_32; // Use VR 1.43 instead. + } + + List availableClients = forceAVC + ? List.of( + ANDROID_VR_1_43_32, + VISIONOS, + ANDROID_CREATOR, + ANDROID_VR_1_61_48, + IPADOS) + : List.of( ANDROID_VR_1_61_48, VISIONOS, ANDROID_CREATOR, @@ -27,6 +42,6 @@ public class SpoofVideoStreamsPatch { ); app.revanced.extension.shared.spoof.SpoofVideoStreamsPatch.setClientsToUse( - availableClients, Settings.SPOOF_VIDEO_STREAMS_CLIENT_TYPE.get()); + availableClients, client); } } \ No newline at end of file diff --git a/extensions/youtube/src/main/java/app/revanced/extension/youtube/settings/Settings.java b/extensions/youtube/src/main/java/app/revanced/extension/youtube/settings/Settings.java index 3a4bf598a..86dd9d961 100644 --- a/extensions/youtube/src/main/java/app/revanced/extension/youtube/settings/Settings.java +++ b/extensions/youtube/src/main/java/app/revanced/extension/youtube/settings/Settings.java @@ -48,6 +48,9 @@ import app.revanced.extension.youtube.swipecontrols.SwipeControlsConfigurationPr public class Settings extends BaseSettings { // Video + public static final BooleanSetting ADVANCED_VIDEO_QUALITY_MENU = new BooleanSetting("revanced_advanced_video_quality_menu", TRUE); + public static final BooleanSetting DISABLE_HDR_VIDEO = new BooleanSetting("revanced_disable_hdr_video", FALSE); + public static final BooleanSetting FORCE_AVC_CODEC = new BooleanSetting("revanced_force_avc_codec", FALSE, true, "revanced_force_avc_codec_user_dialog_message"); public static final IntegerSetting VIDEO_QUALITY_DEFAULT_WIFI = new IntegerSetting("revanced_video_quality_default_wifi", -2); public static final IntegerSetting VIDEO_QUALITY_DEFAULT_MOBILE = new IntegerSetting("revanced_video_quality_default_mobile", -2); public static final BooleanSetting REMEMBER_VIDEO_QUALITY_LAST_SELECTED = new BooleanSetting("revanced_remember_video_quality_last_selected", FALSE); @@ -56,8 +59,6 @@ public class Settings extends BaseSettings { public static final BooleanSetting REMEMBER_SHORTS_QUALITY_LAST_SELECTED = new BooleanSetting("revanced_remember_shorts_quality_last_selected", FALSE); public static final BooleanSetting REMEMBER_VIDEO_QUALITY_LAST_SELECTED_TOAST = new BooleanSetting("revanced_remember_video_quality_last_selected_toast", TRUE, false, parentsAny(REMEMBER_VIDEO_QUALITY_LAST_SELECTED, REMEMBER_SHORTS_QUALITY_LAST_SELECTED)); - public static final BooleanSetting ADVANCED_VIDEO_QUALITY_MENU = new BooleanSetting("revanced_advanced_video_quality_menu", TRUE); - public static final BooleanSetting DISABLE_HDR_VIDEO = new BooleanSetting("revanced_disable_hdr_video", FALSE); // Speed public static final FloatSetting SPEED_TAP_AND_HOLD = new FloatSetting("revanced_speed_tap_and_hold", 2.0f, true); diff --git a/patches/api/patches.api b/patches/api/patches.api index b63399a7a..ab0252db1 100644 --- a/patches/api/patches.api +++ b/patches/api/patches.api @@ -1727,6 +1727,10 @@ public final class app/revanced/patches/youtube/video/audio/ForceOriginalAudioPa public static final fun getForceOriginalAudioPatch ()Lapp/revanced/patcher/patch/BytecodePatch; } +public final class app/revanced/patches/youtube/video/codecs/DisableVideoCodecsPatchKt { + public static final fun getDisableVideoCodecsPatch ()Lapp/revanced/patcher/patch/BytecodePatch; +} + public final class app/revanced/patches/youtube/video/hdr/DisableHdrPatchKt { public static final fun getDisableHdrPatch ()Lapp/revanced/patcher/patch/BytecodePatch; } diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/video/codecs/DisableVideoCodecsPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/video/codecs/DisableVideoCodecsPatch.kt new file mode 100644 index 000000000..fd509f573 --- /dev/null +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/video/codecs/DisableVideoCodecsPatch.kt @@ -0,0 +1,87 @@ +package app.revanced.patches.youtube.video.codecs + +import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels +import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction +import app.revanced.patcher.patch.bytecodePatch +import app.revanced.patches.all.misc.resources.addResources +import app.revanced.patches.all.misc.resources.addResourcesPatch +import app.revanced.patches.all.misc.transformation.transformInstructionsPatch +import app.revanced.patches.shared.misc.settings.preference.SwitchPreference +import app.revanced.patches.youtube.misc.extension.sharedExtensionPatch +import app.revanced.patches.youtube.misc.settings.PreferenceScreen +import app.revanced.patches.youtube.misc.settings.settingsPatch +import app.revanced.util.getReference +import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction +import com.android.tools.smali.dexlib2.iface.reference.MethodReference + +private const val EXTENSION_CLASS_DESCRIPTOR = + "Lapp/revanced/extension/youtube/patches/DisableVideoCodecsPatch;" + +@Suppress("unused") +val disableVideoCodecsPatch = bytecodePatch( + name = "disable video codecs", + description = "Adds options to disable HDR and VP9 codecs.", +) { + dependsOn( + sharedExtensionPatch, + settingsPatch, + addResourcesPatch, + /** + * Override all calls of `getSupportedHdrTypes`. + */ + transformInstructionsPatch( + filterMap = filterMap@{ classDef, _, instruction, instructionIndex -> + if (classDef.type.startsWith("Lapp/revanced/")) { + return@filterMap null + } + + val reference = instruction.getReference() + if (reference?.definingClass =="Landroid/view/Display\$HdrCapabilities;" + && reference.name == "getSupportedHdrTypes") { + return@filterMap instruction to instructionIndex + } + return@filterMap null + }, + transform = { method, entry -> + val (instruction, index) = entry + val register = (instruction as FiveRegisterInstruction).registerC + + method.replaceInstruction( + index, + "invoke-static/range { v$register .. v$register }, $EXTENSION_CLASS_DESCRIPTOR->" + + "disableHdrVideo(Landroid/view/Display\$HdrCapabilities;)[I", + ) + } + ) + ) + + compatibleWith( + "com.google.android.youtube"( + "19.34.42", + "20.07.39", + "20.13.41", + "20.14.43", + ) + ) + + execute { + addResources("youtube", "video.codecs.disableVideoCodecsPatch") + + PreferenceScreen.VIDEO.addPreferences( + SwitchPreference("revanced_disable_hdr_video"), + SwitchPreference("revanced_force_avc_codec") + ) + + vp9CapabilityFingerprint.method.addInstructionsWithLabels( + 0, + """ + invoke-static {}, $EXTENSION_CLASS_DESCRIPTOR->allowVP9()Z + move-result v0 + if-nez v0, :default + return v0 + :default + nop + """ + ) + } +} diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/video/codecs/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/video/codecs/Fingerprints.kt new file mode 100644 index 000000000..a7790191f --- /dev/null +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/video/codecs/Fingerprints.kt @@ -0,0 +1,13 @@ +package app.revanced.patches.youtube.video.codecs + +import app.revanced.patcher.fingerprint +import com.android.tools.smali.dexlib2.AccessFlags + +internal val vp9CapabilityFingerprint = fingerprint { + accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) + returns("Z") + strings( + "vp9_supported", + "video/x-vnd.on2.vp9" + ) +} diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/video/hdr/DisableHdrPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/video/hdr/DisableHdrPatch.kt index dd02c7b52..d0591f2c7 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/video/hdr/DisableHdrPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/video/hdr/DisableHdrPatch.kt @@ -1,71 +1,10 @@ package app.revanced.patches.youtube.video.hdr -import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction import app.revanced.patcher.patch.bytecodePatch -import app.revanced.patches.all.misc.resources.addResources -import app.revanced.patches.all.misc.resources.addResourcesPatch -import app.revanced.patches.all.misc.transformation.transformInstructionsPatch -import app.revanced.patches.shared.misc.settings.preference.SwitchPreference -import app.revanced.patches.youtube.misc.extension.sharedExtensionPatch -import app.revanced.patches.youtube.misc.settings.PreferenceScreen -import app.revanced.patches.youtube.misc.settings.settingsPatch -import app.revanced.util.getReference -import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction -import com.android.tools.smali.dexlib2.iface.reference.MethodReference - -private const val EXTENSION_CLASS_DESCRIPTOR = - "Lapp/revanced/extension/youtube/patches/DisableHdrPatch;" +import app.revanced.patches.youtube.video.codecs.disableVideoCodecsPatch +@Deprecated("Patch was renamed", ReplaceWith("disableVideoCodecsPatch")) @Suppress("unused") -val disableHdrPatch = bytecodePatch( - name = "Disable HDR video", - description = "Adds an option to disable video HDR.", -) { - dependsOn( - sharedExtensionPatch, - settingsPatch, - addResourcesPatch, - // Override all calls of `getSupportedHdrTypes`. - transformInstructionsPatch( - filterMap = filterMap@{ classDef, _, instruction, instructionIndex -> - if (classDef.type.startsWith("Lapp/revanced/")) { - return@filterMap null - } - - val reference = instruction.getReference() - if (reference?.definingClass =="Landroid/view/Display\$HdrCapabilities;" - && reference.name == "getSupportedHdrTypes") { - return@filterMap instruction to instructionIndex - } - return@filterMap null - }, - transform = { method, entry -> - val (instruction, index) = entry - val register = (instruction as FiveRegisterInstruction).registerC - - method.replaceInstruction( - index, - "invoke-static/range { v$register .. v$register }, $EXTENSION_CLASS_DESCRIPTOR->" + - "disableHdrVideo(Landroid/view/Display\$HdrCapabilities;)[I", - ) - } - ) - ) - - compatibleWith( - "com.google.android.youtube"( - "19.34.42", - "20.07.39", - "20.13.41", - "20.14.43", - ) - ) - - execute { - addResources("youtube", "video.hdr.disableHdrPatch") - - PreferenceScreen.VIDEO.addPreferences( - SwitchPreference("revanced_disable_hdr_video") - ) - } -} +val disableHdrPatch = bytecodePatch{ + dependsOn(disableVideoCodecsPatch) +} \ No newline at end of file diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/video/quality/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/video/quality/Fingerprints.kt index 09ec88f9c..31c0c15d5 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/video/quality/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/video/quality/Fingerprints.kt @@ -26,7 +26,6 @@ internal val videoQualityItemOnClickFingerprint = fingerprint { } } - internal val videoQualityMenuOptionsFingerprint = fingerprint { accessFlags(AccessFlags.STATIC) returns("[L") diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/video/quality/VideoQualityPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/video/quality/VideoQualityPatch.kt index bbeb29e10..1a7908772 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/video/quality/VideoQualityPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/video/quality/VideoQualityPatch.kt @@ -14,12 +14,13 @@ internal val settingsMenuVideoQualityGroup = mutableSetOf() @Suppress("unused") val videoQualityPatch = bytecodePatch( name = "Video quality", - description = "Adds options to use the advanced video quality menu and set default video qualities." + description = "Adds options to use the advanced video quality menu, set default video qualities, " + + "and disable video codecs such as VP9/HDR." ) { dependsOn( rememberVideoQualityPatch, advancedVideoQualityMenuPatch, - videoQualityDialogButtonPatch, + videoQualityDialogButtonPatch ) compatibleWith( diff --git a/patches/src/main/resources/addresources/values/strings.xml b/patches/src/main/resources/addresources/values/strings.xml index 375d5ea69..3d24f8b0e 100644 --- a/patches/src/main/resources/addresources/values/strings.xml +++ b/patches/src/main/resources/addresources/values/strings.xml @@ -1641,10 +1641,22 @@ Enabling this can unlock higher video qualities" Default playback speed Changed default speed to: %s - + Disable HDR video HDR video is disabled HDR video is enabled + Force AVC (H.264) + Video codec is forced to AVC (H.264) + Video codec is determined automatically + "Benefits: +• Can improve battery life. +• Can restore missing video resolutions on older device. + +Limitations: +• Maximum resolution is 1080p. +• Video playback will use more internet data than VP9 or AV1. +• HDR videos may not use AVC. +• Some devices cannot force AVC." Show advanced video quality menu