ReVanced / revanced-patches

🧩 Patches for ReVanced
https://revanced.app
GNU General Public License v3.0
2.21k stars 259 forks source link

bug(YouTube - Spoof client): With iOS spoofing, VP9 is used even if the device doesn't support VP9 #3567

Open kitadai31 opened 3 weeks ago

kitadai31 commented 3 weeks ago

Bug description

If Spoof client is enabled and is spoofing to iOS, VP9 is used forcibly even if the device doesn't support VP9 hardware decoding. This started after the user agent spoofing has been added at 0e6ae5fee752a76604cf9b95f9a76c0cbe5f7dae and https://github.com/ReVanced/revanced-integrations/commit/fbf629fd6278440e70b0f1fb07e4cb7c412f0949.

This issue causes video stuttering on devices that doesn't have VP9 HW decoding.

Error logs

No response

Solution

The iOS YouTube app delivers videos in VP9 on iOS 14 and later. So, check if the device has hardware decoding for VP9, and spoof the os version to iOS 13 depending on the result.

I confirmed that osVersion 13.7.17H35 and userAgent com.google.ios.youtube/19.10.7 (iPhone; U; CPU iOS 13_7 like Mac OS X) works.

As for implementation, unlike the AV1 checking, checking for VP9 is also required for Android versions below Android 10, which don't have isHardwareAccelerated(). This can be determined by whether the codec name starts with "OMX.google" or "c2.android". Such codecs are software decoding.

References: https://stackoverflow.com/a/53310935 https://source.android.com/docs/compatibility/10/android-10-cdd#5_1_10_media_codec_characterization

This is example code. (The code is from my fork patches for Android 6-7, so this code is missing a check for AV1, unfortunately.)

private static boolean deviceHasVP9HardwareDecoding() {
    MediaCodecList codecList = new MediaCodecList(MediaCodecList.ALL_CODECS);

    for (MediaCodecInfo codecInfo : codecList.getCodecInfos()) {
        final boolean isHardwareAccelerated = (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q)
                ? codecInfo.isHardwareAccelerated()
                : !codecInfo.getName().startsWith("OMX.google");
        if (isHardwareAccelerated && !codecInfo.isEncoder()) {
            for (String type : codecInfo.getSupportedTypes()) {
                if (type.equals("video/x-vnd.on2.vp9")) {
                    Logger.printDebug(() -> "Device supports VP9 hardware decoding.");
                    return true;
                }
            }
        }
    }
    Logger.printDebug(() -> "Device does not support VP9 hardware decoding.");
    return false;
}

Additional context

No response

Acknowledgements

oSumAtrIX commented 3 weeks ago

This should be a field, instantiated in the constructor once.

kitadai31 commented 3 weeks ago

I found a mistake in the issue, sorry.

This can be determined by whether the codec name starts with "OMX.google" or "c2.android".

c2 (Codec 2.0) was added in Android 10, so the check of "c2.android" isn't needed for below Android 10. Edited. (I just realized why isHardwareAccelerated() was not needed before Android 10. At that time, only OMX.google existed as a software codec.)


@oSumAtrIX I was talking about this: https://github.com/ReVanced/revanced-integrations/blob/9e11ba11d9f40fb3bbc90404bf96c94c12e7b0ba/app/src/main/java/app/revanced/integrations/youtube/patches/spoof/SpoofClientPatch.java#L206-L227

oSumAtrIX commented 3 weeks ago

Can you open a PR?

kitadai31 commented 3 weeks ago

I'm sorry but I can't PR I can't think of an implementation that checks both VP9 and AV1 at the same time Sorry for my lacking in experience of programming

oSumAtrIX commented 3 weeks ago

You can create two methods, one to check for vp9 and one to check for av1

Niterux commented 2 weeks ago

My phone can't handle vp9 or av1 at 1080p, the avc would be very preferred thanks.