Changeset 225813 in webkit


Ignore:
Timestamp:
Dec 12, 2017 3:12:20 PM (6 years ago)
Author:
jer.noble@apple.com
Message:

[EME] Support FPS-over-HLS in the Modern EME API
https://bugs.webkit.org/show_bug.cgi?id=180707

Reviewed by Eric Carlson.

Add support for the "skd" initDataType, where the initData is the URI provided in the
EXT-X-KEY tag in a HLS manifest:

  • platform/graphics/avfoundation/CDMFairPlayStreaming.cpp:

(WebCore::CDMPrivateFairPlayStreaming::sinfName):
(WebCore::CDMPrivateFairPlayStreaming::skdName):
(WebCore::extractSinfData):
(WebCore::CDMPrivateFairPlayStreaming::sanitizeSkd):
(WebCore::CDMPrivateFairPlayStreaming::extractKeyIDsSkd):
(WebCore::validInitDataTypes):
(WebCore::CDMFactory::platformRegisterFactories):
(WebCore::CDMPrivateFairPlayStreaming::supportsInitDataType const):
(WebCore::CDMPrivateFairPlayStreaming::supportsConfiguration const):
(WebCore::CDMPrivateFairPlayStreaming::supportsInitData const):
(WebCore::sinfName): Deleted.

Add support for creating a AVContentKeyRequest from a skd key URI rather than from
initialization data, and for extracting keyIDs from the AVContentKeyRequest identifier.

  • platform/graphics/avfoundation/CDMFairPlayStreaming.h:
  • platform/graphics/avfoundation/objc/CDMInstanceFairPlayStreamingAVFObjC.h:
  • platform/graphics/avfoundation/objc/CDMInstanceFairPlayStreamingAVFObjC.mm:

(WebCore::CDMInstanceFairPlayStreamingAVFObjC::keyIDs):
(WebCore::CDMInstanceFairPlayStreamingAVFObjC::requestLicense):
(WebCore::CDMInstanceFairPlayStreamingAVFObjC::updateLicense):
(WebCore::CDMInstanceFairPlayStreamingAVFObjC::didProvideRequest):

Add support for AVContentKeySession to MediaPlayerPrivateAVFoundationObjC, and for emitting
initializationData messages when encountering a loading request for a "skd" URI.

  • platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.h:
  • platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.mm:

(WebCore::MediaPlayerPrivateAVFoundationObjC::shouldWaitForLoadingOfResource):
(WebCore::MediaPlayerPrivateAVFoundationObjC::cdmInstanceAttached):
(WebCore::MediaPlayerPrivateAVFoundationObjC::cdmInstanceDetached):
(WebCore::MediaPlayerPrivateAVFoundationObjC::attemptToDecryptWithInstance):

Location:
trunk/Source/WebCore
Files:
7 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r225812 r225813  
     12017-12-12  Jer Noble  <jer.noble@apple.com>
     2
     3        [EME] Support FPS-over-HLS in the Modern EME API
     4        https://bugs.webkit.org/show_bug.cgi?id=180707
     5
     6        Reviewed by Eric Carlson.
     7
     8        Add support for the "skd" initDataType, where the initData is the URI provided in the
     9        EXT-X-KEY tag in a HLS manifest:
     10
     11        * platform/graphics/avfoundation/CDMFairPlayStreaming.cpp:
     12        (WebCore::CDMPrivateFairPlayStreaming::sinfName):
     13        (WebCore::CDMPrivateFairPlayStreaming::skdName):
     14        (WebCore::extractSinfData):
     15        (WebCore::CDMPrivateFairPlayStreaming::sanitizeSkd):
     16        (WebCore::CDMPrivateFairPlayStreaming::extractKeyIDsSkd):
     17        (WebCore::validInitDataTypes):
     18        (WebCore::CDMFactory::platformRegisterFactories):
     19        (WebCore::CDMPrivateFairPlayStreaming::supportsInitDataType const):
     20        (WebCore::CDMPrivateFairPlayStreaming::supportsConfiguration const):
     21        (WebCore::CDMPrivateFairPlayStreaming::supportsInitData const):
     22        (WebCore::sinfName): Deleted.
     23
     24        Add support for creating a AVContentKeyRequest from a skd key URI rather than from
     25        initialization data, and for extracting keyIDs from the AVContentKeyRequest identifier.
     26
     27        * platform/graphics/avfoundation/CDMFairPlayStreaming.h:
     28        * platform/graphics/avfoundation/objc/CDMInstanceFairPlayStreamingAVFObjC.h:
     29        * platform/graphics/avfoundation/objc/CDMInstanceFairPlayStreamingAVFObjC.mm:
     30        (WebCore::CDMInstanceFairPlayStreamingAVFObjC::keyIDs):
     31        (WebCore::CDMInstanceFairPlayStreamingAVFObjC::requestLicense):
     32        (WebCore::CDMInstanceFairPlayStreamingAVFObjC::updateLicense):
     33        (WebCore::CDMInstanceFairPlayStreamingAVFObjC::didProvideRequest):
     34
     35        Add support for AVContentKeySession to MediaPlayerPrivateAVFoundationObjC, and for emitting
     36        initializationData messages when encountering a loading request for a "skd" URI.
     37
     38        * platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.h:
     39        * platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.mm:
     40        (WebCore::MediaPlayerPrivateAVFoundationObjC::shouldWaitForLoadingOfResource):
     41        (WebCore::MediaPlayerPrivateAVFoundationObjC::cdmInstanceAttached):
     42        (WebCore::MediaPlayerPrivateAVFoundationObjC::cdmInstanceDetached):
     43        (WebCore::MediaPlayerPrivateAVFoundationObjC::attemptToDecryptWithInstance):
     44
    1452017-12-12  Antoine Quint  <graouts@apple.com>
    246
  • trunk/Source/WebCore/platform/graphics/avfoundation/CDMFairPlayStreaming.cpp

    r225766 r225813  
    6363}
    6464
    65 static const String& sinfName()
    66 {
    67     static NeverDestroyed<String> sinf { MAKE_STATIC_STRING_IMPL("sinf") };
     65const AtomicString& CDMPrivateFairPlayStreaming::sinfName()
     66{
     67    static NeverDestroyed<AtomicString> sinf { MAKE_STATIC_STRING_IMPL("sinf") };
    6868    return sinf;
     69}
     70
     71const AtomicString& CDMPrivateFairPlayStreaming::skdName()
     72{
     73    static NeverDestroyed<AtomicString> skd { MAKE_STATIC_STRING_IMPL("skd") };
     74    return skd;
    6975}
    7076
     
    8591
    8692    RefPtr<JSON::Array> sinfArray;
    87     if (!object->getArray(sinfName(), sinfArray))
     93    if (!object->getArray(CDMPrivateFairPlayStreaming::sinfName(), sinfArray))
    8894        return { };
    8995
     
    175181}
    176182
     183RefPtr<SharedBuffer> CDMPrivateFairPlayStreaming::sanitizeSkd(const SharedBuffer& buffer)
     184{
     185    UNUSED_PARAM(buffer);
     186    notImplemented();
     187    return buffer.copy();
     188}
     189
     190Vector<Ref<SharedBuffer>> CDMPrivateFairPlayStreaming::extractKeyIDsSkd(const SharedBuffer& buffer)
     191{
     192    // In the 'skd' scheme, the init data is the key ID.
     193    Vector<Ref<SharedBuffer>> keyIDs;
     194    keyIDs.append(buffer.copy());
     195    return keyIDs;
     196}
     197
     198static const HashSet<AtomicString>& validInitDataTypes()
     199{
     200    static NeverDestroyed<HashSet<AtomicString>> validTypes = HashSet<AtomicString>({ CDMPrivateFairPlayStreaming::sinfName(), CDMPrivateFairPlayStreaming::skdName() });
     201    return validTypes;
     202}
     203
    177204void CDMFactory::platformRegisterFactories(Vector<CDMFactory*>& factories)
    178205{
     
    180207    factories.append(&CDMFactoryFairPlayStreaming::singleton());
    181208
    182     InitDataRegistry::shared().registerInitDataType(sinfName(), { CDMPrivateFairPlayStreaming::sanitizeSinf, CDMPrivateFairPlayStreaming::extractKeyIDsSinf });
     209    InitDataRegistry::shared().registerInitDataType(CDMPrivateFairPlayStreaming::sinfName(), { CDMPrivateFairPlayStreaming::sanitizeSinf, CDMPrivateFairPlayStreaming::extractKeyIDsSinf });
     210    InitDataRegistry::shared().registerInitDataType(CDMPrivateFairPlayStreaming::skdName(), { CDMPrivateFairPlayStreaming::sanitizeSkd, CDMPrivateFairPlayStreaming::extractKeyIDsSkd });
    183211}
    184212
     
    212240bool CDMPrivateFairPlayStreaming::supportsInitDataType(const AtomicString& initDataType) const
    213241{
    214     return initDataType == sinfName();
     242    return validInitDataTypes().contains(initDataType);
    215243}
    216244
    217245bool CDMPrivateFairPlayStreaming::supportsConfiguration(const CDMKeySystemConfiguration& configuration) const
    218246{
    219     if (!configuration.initDataTypes.contains(sinfName()))
     247    if (!WTF::anyOf(configuration.initDataTypes, [] (auto& initDataType) { return validInitDataTypes().contains(initDataType); }))
    220248        return false;
    221249
     
    332360        return false;
    333361
    334     return WTF::anyOf(extractSchemeAndKeyIdFromSinf(initData), [](auto& result) {
    335         return validFairPlayStreamingSchemes().contains(result.first);
    336     });
     362    if (initDataType == sinfName()) {
     363        return WTF::anyOf(extractSchemeAndKeyIdFromSinf(initData), [](auto& result) {
     364            return validFairPlayStreamingSchemes().contains(result.first);
     365        });
     366    }
     367
     368    if (initDataType == skdName())
     369        return true;
     370
     371    ASSERT_NOT_REACHED();
     372    return false;
    337373}
    338374
  • trunk/Source/WebCore/platform/graphics/avfoundation/CDMFairPlayStreaming.h

    r225637 r225813  
    6666    std::optional<String> sanitizeSessionId(const String&) const override;
    6767
     68    static const AtomicString& sinfName();
    6869    static Vector<Ref<SharedBuffer>> extractKeyIDsSinf(const SharedBuffer&);
    6970    static RefPtr<SharedBuffer> sanitizeSinf(const SharedBuffer&);
     71
     72    static const AtomicString& skdName();
     73    static Vector<Ref<SharedBuffer>> extractKeyIDsSkd(const SharedBuffer&);
     74    static RefPtr<SharedBuffer> sanitizeSkd(const SharedBuffer&);
    7075};
    7176
  • trunk/Source/WebCore/platform/graphics/avfoundation/objc/CDMInstanceFairPlayStreamingAVFObjC.h

    r225802 r225813  
    8282    bool isLicenseTypeSupported(LicenseType) const;
    8383
     84    Vector<Ref<SharedBuffer>> keyIDs();
     85
    8486    WeakPtrFactory<CDMInstanceFairPlayStreamingAVFObjC> m_weakPtrFactory;
    8587    RefPtr<SharedBuffer> m_serverCertificate;
  • trunk/Source/WebCore/platform/graphics/avfoundation/objc/CDMInstanceFairPlayStreamingAVFObjC.mm

    r225802 r225813  
    226226}
    227227
    228 void CDMInstanceFairPlayStreamingAVFObjC::requestLicense(LicenseType licenseType, const AtomicString&, Ref<SharedBuffer>&& initData, LicenseCallback callback)
     228Vector<Ref<SharedBuffer>> CDMInstanceFairPlayStreamingAVFObjC::keyIDs()
     229{
     230    // FIXME(rdar://problem/35597141): use the future AVContentKeyRequest keyID property, rather than parsing it out of the init
     231    // data, to get the keyID.
     232    if ([m_request.get().identifier isKindOfClass:[NSString class]])
     233        return Vector<Ref<SharedBuffer>>::from(SharedBuffer::create([(NSString *)m_request.get().identifier dataUsingEncoding:NSUTF8StringEncoding]));
     234    if ([m_request.get().identifier isKindOfClass:[NSData class]])
     235        return Vector<Ref<SharedBuffer>>::from(SharedBuffer::create((NSData *)m_request.get().identifier));
     236    if (m_request.get().initializationData)
     237        return CDMPrivateFairPlayStreaming::extractKeyIDsSinf(SharedBuffer::create(m_request.get().initializationData));
     238    return { };
     239}
     240
     241void CDMInstanceFairPlayStreamingAVFObjC::requestLicense(LicenseType licenseType, const AtomicString& initDataType, Ref<SharedBuffer>&& initData, LicenseCallback callback)
    229242{
    230243    if (!isLicenseTypeSupported(licenseType)) {
     
    238251    }
    239252
     253    RetainPtr<NSString> identifier;
     254    RetainPtr<NSData> initializationData;
     255
     256    if (initDataType == CDMPrivateFairPlayStreaming::sinfName())
     257        initializationData = initData->createNSData();
     258    else if (initDataType == CDMPrivateFairPlayStreaming::skdName())
     259        identifier = adoptNS([[NSString alloc] initWithData:initData->createNSData().get() encoding:NSUTF8StringEncoding]);
     260    else {
     261        callback(SharedBuffer::create(), emptyString(), false, Failed);
     262        return;
     263    }
     264
    240265    m_requestLicenseCallback = WTFMove(callback);
    241 
    242     [m_session processContentKeyRequestWithIdentifier:nil initializationData:initData->createNSData().get() options:nil];
     266    [m_session processContentKeyRequestWithIdentifier:identifier.get() initializationData:initializationData.get() options:nil];
    243267}
    244268
     
    277301        return;
    278302    }
    279     // FIXME(rdar://problem/35597141): use the future AVContentKeyRequest keyID property, rather than parsing it out of the init
    280     // data, to get the keyID.
    281     Vector<Ref<SharedBuffer>> keyIDs = CDMPrivateFairPlayStreaming::extractKeyIDsSinf(SharedBuffer::create(m_request.get().initializationData));
     303    Vector<Ref<SharedBuffer>> keyIDs = this->keyIDs();
    282304    if (keyIDs.isEmpty()) {
    283305        callback(false, std::nullopt, std::nullopt, std::nullopt, Failed);
     
    401423
    402424    RetainPtr<NSData> appIdentifier = m_serverCertificate ? m_serverCertificate->createNSData() : nullptr;
    403     Vector<Ref<SharedBuffer>> keyIDs = CDMPrivateFairPlayStreaming::extractKeyIDsSinf(SharedBuffer::create(request.initializationData));
     425    Vector<Ref<SharedBuffer>> keyIDs = this->keyIDs();
     426
    404427    if (keyIDs.isEmpty()) {
    405428        m_requestLicenseCallback(SharedBuffer::create(), m_sessionId, false, Failed);
  • trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.h

    r225638 r225813  
    6464class AudioSourceProviderAVFObjC;
    6565class AudioTrackPrivateAVFObjC;
     66class CDMInstanceFairPlayStreamingAVFObjC;
    6667class CDMSessionAVFoundationObjC;
    6768class InbandMetadataTextTrackPrivateAVF;
     
    154155#endif
    155156
     157#if ENABLE(ENCRYPTED_MEDIA)
     158    void cdmInstanceAttached(CDMInstance&) final;
     159    void cdmInstanceDetached(CDMInstance&) final;
     160    void attemptToDecryptWithInstance(CDMInstance&) final;
     161#endif
     162
    156163    WeakPtr<MediaPlayerPrivateAVFoundationObjC> createWeakPtr() { return m_weakPtrFactory.createWeakPtr(*this); }
    157164
     
    397404#if ENABLE(LEGACY_ENCRYPTED_MEDIA)
    398405    WeakPtr<CDMSessionAVFoundationObjC> m_session;
     406#endif
     407#if ENABLE(ENCRYPTED_MEDIA) && HAVE(AVCONTENTKEYSESSION)
     408    RefPtr<CDMInstanceFairPlayStreamingAVFObjC> m_cdmInstance;
    399409#endif
    400410
  • trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.mm

    r225696 r225813  
    3535#import "AudioTrackPrivateAVFObjC.h"
    3636#import "AuthenticationChallenge.h"
     37#import "CDMInstanceFairPlayStreamingAVFObjC.h"
    3738#import "CDMSessionAVFoundationObjC.h"
    3839#import "Cookie.h"
     
    5556#import "SecurityOrigin.h"
    5657#import "SerializedPlatformRepresentationMac.h"
     58#import "SharedBuffer.h"
    5759#import "TextEncoding.h"
    5860#import "TextTrackRepresentation.h"
     
    17671769    String keyURI = [[[avRequest request] URL] absoluteString];
    17681770
     1771#if ENABLE(LEGACY_ENCRYPTED_MEDIA) || ENABLE(ENCRYPTED_MEDIA)
     1772    if (scheme == "skd") {
    17691773#if ENABLE(LEGACY_ENCRYPTED_MEDIA)
    1770     if (scheme == "skd") {
    17711774        // Create an initData with the following layout:
    17721775        // [4 bytes: keyURI size], [keyURI size bytes: keyURI]
     
    17831786        if (!player()->keyNeeded(initData.get()))
    17841787            return false;
    1785 
     1788#endif
    17861789        m_keyURIToRequestMap.set(keyURI, avRequest);
     1790#if ENABLE(ENCRYPTED_MEDIA) && HAVE(AVCONTENTKEYSESSION)
     1791        if (m_cdmInstance)
     1792            return false;
     1793
     1794        RetainPtr<NSData> keyURIData = [keyURI dataUsingEncoding:NSUTF8StringEncoding allowLossyConversion:YES];
     1795        auto keyURIBuffer = SharedBuffer::create(keyURIData.get());
     1796        player()->initializationDataEncountered(ASCIILiteral("skd"), keyURIBuffer->tryCreateArrayBuffer());
     1797#endif
    17871798        return true;
    17881799    }
    17891800
     1801#if ENABLE(LEGACY_ENCRYPTED_MEDIA)
    17901802    if (scheme == "clearkey") {
    17911803        String keyID = [[[avRequest request] URL] resourceSpecifier];
     
    18071819        return true;
    18081820    }
     1821#endif
    18091822#endif
    18101823
     
    24762489}
    24772490
     2491#endif
     2492
     2493#if ENABLE(ENCRYPTED_MEDIA)
     2494void MediaPlayerPrivateAVFoundationObjC::cdmInstanceAttached(CDMInstance& instance)
     2495{
     2496#if HAVE(AVCONTENTKEYSESSION)
     2497    if (!is<CDMInstanceFairPlayStreamingAVFObjC>(instance))
     2498        return;
     2499
     2500    auto& fpsInstance = downcast<CDMInstanceFairPlayStreamingAVFObjC>(instance);
     2501    if (&fpsInstance == m_cdmInstance)
     2502        return;
     2503
     2504    if (m_cdmInstance)
     2505        cdmInstanceDetached(*m_cdmInstance);
     2506
     2507    m_cdmInstance = &fpsInstance;
     2508    [m_cdmInstance->contentKeySession() addContentKeyRecipient:m_avAsset.get()];
     2509#else
     2510    UNUSED_PARAM(instance);
     2511#endif
     2512}
     2513
     2514void MediaPlayerPrivateAVFoundationObjC::cdmInstanceDetached(CDMInstance& instance)
     2515{
     2516#if HAVE(AVCONTENTKEYSESSION)
     2517    ASSERT_UNUSED(instance, m_cdmInstance && m_cdmInstance == &instance);
     2518    [m_cdmInstance->contentKeySession() removeContentKeyRecipient:m_avAsset.get()];
     2519    m_cdmInstance = nullptr;
     2520#else
     2521    UNUSED_PARAM(instance);
     2522#endif
     2523}
     2524
     2525void MediaPlayerPrivateAVFoundationObjC::attemptToDecryptWithInstance(CDMInstance&)
     2526{
     2527    auto keyURIToRequestMap = WTFMove(m_keyURIToRequestMap);
     2528    for (auto& request : keyURIToRequestMap.values())
     2529        [request finishLoading];
     2530}
    24782531#endif
    24792532
Note: See TracChangeset for help on using the changeset viewer.