Diff
Modified: trunk/Source/WebCore/ChangeLog (225812 => 225813)
--- trunk/Source/WebCore/ChangeLog 2017-12-12 23:12:02 UTC (rev 225812)
+++ trunk/Source/WebCore/ChangeLog 2017-12-12 23:12:20 UTC (rev 225813)
@@ -1,3 +1,47 @@
+2017-12-12 Jer Noble <jer.no...@apple.com>
+
+ [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):
+
2017-12-12 Antoine Quint <grao...@apple.com>
[Web Animations] Expose promises on Animation interface
Modified: trunk/Source/WebCore/platform/graphics/avfoundation/CDMFairPlayStreaming.cpp (225812 => 225813)
--- trunk/Source/WebCore/platform/graphics/avfoundation/CDMFairPlayStreaming.cpp 2017-12-12 23:12:02 UTC (rev 225812)
+++ trunk/Source/WebCore/platform/graphics/avfoundation/CDMFairPlayStreaming.cpp 2017-12-12 23:12:20 UTC (rev 225813)
@@ -62,12 +62,18 @@
return validSchemes;
}
-static const String& sinfName()
+const AtomicString& CDMPrivateFairPlayStreaming::sinfName()
{
- static NeverDestroyed<String> sinf { MAKE_STATIC_STRING_IMPL("sinf") };
+ static NeverDestroyed<AtomicString> sinf { MAKE_STATIC_STRING_IMPL("sinf") };
return sinf;
}
+const AtomicString& CDMPrivateFairPlayStreaming::skdName()
+{
+ static NeverDestroyed<AtomicString> skd { MAKE_STATIC_STRING_IMPL("skd") };
+ return skd;
+}
+
static Vector<Ref<SharedBuffer>> extractSinfData(const SharedBuffer& buffer)
{
// JSON of the format: "{ sinf: [ <base64-encoded-string> ] }"
@@ -84,7 +90,7 @@
return { };
RefPtr<JSON::Array> sinfArray;
- if (!object->getArray(sinfName(), sinfArray))
+ if (!object->getArray(CDMPrivateFairPlayStreaming::sinfName(), sinfArray))
return { };
Vector<Ref<SharedBuffer>> sinfs;
@@ -174,12 +180,34 @@
return buffer.copy();
}
+RefPtr<SharedBuffer> CDMPrivateFairPlayStreaming::sanitizeSkd(const SharedBuffer& buffer)
+{
+ UNUSED_PARAM(buffer);
+ notImplemented();
+ return buffer.copy();
+}
+
+Vector<Ref<SharedBuffer>> CDMPrivateFairPlayStreaming::extractKeyIDsSkd(const SharedBuffer& buffer)
+{
+ // In the 'skd' scheme, the init data is the key ID.
+ Vector<Ref<SharedBuffer>> keyIDs;
+ keyIDs.append(buffer.copy());
+ return keyIDs;
+}
+
+static const HashSet<AtomicString>& validInitDataTypes()
+{
+ static NeverDestroyed<HashSet<AtomicString>> validTypes = HashSet<AtomicString>({ CDMPrivateFairPlayStreaming::sinfName(), CDMPrivateFairPlayStreaming::skdName() });
+ return validTypes;
+}
+
void CDMFactory::platformRegisterFactories(Vector<CDMFactory*>& factories)
{
factories.append(&CDMFactoryClearKey::singleton());
factories.append(&CDMFactoryFairPlayStreaming::singleton());
- InitDataRegistry::shared().registerInitDataType(sinfName(), { CDMPrivateFairPlayStreaming::sanitizeSinf, CDMPrivateFairPlayStreaming::extractKeyIDsSinf });
+ InitDataRegistry::shared().registerInitDataType(CDMPrivateFairPlayStreaming::sinfName(), { CDMPrivateFairPlayStreaming::sanitizeSinf, CDMPrivateFairPlayStreaming::extractKeyIDsSinf });
+ InitDataRegistry::shared().registerInitDataType(CDMPrivateFairPlayStreaming::skdName(), { CDMPrivateFairPlayStreaming::sanitizeSkd, CDMPrivateFairPlayStreaming::extractKeyIDsSkd });
}
CDMFactoryFairPlayStreaming& CDMFactoryFairPlayStreaming::singleton()
@@ -211,12 +239,12 @@
bool CDMPrivateFairPlayStreaming::supportsInitDataType(const AtomicString& initDataType) const
{
- return initDataType == sinfName();
+ return validInitDataTypes().contains(initDataType);
}
bool CDMPrivateFairPlayStreaming::supportsConfiguration(const CDMKeySystemConfiguration& configuration) const
{
- if (!configuration.initDataTypes.contains(sinfName()))
+ if (!WTF::anyOf(configuration.initDataTypes, [] (auto& initDataType) { return validInitDataTypes().contains(initDataType); }))
return false;
#if HAVE(AVCONTENTKEYSESSION)
@@ -331,9 +359,17 @@
if (!supportsInitDataType(initDataType))
return false;
- return WTF::anyOf(extractSchemeAndKeyIdFromSinf(initData), [](auto& result) {
- return validFairPlayStreamingSchemes().contains(result.first);
- });
+ if (initDataType == sinfName()) {
+ return WTF::anyOf(extractSchemeAndKeyIdFromSinf(initData), [](auto& result) {
+ return validFairPlayStreamingSchemes().contains(result.first);
+ });
+ }
+
+ if (initDataType == skdName())
+ return true;
+
+ ASSERT_NOT_REACHED();
+ return false;
}
RefPtr<SharedBuffer> CDMPrivateFairPlayStreaming::sanitizeResponse(const SharedBuffer& response) const
Modified: trunk/Source/WebCore/platform/graphics/avfoundation/CDMFairPlayStreaming.h (225812 => 225813)
--- trunk/Source/WebCore/platform/graphics/avfoundation/CDMFairPlayStreaming.h 2017-12-12 23:12:02 UTC (rev 225812)
+++ trunk/Source/WebCore/platform/graphics/avfoundation/CDMFairPlayStreaming.h 2017-12-12 23:12:20 UTC (rev 225813)
@@ -65,8 +65,13 @@
RefPtr<SharedBuffer> sanitizeResponse(const SharedBuffer&) const override;
std::optional<String> sanitizeSessionId(const String&) const override;
+ static const AtomicString& sinfName();
static Vector<Ref<SharedBuffer>> extractKeyIDsSinf(const SharedBuffer&);
static RefPtr<SharedBuffer> sanitizeSinf(const SharedBuffer&);
+
+ static const AtomicString& skdName();
+ static Vector<Ref<SharedBuffer>> extractKeyIDsSkd(const SharedBuffer&);
+ static RefPtr<SharedBuffer> sanitizeSkd(const SharedBuffer&);
};
}
Modified: trunk/Source/WebCore/platform/graphics/avfoundation/objc/CDMInstanceFairPlayStreamingAVFObjC.h (225812 => 225813)
--- trunk/Source/WebCore/platform/graphics/avfoundation/objc/CDMInstanceFairPlayStreamingAVFObjC.h 2017-12-12 23:12:02 UTC (rev 225812)
+++ trunk/Source/WebCore/platform/graphics/avfoundation/objc/CDMInstanceFairPlayStreamingAVFObjC.h 2017-12-12 23:12:20 UTC (rev 225813)
@@ -81,6 +81,8 @@
WeakPtr<CDMInstanceFairPlayStreamingAVFObjC> createWeakPtr() { return m_weakPtrFactory.createWeakPtr(*this); }
bool isLicenseTypeSupported(LicenseType) const;
+ Vector<Ref<SharedBuffer>> keyIDs();
+
WeakPtrFactory<CDMInstanceFairPlayStreamingAVFObjC> m_weakPtrFactory;
RefPtr<SharedBuffer> m_serverCertificate;
bool m_persistentStateAllowed { true };
Modified: trunk/Source/WebCore/platform/graphics/avfoundation/objc/CDMInstanceFairPlayStreamingAVFObjC.mm (225812 => 225813)
--- trunk/Source/WebCore/platform/graphics/avfoundation/objc/CDMInstanceFairPlayStreamingAVFObjC.mm 2017-12-12 23:12:02 UTC (rev 225812)
+++ trunk/Source/WebCore/platform/graphics/avfoundation/objc/CDMInstanceFairPlayStreamingAVFObjC.mm 2017-12-12 23:12:20 UTC (rev 225813)
@@ -225,8 +225,21 @@
}
}
-void CDMInstanceFairPlayStreamingAVFObjC::requestLicense(LicenseType licenseType, const AtomicString&, Ref<SharedBuffer>&& initData, LicenseCallback callback)
+Vector<Ref<SharedBuffer>> CDMInstanceFairPlayStreamingAVFObjC::keyIDs()
{
+ // FIXME(rdar://problem/35597141): use the future AVContentKeyRequest keyID property, rather than parsing it out of the init
+ // data, to get the keyID.
+ if ([m_request.get().identifier isKindOfClass:[NSString class]])
+ return Vector<Ref<SharedBuffer>>::from(SharedBuffer::create([(NSString *)m_request.get().identifier dataUsingEncoding:NSUTF8StringEncoding]));
+ if ([m_request.get().identifier isKindOfClass:[NSData class]])
+ return Vector<Ref<SharedBuffer>>::from(SharedBuffer::create((NSData *)m_request.get().identifier));
+ if (m_request.get().initializationData)
+ return CDMPrivateFairPlayStreaming::extractKeyIDsSinf(SharedBuffer::create(m_request.get().initializationData));
+ return { };
+}
+
+void CDMInstanceFairPlayStreamingAVFObjC::requestLicense(LicenseType licenseType, const AtomicString& initDataType, Ref<SharedBuffer>&& initData, LicenseCallback callback)
+{
if (!isLicenseTypeSupported(licenseType)) {
callback(SharedBuffer::create(), emptyString(), false, Failed);
return;
@@ -237,9 +250,20 @@
return;
}
+ RetainPtr<NSString> identifier;
+ RetainPtr<NSData> initializationData;
+
+ if (initDataType == CDMPrivateFairPlayStreaming::sinfName())
+ initializationData = initData->createNSData();
+ else if (initDataType == CDMPrivateFairPlayStreaming::skdName())
+ identifier = adoptNS([[NSString alloc] initWithData:initData->createNSData().get() encoding:NSUTF8StringEncoding]);
+ else {
+ callback(SharedBuffer::create(), emptyString(), false, Failed);
+ return;
+ }
+
m_requestLicenseCallback = WTFMove(callback);
-
- [m_session processContentKeyRequestWithIdentifier:nil initializationData:initData->createNSData().get() options:nil];
+ [m_session processContentKeyRequestWithIdentifier:identifier.get() initializationData:initializationData.get() options:nil];
}
static bool isEqual(const SharedBuffer& data, const String& value)
@@ -276,9 +300,7 @@
callback(false, std::nullopt, std::nullopt, std::nullopt, Failed);
return;
}
- // FIXME(rdar://problem/35597141): use the future AVContentKeyRequest keyID property, rather than parsing it out of the init
- // data, to get the keyID.
- Vector<Ref<SharedBuffer>> keyIDs = CDMPrivateFairPlayStreaming::extractKeyIDsSinf(SharedBuffer::create(m_request.get().initializationData));
+ Vector<Ref<SharedBuffer>> keyIDs = this->keyIDs();
if (keyIDs.isEmpty()) {
callback(false, std::nullopt, std::nullopt, std::nullopt, Failed);
return;
@@ -400,7 +422,8 @@
return;
RetainPtr<NSData> appIdentifier = m_serverCertificate ? m_serverCertificate->createNSData() : nullptr;
- Vector<Ref<SharedBuffer>> keyIDs = CDMPrivateFairPlayStreaming::extractKeyIDsSinf(SharedBuffer::create(request.initializationData));
+ Vector<Ref<SharedBuffer>> keyIDs = this->keyIDs();
+
if (keyIDs.isEmpty()) {
m_requestLicenseCallback(SharedBuffer::create(), m_sessionId, false, Failed);
m_requestLicenseCallback = nullptr;
Modified: trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.h (225812 => 225813)
--- trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.h 2017-12-12 23:12:02 UTC (rev 225812)
+++ trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.h 2017-12-12 23:12:20 UTC (rev 225813)
@@ -63,6 +63,7 @@
class AudioSourceProviderAVFObjC;
class AudioTrackPrivateAVFObjC;
+class CDMInstanceFairPlayStreamingAVFObjC;
class CDMSessionAVFoundationObjC;
class InbandMetadataTextTrackPrivateAVF;
class InbandTextTrackPrivateAVFObjC;
@@ -153,6 +154,12 @@
void removeSession(LegacyCDMSession&);
#endif
+#if ENABLE(ENCRYPTED_MEDIA)
+ void cdmInstanceAttached(CDMInstance&) final;
+ void cdmInstanceDetached(CDMInstance&) final;
+ void attemptToDecryptWithInstance(CDMInstance&) final;
+#endif
+
WeakPtr<MediaPlayerPrivateAVFoundationObjC> createWeakPtr() { return m_weakPtrFactory.createWeakPtr(*this); }
private:
@@ -397,6 +404,9 @@
#if ENABLE(LEGACY_ENCRYPTED_MEDIA)
WeakPtr<CDMSessionAVFoundationObjC> m_session;
#endif
+#if ENABLE(ENCRYPTED_MEDIA) && HAVE(AVCONTENTKEYSESSION)
+ RefPtr<CDMInstanceFairPlayStreamingAVFObjC> m_cdmInstance;
+#endif
mutable RetainPtr<NSArray> m_cachedSeekableRanges;
mutable RetainPtr<NSArray> m_cachedLoadedRanges;
Modified: trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.mm (225812 => 225813)
--- trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.mm 2017-12-12 23:12:02 UTC (rev 225812)
+++ trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.mm 2017-12-12 23:12:20 UTC (rev 225813)
@@ -34,6 +34,7 @@
#import "AudioSourceProviderAVFObjC.h"
#import "AudioTrackPrivateAVFObjC.h"
#import "AuthenticationChallenge.h"
+#import "CDMInstanceFairPlayStreamingAVFObjC.h"
#import "CDMSessionAVFoundationObjC.h"
#import "Cookie.h"
#import "DeprecatedGlobalSettings.h"
@@ -54,6 +55,7 @@
#import "PlatformTimeRanges.h"
#import "SecurityOrigin.h"
#import "SerializedPlatformRepresentationMac.h"
+#import "SharedBuffer.h"
#import "TextEncoding.h"
#import "TextTrackRepresentation.h"
#import "TextureCacheCV.h"
@@ -1766,8 +1768,9 @@
String scheme = [[[avRequest request] URL] scheme];
String keyURI = [[[avRequest request] URL] absoluteString];
+#if ENABLE(LEGACY_ENCRYPTED_MEDIA) || ENABLE(ENCRYPTED_MEDIA)
+ if (scheme == "skd") {
#if ENABLE(LEGACY_ENCRYPTED_MEDIA)
- if (scheme == "skd") {
// Create an initData with the following layout:
// [4 bytes: keyURI size], [keyURI size bytes: keyURI]
unsigned keyURISize = keyURI.length() * sizeof(UChar);
@@ -1782,11 +1785,20 @@
RefPtr<Uint8Array> initData = Uint8Array::create(WTFMove(initDataBuffer), 0, byteLength);
if (!player()->keyNeeded(initData.get()))
return false;
+#endif
+ m_keyURIToRequestMap.set(keyURI, avRequest);
+#if ENABLE(ENCRYPTED_MEDIA) && HAVE(AVCONTENTKEYSESSION)
+ if (m_cdmInstance)
+ return false;
- m_keyURIToRequestMap.set(keyURI, avRequest);
+ RetainPtr<NSData> keyURIData = [keyURI dataUsingEncoding:NSUTF8StringEncoding allowLossyConversion:YES];
+ auto keyURIBuffer = SharedBuffer::create(keyURIData.get());
+ player()->initializationDataEncountered(ASCIILiteral("skd"), keyURIBuffer->tryCreateArrayBuffer());
+#endif
return true;
}
+#if ENABLE(LEGACY_ENCRYPTED_MEDIA)
if (scheme == "clearkey") {
String keyID = [[[avRequest request] URL] resourceSpecifier];
auto encodedKeyId = UTF8Encoding().encode(keyID, UnencodableHandling::URLEncodedEntities);
@@ -1807,6 +1819,7 @@
return true;
}
#endif
+#endif
RefPtr<WebCoreAVFResourceLoader> resourceLoader = WebCoreAVFResourceLoader::create(this, avRequest);
m_resourceLoaderMap.add(avRequest, resourceLoader);
@@ -2477,6 +2490,46 @@
#endif
+#if ENABLE(ENCRYPTED_MEDIA)
+void MediaPlayerPrivateAVFoundationObjC::cdmInstanceAttached(CDMInstance& instance)
+{
+#if HAVE(AVCONTENTKEYSESSION)
+ if (!is<CDMInstanceFairPlayStreamingAVFObjC>(instance))
+ return;
+
+ auto& fpsInstance = downcast<CDMInstanceFairPlayStreamingAVFObjC>(instance);
+ if (&fpsInstance == m_cdmInstance)
+ return;
+
+ if (m_cdmInstance)
+ cdmInstanceDetached(*m_cdmInstance);
+
+ m_cdmInstance = &fpsInstance;
+ [m_cdmInstance->contentKeySession() addContentKeyRecipient:m_avAsset.get()];
+#else
+ UNUSED_PARAM(instance);
+#endif
+}
+
+void MediaPlayerPrivateAVFoundationObjC::cdmInstanceDetached(CDMInstance& instance)
+{
+#if HAVE(AVCONTENTKEYSESSION)
+ ASSERT_UNUSED(instance, m_cdmInstance && m_cdmInstance == &instance);
+ [m_cdmInstance->contentKeySession() removeContentKeyRecipient:m_avAsset.get()];
+ m_cdmInstance = nullptr;
+#else
+ UNUSED_PARAM(instance);
+#endif
+}
+
+void MediaPlayerPrivateAVFoundationObjC::attemptToDecryptWithInstance(CDMInstance&)
+{
+ auto keyURIToRequestMap = WTFMove(m_keyURIToRequestMap);
+ for (auto& request : keyURIToRequestMap.values())
+ [request finishLoading];
+}
+#endif
+
#if !HAVE(AVFOUNDATION_LEGIBLE_OUTPUT_SUPPORT)
void MediaPlayerPrivateAVFoundationObjC::processLegacyClosedCaptionsTracks()