Changeset 265167 in webkit


Ignore:
Timestamp:
Jul 31, 2020 4:40:06 PM (4 years ago)
Author:
jer.noble@apple.com
Message:

[Mac] YouTube does not offer HDR variants to devices which support HDR
https://bugs.webkit.org/show_bug.cgi?id=215022

Reviewed by Eric Carlson.

Source/WebCore:

Test: platform/mac/media/media-source/is-type-supported-vp9-codec-check.html

There are three separate issues which block YouTube from offering HDR:

1) YouTube checks both valid and invalid VP9 strings through MediaSource.isTypeSupported(), and UAs

which answer true to even invalid VP9 strings are blocked from HDR. To solve this, we will now
send isTypeSupported() through the same code path as Media Capabilities.

2) YouTube's standard valid and invalid VP9 strings do not include the fullRangeVideoFlag field, which

would normally be tossed as invalid. We shouldn't relax our requirements globally, so we will
add a Quirk which relaxes the requriement that VP9 strings contain a fullRangeVideoFlag.

3) YouTube's HDR query checks that window.screen.pixelDepth is > 24. We obviously don't want to change

the value of this field globally, so we will add separate Quirk which sets window.screen.pixelDepth
to 25 (a totally nonsensical value) when HDR is available.

Each of these Quirks has a path towards removal for YouTube. The fullRangeVideoFlag field involves
YouTube updating their compatibility check to inculde the fullRangeVideoFlag. The pixelDepth check
can be replaced by the dynamic-range:high Media Query.

  • Modules/mediasource/MediaSource.cpp:

(WebCore::addVP9FullRangeVideoFlagToContentType):
(WebCore::MediaSource::addSourceBuffer):
(WebCore::MediaSource::removeSourceBuffer):
(WebCore::MediaSource::isTypeSupported):
(WebCore::MediaSource::onReadyStateChange):
(WebCore::MediaSource::activeRanges const):

  • Modules/mediasource/MediaSource.h:
  • page/Quirks.cpp:

(WebCore::Quirks::needsVP9FullRangeFlagQuirk const):
(WebCore::Quirks::needsHDRPixelDepthQuirk const):

  • page/Quirks.h:
  • page/Screen.cpp:

(WebCore::Screen::pixelDepth const):

  • platform/graphics/cocoa/SourceBufferParserWebM.cpp:

(WebCore::SourceBufferParserWebM::isContentTypeSupported):

  • platform/graphics/cocoa/VP9UtilitiesCocoa.h:
  • platform/graphics/cocoa/VP9UtilitiesCocoa.mm:

(WebCore::isVPCodecConfigurationRecordSupported):
(WebCore::validateVPParameters):

LayoutTests:

  • platform/mac/media/media-source/is-type-supported-vp9-codec-check-expected.txt: Added.
  • platform/mac/media/media-source/is-type-supported-vp9-codec-check.html: Added.
  • platform/mac/media/mediacapabilities/vp9-decodingInfo-sw-expected.txt:
  • platform/mac/media/mediacapabilities/vp9-decodingInfo-sw.html:
Location:
trunk
Files:
2 added
13 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r265164 r265167  
     12020-07-31  Jer Noble  <jer.noble@apple.com>
     2
     3        [Mac] YouTube does not offer HDR variants to devices which support HDR
     4        https://bugs.webkit.org/show_bug.cgi?id=215022
     5
     6        Reviewed by Eric Carlson.
     7
     8        * platform/mac/media/media-source/is-type-supported-vp9-codec-check-expected.txt: Added.
     9        * platform/mac/media/media-source/is-type-supported-vp9-codec-check.html: Added.
     10        * platform/mac/media/mediacapabilities/vp9-decodingInfo-sw-expected.txt:
     11        * platform/mac/media/mediacapabilities/vp9-decodingInfo-sw.html:
     12
    1132020-07-31  Hector Lopez  <hector_i_lopez@apple.com>
    214
  • trunk/LayoutTests/platform/mac/TestExpectations

    r265164 r265167  
    19151915[ Catalina Mojave ] media/media-source/media-source-webm.html [ Skip ]
    19161916[ Catalina Mojave ] platform/mac/media/mediacapabilities/vp9-decodingInfo-sw.html [ Skip ]
     1917[ Catalina Mojave ] platform/mac/media/media-source/is-type-supported-vp9-codec-check.html [ Skip ]
    19171918
    19181919webkit.org/b/214422 imported/w3c/web-platform-tests/webaudio/the-audio-api/the-audiocontext-interface/suspend-after-construct.html [ Pass Failure ]
  • trunk/LayoutTests/platform/mac/media/mediacapabilities/vp9-decodingInfo-sw-expected.txt

    r264476 r265167  
    77RUN(promise = navigator.mediaCapabilities.decodingInfo({ type: 'media-source', video: { contentType: 'video/mp4; codecs="vp09.00.41.08"', height: 1080, bitrate: 800000, width: 3180, framerate: 30 }});)
    88Promise resolved OK
    9 EXPECTED (info.supported == 'true') OK
    10 EXPECTED (info.powerEfficient == 'false') OK
    11 EXPECTED (info.smooth == 'true') OK
     9EXPECTED (info === '{ supported: true, powerEfficient: false, smooth: true }') OK
    1210
    1311Test that 4k @ 60fps is supported, but not smooth or powerEfficient
    1412RUN(promise = navigator.mediaCapabilities.decodingInfo({ type: 'media-source', video: { contentType: 'video/mp4; codecs="vp09.00.41.08"', height: 1080, bitrate: 800000, width: 3180, framerate: 60 }});)
    1513Promise resolved OK
    16 EXPECTED (info.supported == 'true') OK
    17 EXPECTED (info.powerEfficient == 'false') OK
    18 EXPECTED (info.smooth == 'false') OK
     14EXPECTED (info === '{ supported: true, powerEfficient: false, smooth: false }') OK
     15
     16Test unsupported codec configurations.
     17Profiles 1 and 3 should be unsupported.
     18RUN(promise = navigator.mediaCapabilities.decodingInfo({ type: 'media-source', video: { contentType: 'video/mp4; codecs="vp09.01.41.08"', height: 1080, bitrate: 800000, width: 3180, framerate: 30 }});)
     19Promise resolved OK
     20EXPECTED (info === '{ supported: false, powerEfficient: false, smooth: false }') OK
     21
     22RUN(promise = navigator.mediaCapabilities.decodingInfo({ type: 'media-source', video: { contentType: 'video/mp4; codecs="vp09.03.41.08"', height: 1080, bitrate: 800000, width: 3180, framerate: 30 }});)
     23Promise resolved OK
     24EXPECTED (info === '{ supported: false, powerEfficient: false, smooth: false }') OK
     25
     26Pixel depths above 10 are unsupported.
     27RUN(promise = navigator.mediaCapabilities.decodingInfo({ type: 'media-source', video: { contentType: 'video/mp4; codecs="vp09.00.41.12"', height: 1080, bitrate: 800000, width: 3180, framerate: 60 }});)
     28Promise resolved OK
     29EXPECTED (info === '{ supported: false, powerEfficient: false, smooth: false }') OK
     30
     31Chroma subsampling 422 or 444 are unsupported.
     32RUN(promise = navigator.mediaCapabilities.decodingInfo({ type: 'media-source', video: { contentType: 'video/mp4; codecs="vp09.00.41.08.02.01.01.01.01"', height: 1080, bitrate: 800000, width: 3180, framerate: 60 }});)
     33Promise resolved OK
     34EXPECTED (info === '{ supported: false, powerEfficient: false, smooth: false }') OK
     35
     36RUN(promise = navigator.mediaCapabilities.decodingInfo({ type: 'media-source', video: { contentType: 'video/mp4; codecs="vp09.00.41.08.03.01.01.01.01"', height: 1080, bitrate: 800000, width: 3180, framerate: 60 }});)
     37Promise resolved OK
     38EXPECTED (info === '{ supported: false, powerEfficient: false, smooth: false }') OK
    1939
    2040Test that SW VP9 decoder is not supported on battery power when screen is not 4k resolution
     
    2242RUN(promise = navigator.mediaCapabilities.decodingInfo({ type: 'media-source', video: { contentType: 'video/mp4; codecs="vp09.00.41.08"', height: 1080, bitrate: 800000, width: 3180, framerate: 30 }});)
    2343Promise resolved OK
    24 EXPECTED (info.supported == 'false') OK
    25 EXPECTED (info.powerEfficient == 'false') OK
    26 EXPECTED (info.smooth == 'false') OK
     44EXPECTED (info === '{ supported: false, powerEfficient: false, smooth: false }') OK
    2745
    2846Test that SW VP9 decoder is supported on battery power when screen is at least 4k resolution
     
    3048RUN(promise = navigator.mediaCapabilities.decodingInfo({ type: 'media-source', video: { contentType: 'video/mp4; codecs="vp09.00.41.08"', height: 1080, bitrate: 800000, width: 3180, framerate: 30 }});)
    3149Promise resolved OK
    32 EXPECTED (info.supported == 'true') OK
    33 EXPECTED (info.powerEfficient == 'false') OK
    34 EXPECTED (info.smooth == 'true') OK
     50EXPECTED (info === '{ supported: true, powerEfficient: false, smooth: true }') OK
    3551END OF TEST
    3652
  • trunk/LayoutTests/platform/mac/media/mediacapabilities/vp9-decodingInfo-sw.html

    r264476 r265167  
    66    var promise;
    77    var info;
     8
     9    function MediaCapabilitiesInfoToString(info) {
     10        try {
     11            return `{ supported: ${ info.supported }, powerEfficient: ${ info.powerEfficient }, smooth: ${ info.smooth } }`;
     12        } catch(e) {
     13            return `{ ${set} }`;
     14        }
     15    }
     16
     17    function isEqualMediaCapabilitiesInfo(infoA, infoB) {
     18        try {
     19            return infoA.supported === infoB.supported
     20                && infoA.powerEfficient === infoB.powerEfficient
     21                && infoA.smooth === infoB.smooth;
     22        } catch(e) {
     23            return false;
     24        }
     25    }
     26
     27    function testExpectedMediaCapabilitiesInfo(testFuncString, expected)
     28    {
     29        let observed = eval(testFuncString);
     30        let success = isEqualMediaCapabilitiesInfo(observed, expected);
     31        reportExpected(success, testFuncString, '===', MediaCapabilitiesInfoToString(expected), MediaCapabilitiesInfoToString(observed));
     32    }
    833
    934    async function doTest()
     
    2348        run("promise = navigator.mediaCapabilities.decodingInfo({ type: 'media-source', video: { contentType: 'video/mp4; codecs=\"vp09.00.41.08\"', height: 1080, bitrate: 800000, width: 3180, framerate: 30 }});");
    2449        info = await shouldResolve(promise);
    25         testExpected('info.supported', true);
    26         testExpected('info.powerEfficient', false);
    27         testExpected('info.smooth', true);
     50        testExpectedMediaCapabilitiesInfo('info', {supported: true, powerEfficient: false, smooth: true});
    2851
    2952        consoleWrite('');
     
    3255        run("promise = navigator.mediaCapabilities.decodingInfo({ type: 'media-source', video: { contentType: 'video/mp4; codecs=\"vp09.00.41.08\"', height: 1080, bitrate: 800000, width: 3180, framerate: 60 }});");
    3356        info = await shouldResolve(promise);
    34         testExpected('info.supported', true);
    35         testExpected('info.powerEfficient', false);
    36         testExpected('info.smooth', false);
     57        testExpectedMediaCapabilitiesInfo('info', {supported: true, powerEfficient: false, smooth: false});
     58
     59        consoleWrite('');
     60        consoleWrite('Test unsupported codec configurations.');
     61        consoleWrite('Profiles 1 and 3 should be unsupported.');
     62        run("promise = navigator.mediaCapabilities.decodingInfo({ type: 'media-source', video: { contentType: 'video/mp4; codecs=\"vp09.01.41.08\"', height: 1080, bitrate: 800000, width: 3180, framerate: 30 }});");
     63        info = await shouldResolve(promise);
     64        testExpectedMediaCapabilitiesInfo('info', {supported: false, powerEfficient: false, smooth: false});
     65
     66        consoleWrite('');
     67        run("promise = navigator.mediaCapabilities.decodingInfo({ type: 'media-source', video: { contentType: 'video/mp4; codecs=\"vp09.03.41.08\"', height: 1080, bitrate: 800000, width: 3180, framerate: 30 }});");
     68        info = await shouldResolve(promise);
     69        testExpectedMediaCapabilitiesInfo('info', {supported: false, powerEfficient: false, smooth: false});
     70
     71        consoleWrite('');
     72        consoleWrite('Pixel depths above 10 are unsupported.');
     73
     74        run("promise = navigator.mediaCapabilities.decodingInfo({ type: 'media-source', video: { contentType: 'video/mp4; codecs=\"vp09.00.41.12\"', height: 1080, bitrate: 800000, width: 3180, framerate: 60 }});");
     75        info = await shouldResolve(promise);
     76        testExpectedMediaCapabilitiesInfo('info', {supported: false, powerEfficient: false, smooth: false});
     77
     78        consoleWrite('');
     79        consoleWrite('Chroma subsampling 422 or 444 are unsupported.');
     80
     81        run("promise = navigator.mediaCapabilities.decodingInfo({ type: 'media-source', video: { contentType: 'video/mp4; codecs=\"vp09.00.41.08.02.01.01.01.01\"', height: 1080, bitrate: 800000, width: 3180, framerate: 60 }});");
     82        info = await shouldResolve(promise);
     83        testExpectedMediaCapabilitiesInfo('info', {supported: false, powerEfficient: false, smooth: false});
     84
     85        consoleWrite('');
     86        run("promise = navigator.mediaCapabilities.decodingInfo({ type: 'media-source', video: { contentType: 'video/mp4; codecs=\"vp09.00.41.08.03.01.01.01.01\"', height: 1080, bitrate: 800000, width: 3180, framerate: 60 }});");
     87        info = await shouldResolve(promise);
     88        testExpectedMediaCapabilitiesInfo('info', {supported: false, powerEfficient: false, smooth: false});
    3789
    3890        consoleWrite('');
     
    4193        run("promise = navigator.mediaCapabilities.decodingInfo({ type: 'media-source', video: { contentType: 'video/mp4; codecs=\"vp09.00.41.08\"', height: 1080, bitrate: 800000, width: 3180, framerate: 30 }});");
    4294        info = await shouldResolve(promise);
    43         testExpected('info.supported', false);
    44         testExpected('info.powerEfficient', false);
    45         testExpected('info.smooth', false);
     95        testExpectedMediaCapabilitiesInfo('info', {supported: false, powerEfficient: false, smooth: false});
    4696
    4797        consoleWrite('');
     
    50100        run("promise = navigator.mediaCapabilities.decodingInfo({ type: 'media-source', video: { contentType: 'video/mp4; codecs=\"vp09.00.41.08\"', height: 1080, bitrate: 800000, width: 3180, framerate: 30 }});");
    51101        info = await shouldResolve(promise);
    52         testExpected('info.supported', true);
    53         testExpected('info.powerEfficient', false);
    54         testExpected('info.smooth', true);
     102        testExpectedMediaCapabilitiesInfo('info', {supported: true, powerEfficient: false, smooth: true});
    55103
    56104        endTest();
  • trunk/Source/WebCore/ChangeLog

    r265165 r265167  
     12020-07-31  Jer Noble  <jer.noble@apple.com>
     2
     3        [Mac] YouTube does not offer HDR variants to devices which support HDR
     4        https://bugs.webkit.org/show_bug.cgi?id=215022
     5
     6        Reviewed by Eric Carlson.
     7
     8        Test: platform/mac/media/media-source/is-type-supported-vp9-codec-check.html
     9
     10        There are three separate issues which block YouTube from offering HDR:
     11
     12        1) YouTube checks both valid and invalid VP9 strings through MediaSource.isTypeSupported(), and UAs
     13           which answer `true` to even invalid VP9 strings are blocked from HDR. To solve this, we will now
     14           send isTypeSupported() through the same code path as Media Capabilities.
     15
     16        2) YouTube's standard valid and invalid VP9 strings do not include the fullRangeVideoFlag field, which
     17           would normally be tossed as invalid. We shouldn't relax our requirements globally, so we will
     18           add a Quirk which relaxes the requriement that VP9 strings contain a fullRangeVideoFlag.
     19
     20        3) YouTube's HDR query checks that window.screen.pixelDepth is > 24. We obviously don't want to change
     21           the value of this field globally, so we will add separate Quirk which sets window.screen.pixelDepth
     22           to 25 (a totally nonsensical value) when HDR is available.
     23
     24        Each of these Quirks has a path towards removal for YouTube. The fullRangeVideoFlag field involves
     25        YouTube updating their compatibility check to inculde the fullRangeVideoFlag. The pixelDepth check
     26        can be replaced by the `dynamic-range:high` Media Query.
     27
     28        * Modules/mediasource/MediaSource.cpp:
     29        (WebCore::addVP9FullRangeVideoFlagToContentType):
     30        (WebCore::MediaSource::addSourceBuffer):
     31        (WebCore::MediaSource::removeSourceBuffer):
     32        (WebCore::MediaSource::isTypeSupported):
     33        (WebCore::MediaSource::onReadyStateChange):
     34        (WebCore::MediaSource::activeRanges const):
     35        * Modules/mediasource/MediaSource.h:
     36        * page/Quirks.cpp:
     37        (WebCore::Quirks::needsVP9FullRangeFlagQuirk const):
     38        (WebCore::Quirks::needsHDRPixelDepthQuirk const):
     39        * page/Quirks.h:
     40        * page/Screen.cpp:
     41        (WebCore::Screen::pixelDepth const):
     42        * platform/graphics/cocoa/SourceBufferParserWebM.cpp:
     43        (WebCore::SourceBufferParserWebM::isContentTypeSupported):
     44        * platform/graphics/cocoa/VP9UtilitiesCocoa.h:
     45        * platform/graphics/cocoa/VP9UtilitiesCocoa.mm:
     46        (WebCore::isVPCodecConfigurationRecordSupported):
     47        (WebCore::validateVPParameters):
     48
    1492020-07-31  Chris Dumez  <cdumez@apple.com>
    250
  • trunk/Source/WebCore/Modules/mediasource/MediaSource.cpp

    r264164 r265167  
    4343#include "MediaSourcePrivate.h"
    4444#include "MediaSourceRegistry.h"
     45#include "Quirks.h"
    4546#include "Settings.h"
    4647#include "SourceBuffer.h"
     
    660661}
    661662
     663static ContentType addVP9FullRangeVideoFlagToContentType(const ContentType& type)
     664{
     665    auto countPeriods = [] (const String& codec) {
     666        unsigned count = 0;
     667        unsigned position = 0;
     668
     669        while (codec.find('.', position) != notFound) {
     670            ++count;
     671            ++position;
     672        }
     673
     674        return count;
     675    };
     676
     677    for (auto codec : type.codecs()) {
     678        if (!codec.startsWith("vp09") || countPeriods(codec) != 7)
     679            continue;
     680
     681        auto rawType = type.raw();
     682        auto position = rawType.find(codec);
     683        ASSERT(position != notFound);
     684        if (position == notFound)
     685            continue;
     686
     687        rawType.insert(".00", position + codec.length());
     688        return ContentType(rawType);
     689    }
     690    return type;
     691}
     692
    662693ExceptionOr<Ref<SourceBuffer>> MediaSource::addSourceBuffer(const String& type)
    663694{
     
    677708        mediaContentTypesRequiringHardwareSupport.appendVector(m_mediaElement->document().settings().mediaContentTypesRequiringHardwareSupport());
    678709
    679     if (!isTypeSupported(type, WTFMove(mediaContentTypesRequiringHardwareSupport)))
     710    auto context = scriptExecutionContext();
     711    if (!context)
     712        return Exception { NotAllowedError };
     713
     714    if (!isTypeSupported(*context, type, WTFMove(mediaContentTypesRequiringHardwareSupport)))
    680715        return Exception { NotSupportedError };
    681716
     
    687722    // 5. Create a new SourceBuffer object and associated resources.
    688723    ContentType contentType(type);
     724    if (context->isDocument() && downcast<Document>(context)->quirks().needsVP9FullRangeFlagQuirk())
     725        contentType = addVP9FullRangeVideoFlagToContentType(contentType);
     726
    689727    auto sourceBufferPrivate = createSourceBufferPrivate(contentType);
    690728
     
    877915    }
    878916
    879     return isTypeSupported(type, WTFMove(mediaContentTypesRequiringHardwareSupport));
    880 }
    881 
    882 bool MediaSource::isTypeSupported(const String& type, Vector<ContentType>&& contentTypesRequiringHardwareSupport)
     917    return isTypeSupported(context, type, WTFMove(mediaContentTypesRequiringHardwareSupport));
     918}
     919
     920bool MediaSource::isTypeSupported(ScriptExecutionContext& context, const String& type, Vector<ContentType>&& contentTypesRequiringHardwareSupport)
    883921{
    884922    // Section 2.2 isTypeSupported() method steps.
     
    889927
    890928    ContentType contentType(type);
     929    if (context.isDocument() && downcast<Document>(context).quirks().needsVP9FullRangeFlagQuirk())
     930        contentType = addVP9FullRangeVideoFlagToContentType(contentType);
     931
    891932    String codecs = contentType.parameter("codecs");
    892933
     
    10331074}
    10341075
    1035 ExceptionOr<Ref<SourceBufferPrivate>> MediaSource::createSourceBufferPrivate(const ContentType& type)
    1036 {
     1076ExceptionOr<Ref<SourceBufferPrivate>> MediaSource::createSourceBufferPrivate(const ContentType& incomingType)
     1077{
     1078    ContentType type { incomingType };
     1079
     1080    auto context = scriptExecutionContext();
     1081    if (context && context->isDocument() && downcast<Document>(context)->quirks().needsVP9FullRangeFlagQuirk())
     1082        type = addVP9FullRangeVideoFlagToContentType(incomingType);
     1083
    10371084    RefPtr<SourceBufferPrivate> sourceBufferPrivate;
    10381085    switch (m_private->addSourceBuffer(type, sourceBufferPrivate)) {
  • trunk/Source/WebCore/Modules/mediasource/MediaSource.h

    r264164 r265167  
    131131    const char* activeDOMObjectName() const final;
    132132    bool virtualHasPendingActivity() const final;
    133     static bool isTypeSupported(const String& type, Vector<ContentType>&& contentTypesRequiringHardwareSupport);
     133    static bool isTypeSupported(ScriptExecutionContext&, const String& type, Vector<ContentType>&& contentTypesRequiringHardwareSupport);
    134134
    135135    void setPrivateAndOpen(Ref<MediaSourcePrivate>&&) final;
  • trunk/Source/WebCore/page/Quirks.cpp

    r265067 r265167  
    962962}
    963963
    964 }
     964bool Quirks::needsVP9FullRangeFlagQuirk() const
     965{
     966    if (!needsQuirks())
     967        return false;
     968
     969    if (!m_needsVP9FullRangeFlagQuirk)
     970        m_needsVP9FullRangeFlagQuirk = equalLettersIgnoringASCIICase(m_document->url().host(), "www.youtube.com");
     971
     972    return *m_needsVP9FullRangeFlagQuirk;
     973}
     974
     975bool Quirks::needsHDRPixelDepthQuirk() const
     976{
     977    if (!needsQuirks())
     978        return false;
     979
     980    if (!m_needsHDRPixelDepthQuirk)
     981        m_needsHDRPixelDepthQuirk = equalLettersIgnoringASCIICase(m_document->url().host(), "www.youtube.com");
     982
     983    return *m_needsHDRPixelDepthQuirk;
     984}
     985
     986
     987}
  • trunk/Source/WebCore/page/Quirks.h

    r264001 r265167  
    109109    StorageAccessResult triggerOptionalStorageAccessQuirk(const Element&, const AtomString& eventType) const;
    110110
     111    bool needsVP9FullRangeFlagQuirk() const;
     112    bool needsHDRPixelDepthQuirk() const;
     113
    111114private:
    112115    bool needsQuirks() const;
     
    134137    mutable Optional<bool> m_needsCanPlayAfterSeekedQuirk;
    135138    mutable Optional<bool> m_shouldBypassAsyncScriptDeferring;
     139    mutable Optional<bool> m_needsVP9FullRangeFlagQuirk;
     140    mutable Optional<bool> m_needsHDRPixelDepthQuirk;
    136141};
    137142
  • trunk/Source/WebCore/page/Screen.cpp

    r243887 r265167  
    3434#include "FrameView.h"
    3535#include "PlatformScreen.h"
     36#include "Quirks.h"
    3637#include "ResourceLoadObserver.h"
    3738#include "RuntimeEnabledFeatures.h"
     
    8687    if (RuntimeEnabledFeatures::sharedFeatures().webAPIStatisticsEnabled())
    8788        ResourceLoadObserver::shared().logScreenAPIAccessed(*frame->document(), ResourceLoadStatistics::ScreenAPI::PixelDepth);
    88     return static_cast<unsigned>(screenDepth(frame->view()));
     89
     90    auto* document = window()->document();
     91    if (!document || !document->quirks().needsHDRPixelDepthQuirk() || !screenSupportsHighDynamicRange(frame->view()))
     92        return static_cast<unsigned>(screenDepth(frame->view()));
     93
     94    return static_cast<unsigned>(screenDepth(frame->view())) + 1;
    8995}
    9096
  • trunk/Source/WebCore/platform/graphics/cocoa/SourceBufferParserWebM.cpp

    r265079 r265167  
    244244    for (auto split : splitResults) {
    245245        if (split.startsWith("vp09")) {
    246             if (!isVP9DecoderAvailable())
     246            auto codecParameters = parseVPCodecParameters(split);
     247            if (!codecParameters)
    247248                return MediaPlayerEnums::SupportsType::IsNotSupported;
     249
     250            if (!isVPCodecConfigurationRecordSupported(*codecParameters))
     251                return MediaPlayerEnums::SupportsType::IsNotSupported;
     252
    248253            continue;
    249254        }
  • trunk/Source/WebCore/platform/graphics/cocoa/VP9UtilitiesCocoa.h

    r265095 r265167  
    4242WEBCORE_EXPORT extern void registerSupplementalVP9Decoder();
    4343extern bool isVP9DecoderAvailable();
     44extern bool isVPCodecConfigurationRecordSupported(VPCodecConfigurationRecord&);
    4445extern bool validateVPParameters(VPCodecConfigurationRecord&, MediaCapabilitiesInfo&, const VideoConfiguration&);
    4546
  • trunk/Source/WebCore/platform/graphics/cocoa/VP9UtilitiesCocoa.mm

    r265095 r265167  
    119119}
    120120
    121 bool validateVPParameters(VPCodecConfigurationRecord& codecConfiguration, MediaCapabilitiesInfo& info, const VideoConfiguration& videoConfiguration)
     121bool isVPCodecConfigurationRecordSupported(VPCodecConfigurationRecord& codecConfiguration)
    122122{
    123123    if (!isVP9DecoderAvailable())
    124124        return false;
    125125
    126     // VideoConfiguration and VPCodecConfigurationRecord can have conflicting values for HDR properties. If so, reject.
    127     if (videoConfiguration.transferFunction) {
    128         // Note: Transfer Characteristics are defined by ISO/IEC 23091-2:2019.
    129         if (*videoConfiguration.transferFunction == TransferFunction::SRGB && codecConfiguration.transferCharacteristics > 15)
    130             return false;
    131         if (*videoConfiguration.transferFunction == TransferFunction::PQ && codecConfiguration.transferCharacteristics != 16)
    132             return false;
    133         if (*videoConfiguration.transferFunction == TransferFunction::HLG && codecConfiguration.transferCharacteristics != 18)
    134             return false;
    135     }
    136 
    137     if (videoConfiguration.colorGamut) {
    138         if (*videoConfiguration.colorGamut == ColorGamut::Rec2020 && codecConfiguration.colorPrimaries != 9)
    139             return false;
    140     }
    141 
    142     if (canLoad_VideoToolbox_VTIsHardwareDecodeSupported() && VTIsHardwareDecodeSupported(kCMVideoCodecType_VP9) && !hardwareVP9DecoderDisabledForTesting) {
    143         info.powerEfficient = true;
    144 
    145         // HW VP9 Decoder supports Profile 0 & 2:
    146         if (codecConfiguration.profile && codecConfiguration.profile != 2)
    147             return false;
    148 
    149         // HW VP9 Decoder supports up to Level 6:
    150         if (codecConfiguration.level > VPConfigurationLevel::Level_6)
    151             return false;
    152 
    153         // HW VP9 Decoder supports 8 or 10 bit color:
    154         if (codecConfiguration.bitDepth > 10)
    155             return false;
    156 
    157         // HW VP9 Decoder suports only 420 chroma subsampling:
    158         if (codecConfiguration.chromaSubsampling > VPConfigurationChromaSubsampling::Subsampling_420_Colocated)
    159             return false;
    160 
    161         // HW VP9 Decoder does not support alpha channel:
    162         if (videoConfiguration.alphaChannel && *videoConfiguration.alphaChannel)
    163             return false;
    164 
    165         // HW VP9 Decoder can support up to 4K @ 120 or 8K @ 30
    166         auto resolution = resolutionCategory({ (float)videoConfiguration.width, (float)videoConfiguration.height });
    167         if (resolution > ResolutionCategory::R_8K)
    168             return false;
    169         if (resolution == ResolutionCategory::R_8K && videoConfiguration.framerate > 30)
    170             info.smooth = false;
    171         else if (resolution <= ResolutionCategory::R_4K && videoConfiguration.framerate > 120)
    172             info.smooth = false;
    173         else
    174             info.smooth = true;
    175 
    176         return true;
    177     }
    178 
    179     // SW VP9 Decoder has much more variable capabilities depending on CPU characteristics.
    180     // FIXME: Add a lookup table for device-to-capabilities. For now, assume that the SW VP9
    181     // decoder can support 4K @ 30.
    182     if (videoConfiguration.height <= 1080 && videoConfiguration.framerate > 60)
    183         info.smooth = false;
    184     if (videoConfiguration.height <= 2160 && videoConfiguration.framerate > 30)
    185         info.smooth = false;
    186     else
    187         info.smooth = true;
     126    // HW & SW VP9 Decoders support Profile 0 & 2:
     127    if (codecConfiguration.profile && codecConfiguration.profile != 2)
     128        return false;
     129
     130    // HW & SW VP9 Decoders support only 420 chroma subsampling:
     131    if (codecConfiguration.chromaSubsampling > VPConfigurationChromaSubsampling::Subsampling_420_Colocated)
     132        return false;
     133
     134    // HW & SW VP9 Decoders support 8 or 10 bit color:
     135    if (codecConfiguration.bitDepth > 10)
     136        return false;
     137
     138    // HW & SW VP9 Decoders support up to Level 6:
     139    if (codecConfiguration.level > VPConfigurationLevel::Level_6)
     140        return false;
     141
     142    // Hardware decoders are always available.
     143    if (canLoad_VideoToolbox_VTIsHardwareDecodeSupported() && VTIsHardwareDecodeSupported(kCMVideoCodecType_VP9) && !hardwareVP9DecoderDisabledForTesting)
     144        return true;
    188145
    189146    // For wall-powered devices, always report VP9 as supported, even if not powerEfficient.
    190     if (!systemHasBattery()) {
    191         info.supported = true;
    192         return true;
    193     }
     147    if (!systemHasBattery())
     148        return true;
    194149
    195150    // For battery-powered devices, always report VP9 as supported when running on AC power,
    196151    // but only on battery when there is an attached screen whose resolution is large enough
    197152    // to support 4K video.
    198     if (systemHasAC()) {
    199         info.supported = true;
    200         return true;
    201     }
     153    if (systemHasAC())
     154        return true;
    202155
    203156    bool has4kScreen = false;
     
    215168    }
    216169
    217     if (!has4kScreen) {
    218         info.supported = false;
    219         return false;
    220     }
    221 
     170    return has4kScreen;
     171}
     172
     173bool validateVPParameters(VPCodecConfigurationRecord& codecConfiguration, MediaCapabilitiesInfo& info, const VideoConfiguration& videoConfiguration)
     174{
     175    if (!isVPCodecConfigurationRecordSupported(codecConfiguration))
     176        return false;
     177
     178    // VideoConfiguration and VPCodecConfigurationRecord can have conflicting values for HDR properties. If so, reject.
     179    if (videoConfiguration.transferFunction) {
     180        // Note: Transfer Characteristics are defined by ISO/IEC 23091-2:2019.
     181        if (*videoConfiguration.transferFunction == TransferFunction::SRGB && codecConfiguration.transferCharacteristics > 15)
     182            return false;
     183        if (*videoConfiguration.transferFunction == TransferFunction::PQ && codecConfiguration.transferCharacteristics != 16)
     184            return false;
     185        if (*videoConfiguration.transferFunction == TransferFunction::HLG && codecConfiguration.transferCharacteristics != 18)
     186            return false;
     187    }
     188
     189    if (videoConfiguration.colorGamut) {
     190        if (*videoConfiguration.colorGamut == ColorGamut::Rec2020 && codecConfiguration.colorPrimaries != 9)
     191            return false;
     192    }
     193
     194    if (canLoad_VideoToolbox_VTIsHardwareDecodeSupported() && VTIsHardwareDecodeSupported(kCMVideoCodecType_VP9) && !hardwareVP9DecoderDisabledForTesting) {
     195        // HW VP9 Decoder does not support alpha channel:
     196        if (videoConfiguration.alphaChannel && *videoConfiguration.alphaChannel)
     197            return false;
     198
     199        // HW VP9 Decoder can support up to 4K @ 120 or 8K @ 30
     200        auto resolution = resolutionCategory({ (float)videoConfiguration.width, (float)videoConfiguration.height });
     201        if (resolution > ResolutionCategory::R_8K)
     202            return false;
     203        if (resolution == ResolutionCategory::R_8K && videoConfiguration.framerate > 30)
     204            info.smooth = false;
     205        else if (resolution <= ResolutionCategory::R_4K && videoConfiguration.framerate > 120)
     206            info.smooth = false;
     207        else
     208            info.smooth = true;
     209
     210        info.powerEfficient = true;
     211        info.supported = true;
     212        return true;
     213    }
     214
     215    info.powerEfficient = false;
     216
     217    // SW VP9 Decoder has much more variable capabilities depending on CPU characteristics.
     218    // FIXME: Add a lookup table for device-to-capabilities. For now, assume that the SW VP9
     219    // decoder can support 4K @ 30.
     220    if (videoConfiguration.height <= 1080 && videoConfiguration.framerate > 60)
     221        info.smooth = false;
     222    if (videoConfiguration.height <= 2160 && videoConfiguration.framerate > 30)
     223        info.smooth = false;
     224    else
     225        info.smooth = true;
     226
     227    // For wall-powered devices, always report VP9 as supported, even if not powerEfficient.
     228    if (!systemHasBattery()) {
     229        info.supported = true;
     230        return true;
     231    }
     232
     233    // For battery-powered devices, always report VP9 as supported when running on AC power,
     234    // but only on battery when there is an attached screen whose resolution is large enough
     235    // to support 4K video.
     236    if (systemHasAC()) {
     237        info.supported = true;
     238        return true;
     239    }
     240
     241    bool has4kScreen = false;
     242
     243    if (screenSizeAndScaleForTesting) {
     244        auto screenSize = FloatSize(screenSizeAndScaleForTesting->width, screenSizeAndScaleForTesting->height).scaled(screenSizeAndScaleForTesting->scale);
     245        has4kScreen = resolutionCategory(screenSize) >= ResolutionCategory::R_4K;
     246    } else {
     247        for (auto& screenData : getScreenProperties().screenDataMap.values()) {
     248            if (resolutionCategory(screenData.screenRect.size().scaled(screenData.scaleFactor)) >= ResolutionCategory::R_4K) {
     249                has4kScreen = true;
     250                break;
     251            }
     252        }
     253    }
     254
     255    if (!has4kScreen)
     256        return false;
     257
     258    info.supported = true;
    222259    return true;
    223260}
Note: See TracChangeset for help on using the changeset viewer.