[EME][GStreamer] Ensure key id buffers are present and simplify lifetime management...
authorcturner@igalia.com <cturner@igalia.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 7 Nov 2018 11:50:30 +0000 (11:50 +0000)
committercturner@igalia.com <cturner@igalia.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 7 Nov 2018 11:50:30 +0000 (11:50 +0000)
https://bugs.webkit.org/show_bug.cgi?id=191157

Reviewed by Xabier Rodriguez-Calvar.

This is in preparation for moving the clearkey decryptor behind a
new decrypt API in CDMInstance, which will be sent into the
pipeline to handle key management and decryption. This is for a
later patch.

Covered by existing clear key tests in media/encrypted-media.

* platform/graphics/gstreamer/GStreamerCommon.h:
(WebCore::GstMappedBuffer::data const): Add a const data accessor,
since we are now providing operator=='s on const objects of this
class that need const access to the data pointer.
(WebCore::GstMappedBuffer::operator==): Add a swap of the new
equality operator so you don't have to remember to have the
GstBuffer on the RHS of the equality all the time.
(WebCore::operator==): Define an equality operator between Gst
buffers and WebCore's mapped buffers. Gst creates a ref and a
separate read view under the covers in the memcmp call, so we do
not need to map the buffer ourselves.
* platform/graphics/gstreamer/eme/WebKitClearKeyDecryptorGStreamer.cpp:
(webkit_media_clear_key_decrypt_class_init): Remove setup/release
bindings.
(webkit_media_clear_key_decrypt_init): Initialize gcrypt cipher
here once instead of for every buffer to be decrypted.
(webKitMediaClearKeyDecryptorFinalize): And destroy the cipher
context when the decryptor is destroyed.
(webKitMediaClearKeyDecryptorFindAndSetKey): Factor out the key
retrieval and context setting in this method, call it for each
sample.
(webKitMediaClearKeyDecryptorDecrypt): Base key id buffer into
this function, and remove cipher creation / destroy methods.
* platform/graphics/gstreamer/eme/WebKitCommonEncryptionDecryptorGStreamer.cpp:
(webkit_media_common_encryption_decrypt_class_init): Remove
setup/release bindings.
(webkitMediaCommonEncryptionDecryptTransformInPlace): Ensure a key
id is present and pass it to the decrypt class method.
(webKitMediaCommonEncryptionDecryptDefaultSetupCipher): Deleted.
(webKitMediaCommonEncryptionDecryptDefaultReleaseCipher): Deleted.
* platform/graphics/gstreamer/eme/WebKitCommonEncryptionDecryptorGStreamer.h:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@237921 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/WebCore/ChangeLog
Source/WebCore/platform/graphics/gstreamer/GStreamerCommon.h
Source/WebCore/platform/graphics/gstreamer/eme/WebKitClearKeyDecryptorGStreamer.cpp
Source/WebCore/platform/graphics/gstreamer/eme/WebKitCommonEncryptionDecryptorGStreamer.cpp
Source/WebCore/platform/graphics/gstreamer/eme/WebKitCommonEncryptionDecryptorGStreamer.h

index 43f38aa..e11109e 100644 (file)
@@ -1,3 +1,49 @@
+2018-11-07  Charlie Turner  <cturner@igalia.com>
+
+        [EME][GStreamer] Ensure key id buffers are present and simplify lifetime management of ClearKey class.
+        https://bugs.webkit.org/show_bug.cgi?id=191157
+
+        Reviewed by Xabier Rodriguez-Calvar.
+
+        This is in preparation for moving the clearkey decryptor behind a
+        new decrypt API in CDMInstance, which will be sent into the
+        pipeline to handle key management and decryption. This is for a
+        later patch.
+
+        Covered by existing clear key tests in media/encrypted-media.
+
+        * platform/graphics/gstreamer/GStreamerCommon.h:
+        (WebCore::GstMappedBuffer::data const): Add a const data accessor,
+        since we are now providing operator=='s on const objects of this
+        class that need const access to the data pointer.
+        (WebCore::GstMappedBuffer::operator==): Add a swap of the new
+        equality operator so you don't have to remember to have the
+        GstBuffer on the RHS of the equality all the time.
+        (WebCore::operator==): Define an equality operator between Gst
+        buffers and WebCore's mapped buffers. Gst creates a ref and a
+        separate read view under the covers in the memcmp call, so we do
+        not need to map the buffer ourselves.
+        * platform/graphics/gstreamer/eme/WebKitClearKeyDecryptorGStreamer.cpp:
+        (webkit_media_clear_key_decrypt_class_init): Remove setup/release
+        bindings.
+        (webkit_media_clear_key_decrypt_init): Initialize gcrypt cipher
+        here once instead of for every buffer to be decrypted.
+        (webKitMediaClearKeyDecryptorFinalize): And destroy the cipher
+        context when the decryptor is destroyed.
+        (webKitMediaClearKeyDecryptorFindAndSetKey): Factor out the key
+        retrieval and context setting in this method, call it for each
+        sample.
+        (webKitMediaClearKeyDecryptorDecrypt): Base key id buffer into
+        this function, and remove cipher creation / destroy methods.
+        * platform/graphics/gstreamer/eme/WebKitCommonEncryptionDecryptorGStreamer.cpp:
+        (webkit_media_common_encryption_decrypt_class_init): Remove
+        setup/release bindings.
+        (webkitMediaCommonEncryptionDecryptTransformInPlace): Ensure a key
+        id is present and pass it to the decrypt class method.
+        (webKitMediaCommonEncryptionDecryptDefaultSetupCipher): Deleted.
+        (webKitMediaCommonEncryptionDecryptDefaultReleaseCipher): Deleted.
+        * platform/graphics/gstreamer/eme/WebKitCommonEncryptionDecryptorGStreamer.h:
+
 2018-11-07  Frederic Wang  <fwang@igalia.com>
 
         [Cairo] Move state change operations from GraphicsContextCairo to CairoOperations
index 110b6ee..f7c8d2a 100644 (file)
@@ -108,15 +108,33 @@ public:
     }
 
     uint8_t* data() { ASSERT(m_isValid); return static_cast<uint8_t*>(m_info.data); }
+    const uint8_t* data() const { ASSERT(m_isValid); return static_cast<uint8_t*>(m_info.data); }
+
     size_t size() const { ASSERT(m_isValid); return static_cast<size_t>(m_info.size); }
 
     explicit operator bool() const { return m_isValid; }
+
 private:
+    friend bool operator==(const GstMappedBuffer&, const GstMappedBuffer&);
+    friend bool operator==(const GstMappedBuffer&, const GstBuffer*);
+    friend bool operator==(const GstBuffer* a, const GstMappedBuffer& b) { return operator==(b, a); }
+
     GstBuffer* m_buffer { nullptr };
     GstMapInfo m_info;
     bool m_isValid { false };
 };
 
+inline bool operator==(const GstMappedBuffer& a, const GstMappedBuffer& b)
+{
+    return a.size() == b.size() && !gst_buffer_memcmp(a.m_buffer, 0, b.data(), b.size());
+}
+
+inline bool operator==(const GstMappedBuffer& a, const GstBuffer* b)
+{
+    GstBuffer* nonConstB = const_cast<GstBuffer*>(b);
+    return a.size() == gst_buffer_get_size(nonConstB) && !gst_buffer_memcmp(nonConstB, 0, a.data(), a.size());
+}
+
 bool gstRegistryHasElementForMediaType(GList* elementFactories, const char* capsString);
 void connectSimpleBusMessageCallback(GstElement *pipeline);
 void disconnectSimpleBusMessageCallback(GstElement *pipeline);
index 8ae3a56..33f6089 100644 (file)
@@ -45,9 +45,7 @@ struct _WebKitMediaClearKeyDecryptPrivate {
 
 static void webKitMediaClearKeyDecryptorFinalize(GObject*);
 static gboolean webKitMediaClearKeyDecryptorHandleKeyResponse(WebKitMediaCommonEncryptionDecrypt* self, GstEvent*);
-static gboolean webKitMediaClearKeyDecryptorSetupCipher(WebKitMediaCommonEncryptionDecrypt*, GstBuffer*);
-static gboolean webKitMediaClearKeyDecryptorDecrypt(WebKitMediaCommonEncryptionDecrypt*, GstBuffer* iv, GstBuffer* sample, unsigned subSamplesCount, GstBuffer* subSamples);
-static void webKitMediaClearKeyDecryptorReleaseCipher(WebKitMediaCommonEncryptionDecrypt*);
+static gboolean webKitMediaClearKeyDecryptorDecrypt(WebKitMediaCommonEncryptionDecrypt*, GstBuffer* iv, GstBuffer* keyid, GstBuffer* sample, unsigned subSamplesCount, GstBuffer* subSamples);
 
 GST_DEBUG_CATEGORY_STATIC(webkit_media_clear_key_decrypt_debug_category);
 #define GST_CAT_DEFAULT webkit_media_clear_key_decrypt_debug_category
@@ -89,9 +87,7 @@ static void webkit_media_clear_key_decrypt_class_init(WebKitMediaClearKeyDecrypt
     WebKitMediaCommonEncryptionDecryptClass* cencClass = WEBKIT_MEDIA_CENC_DECRYPT_CLASS(klass);
     cencClass->protectionSystemId = WebCore::GStreamerEMEUtilities::s_ClearKeyUUID;
     cencClass->handleKeyResponse = GST_DEBUG_FUNCPTR(webKitMediaClearKeyDecryptorHandleKeyResponse);
-    cencClass->setupCipher = GST_DEBUG_FUNCPTR(webKitMediaClearKeyDecryptorSetupCipher);
     cencClass->decrypt = GST_DEBUG_FUNCPTR(webKitMediaClearKeyDecryptorDecrypt);
-    cencClass->releaseCipher = GST_DEBUG_FUNCPTR(webKitMediaClearKeyDecryptorReleaseCipher);
 
     g_type_class_add_private(klass, sizeof(WebKitMediaClearKeyDecryptPrivate));
 }
@@ -102,13 +98,17 @@ static void webkit_media_clear_key_decrypt_init(WebKitMediaClearKeyDecrypt* self
 
     self->priv = priv;
     new (priv) WebKitMediaClearKeyDecryptPrivate();
+    if (gcry_error_t error = gcry_cipher_open(&(priv->handle), GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_CTR, GCRY_CIPHER_SECURE)) {
+        GST_ERROR_OBJECT(self, "Failed to create AES 128 CTR cipher handle: %s", gpg_strerror(error));
+        ASSERT(!error);
+    }
 }
 
 static void webKitMediaClearKeyDecryptorFinalize(GObject* object)
 {
     WebKitMediaClearKeyDecrypt* self = WEBKIT_MEDIA_CK_DECRYPT(object);
     WebKitMediaClearKeyDecryptPrivate* priv = self->priv;
-
+    gcry_cipher_close(priv->handle);
     priv->~WebKitMediaClearKeyDecryptPrivate();
 
     GST_CALL_PARENT(G_OBJECT_CLASS, finalize, (object));
@@ -150,58 +150,37 @@ static gboolean webKitMediaClearKeyDecryptorHandleKeyResponse(WebKitMediaCommonE
     return TRUE;
 }
 
-static gboolean webKitMediaClearKeyDecryptorSetupCipher(WebKitMediaCommonEncryptionDecrypt* self, GstBuffer* keyIDBuffer)
+static gboolean webKitMediaClearKeyDecryptorFindAndSetKey(WebKitMediaClearKeyDecryptPrivate* priv, const WebCore::GstMappedBuffer& keyIDBuffer)
 {
-    if (!keyIDBuffer) {
-        GST_ERROR_OBJECT(self, "got no key id buffer");
-        return false;
-    }
-
-    WebKitMediaClearKeyDecryptPrivate* priv = WEBKIT_MEDIA_CK_DECRYPT_GET_PRIVATE(WEBKIT_MEDIA_CK_DECRYPT(self));
-    gcry_error_t error;
-
     GRefPtr<GstBuffer> keyBuffer;
-    WebCore::GstMappedBuffer mappedKeyIdBuffer(keyIDBuffer, GST_MAP_READ);
-    if (!mappedKeyIdBuffer) {
-        GST_ERROR_OBJECT(self, "Failed to map key ID buffer");
-        return false;
-    }
-
     for (auto& key : priv->keys) {
-        if (!gst_buffer_memcmp(key.keyID.get(), 0, mappedKeyIdBuffer.data(), mappedKeyIdBuffer.size())) {
+        if (key.keyID.get() == keyIDBuffer) {
             keyBuffer = key.keyValue;
             break;
         }
     }
 
     if (!keyBuffer) {
-        GST_ERROR_OBJECT(self, "Failed to find an appropriate key buffer");
+        GST_ERROR_OBJECT(priv, "Failed to find an appropriate key buffer");
         return false;
     }
 
-    error = gcry_cipher_open(&(priv->handle), GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_CTR, GCRY_CIPHER_SECURE);
-    if (error) {
-        GST_ERROR_OBJECT(self, "Failed to create AES 128 CTR cipher handle: %s", gpg_strerror(error));
+    WebCore::GstMappedBuffer mappedKeyValueBuffer(keyBuffer.get(), GST_MAP_READ);
+    if (!mappedKeyValueBuffer) {
+        GST_ERROR_OBJECT(priv, "Failed to map decryption key");
         return false;
     }
 
-    WebCore::GstMappedBuffer mappedKeyBuffer(keyBuffer.get(), GST_MAP_READ);
-    if (!mappedKeyBuffer) {
-        GST_ERROR_OBJECT(self, "Failed to map decryption key");
-        return false;
-    }
-
-    ASSERT(mappedKeyBuffer.size() == CLEARKEY_SIZE);
-    error = gcry_cipher_setkey(priv->handle, mappedKeyBuffer.data(), mappedKeyBuffer.size());
-    if (error) {
-        GST_ERROR_OBJECT(self, "gcry_cipher_setkey failed: %s", gpg_strerror(error));
+    ASSERT(mappedKeyValueBuffer.size() == CLEARKEY_SIZE);
+    if (gcry_error_t error = gcry_cipher_setkey(priv->handle, mappedKeyValueBuffer.data(), mappedKeyValueBuffer.size())) {
+        GST_ERROR_OBJECT(priv, "gcry_cipher_setkey failed: %s", gpg_strerror(error));
         return false;
     }
 
     return true;
 }
 
-static gboolean webKitMediaClearKeyDecryptorDecrypt(WebKitMediaCommonEncryptionDecrypt* self, GstBuffer* ivBuffer, GstBuffer* buffer, unsigned subSampleCount, GstBuffer* subSamplesBuffer)
+static gboolean webKitMediaClearKeyDecryptorDecrypt(WebKitMediaCommonEncryptionDecrypt* self, GstBuffer* ivBuffer, GstBuffer* keyIDBuffer, GstBuffer* buffer, unsigned subSampleCount, GstBuffer* subSamplesBuffer)
 {
     // Check ivBuffer isn't null.
     if (!ivBuffer) {
@@ -233,7 +212,13 @@ static gboolean webKitMediaClearKeyDecryptorDecrypt(WebKitMediaCommonEncryptionD
 
     // Check buffer isn't null.
     if (!buffer) {
-        GST_ERROR_OBJECT(self, "Error, the buffer is null");
+        GST_ERROR_OBJECT(self, "No buffer to decrypt");
+        return false;
+    }
+
+    WebCore::GstMappedBuffer mappedKeyIdBuffer(keyIDBuffer, GST_MAP_READ);
+    if (!mappedKeyIdBuffer) {
+        GST_ERROR_OBJECT(self, "Failed to map key id buffer");
         return false;
     }
 
@@ -243,6 +228,8 @@ static gboolean webKitMediaClearKeyDecryptorDecrypt(WebKitMediaCommonEncryptionD
         return false;
     }
 
+    webKitMediaClearKeyDecryptorFindAndSetKey(priv, mappedKeyIdBuffer);
+
     unsigned position = 0;
     unsigned sampleIndex = 0;
 
@@ -309,10 +296,4 @@ static gboolean webKitMediaClearKeyDecryptorDecrypt(WebKitMediaCommonEncryptionD
     return true;
 }
 
-static void webKitMediaClearKeyDecryptorReleaseCipher(WebKitMediaCommonEncryptionDecrypt* self)
-{
-    WebKitMediaClearKeyDecryptPrivate* priv = WEBKIT_MEDIA_CK_DECRYPT_GET_PRIVATE(WEBKIT_MEDIA_CK_DECRYPT(self));
-    gcry_cipher_close(priv->handle);
-}
-
 #endif // ENABLE(ENCRYPTED_MEDIA) && USE(GSTREAMER)
index 297cb5d..dd2619f 100644 (file)
@@ -45,8 +45,6 @@ static GstCaps* webkitMediaCommonEncryptionDecryptTransformCaps(GstBaseTransform
 static GstFlowReturn webkitMediaCommonEncryptionDecryptTransformInPlace(GstBaseTransform*, GstBuffer*);
 static gboolean webkitMediaCommonEncryptionDecryptSinkEventHandler(GstBaseTransform*, GstEvent*);
 
-static gboolean webKitMediaCommonEncryptionDecryptDefaultSetupCipher(WebKitMediaCommonEncryptionDecrypt*, GstBuffer*);
-static void webKitMediaCommonEncryptionDecryptDefaultReleaseCipher(WebKitMediaCommonEncryptionDecrypt*);
 
 GST_DEBUG_CATEGORY_STATIC(webkit_media_common_encryption_decrypt_debug_category);
 #define GST_CAT_DEFAULT webkit_media_common_encryption_decrypt_debug_category
@@ -71,9 +69,6 @@ static void webkit_media_common_encryption_decrypt_class_init(WebKitMediaCommonE
     baseTransformClass->transform_ip_on_passthrough = FALSE;
     baseTransformClass->sink_event = GST_DEBUG_FUNCPTR(webkitMediaCommonEncryptionDecryptSinkEventHandler);
 
-    klass->setupCipher = GST_DEBUG_FUNCPTR(webKitMediaCommonEncryptionDecryptDefaultSetupCipher);
-    klass->releaseCipher = GST_DEBUG_FUNCPTR(webKitMediaCommonEncryptionDecryptDefaultReleaseCipher);
-
     g_type_class_add_private(klass, sizeof(WebKitMediaCommonEncryptionDecryptPrivate));
 }
 
@@ -269,35 +264,31 @@ static GstFlowReturn webkitMediaCommonEncryptionDecryptTransformInPlace(GstBaseT
     }
 
     value = gst_structure_get_value(protectionMeta->info, "kid");
-    GstBuffer* keyIDBuffer = nullptr;
-    if (value)
-        keyIDBuffer = gst_value_get_buffer(value);
 
-    WebKitMediaCommonEncryptionDecryptClass* klass = WEBKIT_MEDIA_CENC_DECRYPT_GET_CLASS(self);
-    if (!klass->setupCipher(self, keyIDBuffer)) {
-        GST_ERROR_OBJECT(self, "Failed to configure cipher");
+    if (!value) {
+        GST_ERROR_OBJECT(self, "Failed to get key id for buffer");
         gst_buffer_remove_meta(buffer, reinterpret_cast<GstMeta*>(protectionMeta));
         return GST_FLOW_NOT_SUPPORTED;
     }
+    GstBuffer* keyIDBuffer = gst_value_get_buffer(value);
 
     value = gst_structure_get_value(protectionMeta->info, "iv");
     if (!value) {
         GST_ERROR_OBJECT(self, "Failed to get IV for sample");
-        klass->releaseCipher(self);
         gst_buffer_remove_meta(buffer, reinterpret_cast<GstMeta*>(protectionMeta));
         return GST_FLOW_NOT_SUPPORTED;
     }
 
     GstBuffer* ivBuffer = gst_value_get_buffer(value);
+    WebKitMediaCommonEncryptionDecryptClass* klass = WEBKIT_MEDIA_CENC_DECRYPT_GET_CLASS(self);
+
     GST_TRACE_OBJECT(self, "decrypting");
-    if (!klass->decrypt(self, ivBuffer, buffer, subSampleCount, subSamplesBuffer)) {
+    if (!klass->decrypt(self, ivBuffer, keyIDBuffer, buffer, subSampleCount, subSamplesBuffer)) {
         GST_ERROR_OBJECT(self, "Decryption failed");
-        klass->releaseCipher(self);
         gst_buffer_remove_meta(buffer, reinterpret_cast<GstMeta*>(protectionMeta));
         return GST_FLOW_NOT_SUPPORTED;
     }
 
-    klass->releaseCipher(self);
     gst_buffer_remove_meta(buffer, reinterpret_cast<GstMeta*>(protectionMeta));
     return GST_FLOW_OK;
 }
@@ -356,15 +347,4 @@ static GstStateChangeReturn webKitMediaCommonEncryptionDecryptorChangeState(GstE
     return result;
 }
 
-
-static gboolean webKitMediaCommonEncryptionDecryptDefaultSetupCipher(WebKitMediaCommonEncryptionDecrypt*, GstBuffer*)
-{
-    return true;
-}
-
-
-static void webKitMediaCommonEncryptionDecryptDefaultReleaseCipher(WebKitMediaCommonEncryptionDecrypt*)
-{
-}
-
 #endif // ENABLE(ENCRYPTED_MEDIA) && USE(GSTREAMER)
index 267791a..2221125 100644 (file)
@@ -54,9 +54,7 @@ struct _WebKitMediaCommonEncryptionDecryptClass {
 
     const char* protectionSystemId;
     gboolean (*handleKeyResponse)(WebKitMediaCommonEncryptionDecrypt*, GstEvent* event);
-    gboolean (*setupCipher)(WebKitMediaCommonEncryptionDecrypt*, GstBuffer*);
-    gboolean (*decrypt)(WebKitMediaCommonEncryptionDecrypt*, GstBuffer* ivBuffer, GstBuffer* buffer, unsigned subSamplesCount, GstBuffer* subSamplesBuffer);
-    void (*releaseCipher)(WebKitMediaCommonEncryptionDecrypt*);
+    gboolean (*decrypt)(WebKitMediaCommonEncryptionDecrypt*, GstBuffer* ivBuffer, GstBuffer* keyIDBuffer, GstBuffer* buffer, unsigned subSamplesCount, GstBuffer* subSamplesBuffer);
 };
 
 G_END_DECLS