Title: [238131] trunk/Source/WebCore
Revision
238131
Author
ctur...@igalia.com
Date
2018-11-13 06:45:31 -0800 (Tue, 13 Nov 2018)

Log Message

[EME][GStreamer] Make CDMInstance's available in decryptors, and factor out some EME utility classes.
https://bugs.webkit.org/show_bug.cgi?id=191316

Reviewed by Xabier Rodriguez-Calvar.

Another preparation in patch getting ready to move the decryption
logic behind the CDMInstance and out of the GStreamer decryptors
themselves. The first step taken here is to arrange for the
instances to always be available in the decryptors when they need
to decrypt content.

In doing so, there were a number of hairy bits of code that could
use some abstraction, so the opportunity was taken to do that as
well.

Covered by tests in media/encrypted-media and
imported/w3c/web-platform-tests/encrypted-media.

* platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp:
(WebCore::MediaPlayerPrivateGStreamer::handleMessage): Remove
drm-key-needed since it was not being used anywhere.
* platform/graphics/gstreamer/MediaPlayerPrivateGStreamerBase.cpp:
(WebCore::MediaPlayerPrivateGStreamerBase::handleSyncMessage):
Factor out the parsing of decryption system information from
GStreamer, since it was not clear what that code was doing unless
you squinted pretty hard. Also remove the duplicated
initialization-data-encountered posting.
(WebCore::MediaPlayerPrivateGStreamerBase::initializationDataEncountered):
Refactored to make it a more general method and usable in more
situations. It now has an optional to stop it from eliding init
datas for a different key system. This is required the first time
we post them, since if a CDM instance has already been set, and if
the stream init datas are for different systems, we ended up never
posting an encrypted event.
(WebCore::MediaPlayerPrivateGStreamerBase::attemptToDecryptWithLocalInstance):
Actually send a CDMInstance now when in regular playback mode.
(WebCore::MediaPlayerPrivateGStreamerBase::dispatchDecryptionKey):
Remove m_needToSendCredentials, it was not being used.
(WebCore::MediaPlayerPrivateGStreamerBase::handleProtectionEvent):
Refactored to use the new initializationDataEncountered.
(WebCore::MediaPlayerPrivateGStreamerBase::reportWaitingForKey):
Log the waiting state, since it was currently not clear what that
logging message was even telling you!
(WebCore::extractEventsAndSystemsFromMessage): Deleted.
* platform/graphics/gstreamer/MediaPlayerPrivateGStreamerBase.h:
* platform/graphics/gstreamer/eme/GStreamerEMEUtilities.h:
(WebCore::InitData::InitData): New class that encapsulates both
single instantiation and streaming instantiation.
(WebCore::InitData::append): Used for the streaming mode, when you
are concatenating init datas together.
(WebCore::InitData::payload const):
(WebCore::InitData::systemId const):
(WebCore::InitData::payloadContainerType const):
(WebCore::InitData::isFromDifferentContainer):
(WebCore::ProtectionSystemEvents::ProtectionSystemEvents):
(WebCore::ProtectionSystemEvents::events const):
(WebCore::ProtectionSystemEvents::availableSystems const):
* platform/graphics/gstreamer/eme/WebKitCommonEncryptionDecryptorGStreamer.cpp:
(webkitMediaCommonEncryptionDecryptTransformInPlace): If you post
waiting-for-key after requesting a CDM instance, it will flap back
to not waiting for a key almost immediately, didn't make sense
positing after requesting an instance. Also post key-received when
we receive the key.
(webkitMediaCommonEncryptionDecryptSinkEventHandler): It has now
been arranged that a CDMInstance will always be present in an OOB
message, so parse it out here.
* platform/graphics/gstreamer/mse/MediaPlayerPrivateGStreamerMSE.cpp:
(WebCore::MediaPlayerPrivateGStreamerMSE::attemptToDecryptWithInstance):
As above, make sure when posting the OOB that a CDMInstance is present.

Modified Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (238130 => 238131)


--- trunk/Source/WebCore/ChangeLog	2018-11-13 14:35:23 UTC (rev 238130)
+++ trunk/Source/WebCore/ChangeLog	2018-11-13 14:45:31 UTC (rev 238131)
@@ -1,5 +1,77 @@
 2018-11-13  Charlie Turner  <ctur...@igalia.com>
 
+        [EME][GStreamer] Make CDMInstance's available in decryptors, and factor out some EME utility classes.
+        https://bugs.webkit.org/show_bug.cgi?id=191316
+
+        Reviewed by Xabier Rodriguez-Calvar.
+
+        Another preparation in patch getting ready to move the decryption
+        logic behind the CDMInstance and out of the GStreamer decryptors
+        themselves. The first step taken here is to arrange for the
+        instances to always be available in the decryptors when they need
+        to decrypt content.
+
+        In doing so, there were a number of hairy bits of code that could
+        use some abstraction, so the opportunity was taken to do that as
+        well.
+
+        Covered by tests in media/encrypted-media and
+        imported/w3c/web-platform-tests/encrypted-media.
+
+        * platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp:
+        (WebCore::MediaPlayerPrivateGStreamer::handleMessage): Remove
+        drm-key-needed since it was not being used anywhere.
+        * platform/graphics/gstreamer/MediaPlayerPrivateGStreamerBase.cpp:
+        (WebCore::MediaPlayerPrivateGStreamerBase::handleSyncMessage):
+        Factor out the parsing of decryption system information from
+        GStreamer, since it was not clear what that code was doing unless
+        you squinted pretty hard. Also remove the duplicated
+        initialization-data-encountered posting.
+        (WebCore::MediaPlayerPrivateGStreamerBase::initializationDataEncountered):
+        Refactored to make it a more general method and usable in more
+        situations. It now has an optional to stop it from eliding init
+        datas for a different key system. This is required the first time
+        we post them, since if a CDM instance has already been set, and if
+        the stream init datas are for different systems, we ended up never
+        posting an encrypted event.
+        (WebCore::MediaPlayerPrivateGStreamerBase::attemptToDecryptWithLocalInstance):
+        Actually send a CDMInstance now when in regular playback mode.
+        (WebCore::MediaPlayerPrivateGStreamerBase::dispatchDecryptionKey):
+        Remove m_needToSendCredentials, it was not being used.
+        (WebCore::MediaPlayerPrivateGStreamerBase::handleProtectionEvent):
+        Refactored to use the new initializationDataEncountered.
+        (WebCore::MediaPlayerPrivateGStreamerBase::reportWaitingForKey):
+        Log the waiting state, since it was currently not clear what that
+        logging message was even telling you!
+        (WebCore::extractEventsAndSystemsFromMessage): Deleted.
+        * platform/graphics/gstreamer/MediaPlayerPrivateGStreamerBase.h:
+        * platform/graphics/gstreamer/eme/GStreamerEMEUtilities.h:
+        (WebCore::InitData::InitData): New class that encapsulates both
+        single instantiation and streaming instantiation.
+        (WebCore::InitData::append): Used for the streaming mode, when you
+        are concatenating init datas together.
+        (WebCore::InitData::payload const):
+        (WebCore::InitData::systemId const):
+        (WebCore::InitData::payloadContainerType const):
+        (WebCore::InitData::isFromDifferentContainer):
+        (WebCore::ProtectionSystemEvents::ProtectionSystemEvents):
+        (WebCore::ProtectionSystemEvents::events const):
+        (WebCore::ProtectionSystemEvents::availableSystems const):
+        * platform/graphics/gstreamer/eme/WebKitCommonEncryptionDecryptorGStreamer.cpp:
+        (webkitMediaCommonEncryptionDecryptTransformInPlace): If you post
+        waiting-for-key after requesting a CDM instance, it will flap back
+        to not waiting for a key almost immediately, didn't make sense
+        positing after requesting an instance. Also post key-received when
+        we receive the key.
+        (webkitMediaCommonEncryptionDecryptSinkEventHandler): It has now
+        been arranged that a CDMInstance will always be present in an OOB
+        message, so parse it out here.
+        * platform/graphics/gstreamer/mse/MediaPlayerPrivateGStreamerMSE.cpp:
+        (WebCore::MediaPlayerPrivateGStreamerMSE::attemptToDecryptWithInstance):
+        As above, make sure when posting the OOB that a CDMInstance is present.
+
+2018-11-13  Charlie Turner  <ctur...@igalia.com>
+
         Various compiler warnings/errors fixes.
         https://bugs.webkit.org/show_bug.cgi?id=191583
 

Modified: trunk/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp (238130 => 238131)


--- trunk/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp	2018-11-13 14:35:23 UTC (rev 238130)
+++ trunk/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp	2018-11-13 14:45:31 UTC (rev 238131)
@@ -1326,12 +1326,7 @@
         }
 #endif
 #if ENABLE(ENCRYPTED_MEDIA)
-        else if (gst_structure_has_name(structure, "drm-key-needed")) {
-            GST_DEBUG("drm-key-needed message from %s", GST_MESSAGE_SRC_NAME(message));
-            GRefPtr<GstEvent> event;
-            gst_structure_get(structure, "event", GST_TYPE_EVENT, &event.outPtr(), nullptr);
-            handleProtectionEvent(event.get());
-        } else if (gst_structure_has_name(structure, "drm-waiting-for-key")) {
+        else if (gst_structure_has_name(structure, "drm-waiting-for-key")) {
             GST_DEBUG("drm-waiting-for-key message from %s", GST_MESSAGE_SRC_NAME(message));
             setWaitingForKey(true);
         } else if (gst_structure_has_name(structure, "drm-key-received")) {

Modified: trunk/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamerBase.cpp (238130 => 238131)


--- trunk/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamerBase.cpp	2018-11-13 14:35:23 UTC (rev 238130)
+++ trunk/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamerBase.cpp	2018-11-13 14:45:31 UTC (rev 238131)
@@ -316,32 +316,6 @@
     }, this, nullptr);
 }
 
-#if ENABLE(ENCRYPTED_MEDIA)
-static std::pair<Vector<GRefPtr<GstEvent>>, Vector<String>> extractEventsAndSystemsFromMessage(GstMessage* message)
-{
-    const GstStructure* structure = gst_message_get_structure(message);
-
-    const GValue* streamEncryptionEventsList = gst_structure_get_value(structure, "stream-encryption-events");
-    ASSERT(streamEncryptionEventsList && GST_VALUE_HOLDS_LIST(streamEncryptionEventsList));
-    unsigned streamEncryptionEventsListSize = gst_value_list_get_size(streamEncryptionEventsList);
-    Vector<GRefPtr<GstEvent>> streamEncryptionEventsVector;
-
-    unsigned i;
-    for (i = 0; i < streamEncryptionEventsListSize; ++i)
-        streamEncryptionEventsVector.append(GRefPtr<GstEvent>(static_cast<GstEvent*>(g_value_get_boxed(gst_value_list_get_value(streamEncryptionEventsList, i)))));
-
-    Vector<String> streamEncryptionAllowedSystemsVector;
-    const GValue* streamEncryptionAllowedSystemsValue = gst_structure_get_value(structure, "available-stream-encryption-systems");
-    const char** streamEncryptionAllowedSystems = reinterpret_cast<const char**>(g_value_get_boxed(streamEncryptionAllowedSystemsValue));
-    if (streamEncryptionAllowedSystems) {
-        for (i = 0; streamEncryptionAllowedSystems[i]; ++i)
-            streamEncryptionAllowedSystemsVector.append(streamEncryptionAllowedSystems[i]);
-    }
-
-    return std::make_pair(streamEncryptionEventsVector, streamEncryptionAllowedSystemsVector);
-}
-#endif
-
 bool MediaPlayerPrivateGStreamerBase::handleSyncMessage(GstMessage* message)
 {
     UNUSED_PARAM(message);
@@ -369,56 +343,29 @@
         }
         GST_DEBUG_OBJECT(pipeline(), "handling drm-preferred-decryption-system-id need context message");
         LockHolder lock(m_protectionMutex);
-        std::pair<Vector<GRefPtr<GstEvent>>, Vector<String>> streamEncryptionInformation = extractEventsAndSystemsFromMessage(message);
-        GST_TRACE("found %" G_GSIZE_FORMAT " protection events", streamEncryptionInformation.first.size());
-        Vector<uint8_t> concatenatedInitDataChunks;
-        unsigned concatenatedInitDataChunksNumber = 0;
-        String eventKeySystemIdString;
+        ProtectionSystemEvents protectionSystemEvents(message);
+        GST_TRACE("found %lu protection events, %lu decryptors available", protectionSystemEvents.events().size(), protectionSystemEvents.availableSystems().size());
+        InitData initData;
 
-        for (auto& event : streamEncryptionInformation.first) {
-            GST_TRACE("handling protection event %u", GST_EVENT_SEQNUM(event.get()));
+        for (auto& event : protectionSystemEvents.events()) {
             const char* eventKeySystemId = nullptr;
             GstBuffer* data = ""
             gst_event_parse_protection(event.get(), &eventKeySystemId, &data, nullptr);
 
-            GstMappedBuffer dataMapped(data, GST_MAP_READ);
-            if (!dataMapped) {
-                GST_WARNING("cannot map %s protection data", eventKeySystemId);
-                break;
-            }
-            GST_TRACE("appending init data for %s of size %" G_GSIZE_FORMAT, eventKeySystemId, dataMapped.size());
-            GST_MEMDUMP("init data", reinterpret_cast<const unsigned char*>(dataMapped.data()), dataMapped.size());
-            concatenatedInitDataChunks.append(dataMapped.data(), dataMapped.size());
-            ++concatenatedInitDataChunksNumber;
-            eventKeySystemIdString = eventKeySystemId;
-            if (streamEncryptionInformation.second.contains(eventKeySystemId)) {
-                GST_TRACE("considering init data handled for %s", eventKeySystemId);
-                m_handledProtectionEvents.add(GST_EVENT_SEQNUM(event.get()));
-            }
+            initData.append({eventKeySystemId, data});
+            m_handledProtectionEvents.add(GST_EVENT_SEQNUM(event.get()));
         }
 
-        if (!concatenatedInitDataChunksNumber)
-            return false;
+        initializationDataEncountered(WTFMove(initData));
 
-        if (concatenatedInitDataChunksNumber > 1)
-            eventKeySystemIdString = emptyString();
-
-        RunLoop::main().dispatch([weakThis = makeWeakPtr(*this), eventKeySystemIdString, initData = WTFMove(concatenatedInitDataChunks)] {
-            if (!weakThis)
-                return;
-
-            GST_DEBUG_OBJECT(weakThis->pipeline(), "scheduling initializationDataEncountered event for %s with concatenated init datas size of %" G_GSIZE_FORMAT, eventKeySystemIdString.utf8().data(), initData.size());
-            GST_MEMDUMP("init datas", initData.data(), initData.size());
-            weakThis->m_player->initializationDataEncountered("cenc"_s, ArrayBuffer::create(initData.data(), initData.size()));
-        });
-
         GST_INFO_OBJECT(pipeline(), "waiting for a CDM instance");
         m_protectionCondition.waitFor(m_protectionMutex, Seconds(4), [this] {
             return this->m_cdmInstance;
         });
+
         if (m_cdmInstance && !m_cdmInstance->keySystem().isEmpty()) {
             const char* preferredKeySystemUuid = GStreamerEMEUtilities::keySystemToUuid(m_cdmInstance->keySystem());
-            GST_INFO_OBJECT(pipeline(), "working with %s, continuing with %s on %s", m_cdmInstance->keySystem().utf8().data(), preferredKeySystemUuid, GST_MESSAGE_SRC_NAME(message));
+            GST_INFO_OBJECT(pipeline(), "working with key system %s, continuing with key system %s on %s", m_cdmInstance->keySystem().utf8().data(), preferredKeySystemUuid, GST_MESSAGE_SRC_NAME(message));
 
             GRefPtr<GstContext> context = adoptGRef(gst_context_new("drm-preferred-decryption-system-id", FALSE));
             GstStructure* contextStructure = gst_context_writable_structure(context.get());
@@ -425,7 +372,7 @@
             gst_structure_set(contextStructure, "decryption-system-id", G_TYPE_STRING, preferredKeySystemUuid, nullptr);
             gst_element_set_context(GST_ELEMENT(GST_MESSAGE_SRC(message)), context.get());
         } else
-            GST_WARNING("no proper CDM instance attached");
+            GST_WARNING("CDM instance not initializaed");
 
         return true;
     }
@@ -1234,48 +1181,17 @@
 }
 
 #if ENABLE(ENCRYPTED_MEDIA)
-void MediaPlayerPrivateGStreamerBase::initializationDataEncountered(GstEvent* event)
+void MediaPlayerPrivateGStreamerBase::initializationDataEncountered(InitData&& initData)
 {
-    const char* eventKeySystemUUID = nullptr;
-    GstBuffer* data = ""
-    gst_event_parse_protection(event, &eventKeySystemUUID, &data, nullptr);
+    ASSERT(!isMainThread());
 
-    // Check if the system key of the protection event is the same of the CDM instance.
-    // For example: we can receive a new Widevine protection event but the CDM instance initialized with
-    // Playready, so we ignore this event.
-    if (m_cdmInstance
-#if GST_CHECK_VERSION(1, 15, 0)
-        && g_strcmp0(eventKeySystemUUID, GST_PROTECTION_UNSPECIFIED_SYSTEM_ID)
-#endif
-        && g_strcmp0(GStreamerEMEUtilities::keySystemToUuid(m_cdmInstance->keySystem()), eventKeySystemUUID)) {
-        GST_DEBUG("The protection event with UUID %s is ignored because it isn't supported by the CDM %s", eventKeySystemUUID, m_cdmInstance->keySystem().utf8().data());
-        return;
-    }
-
-    GstMappedBuffer dataMapped(data, GST_MAP_READ);
-    if (!dataMapped) {
-        GST_WARNING("cannot map %s protection data", eventKeySystemUUID);
-        return;
-    }
-
-    GST_TRACE("init data encountered for %s of size %" G_GSIZE_FORMAT, eventKeySystemUUID, dataMapped.size());
-    GST_MEMDUMP("init data", reinterpret_cast<const uint8_t*>(dataMapped.data()), dataMapped.size());
-    InitData initData(reinterpret_cast<const uint8_t*>(dataMapped.data()), dataMapped.size());
-
-    String eventKeySystemUUIDString = eventKeySystemUUID;
-    RunLoop::main().dispatch([weakThis = makeWeakPtr(*this), eventKeySystemUUID = eventKeySystemUUIDString, initData] {
+    RunLoop::main().dispatch([weakThis = makeWeakPtr(*this), initData = WTFMove(initData)] {
         if (!weakThis)
             return;
 
-        GST_DEBUG("scheduling initializationDataEncountered event for %s with init data size of %u", eventKeySystemUUID.utf8().data(), initData.sizeInBytes());
-        GST_MEMDUMP("init datas", reinterpret_cast<const uint8_t*>(initData.characters8()), initData.sizeInBytes());
-        auto initDataType = "cenc"_s;
-#if GST_CHECK_VERSION(1, 15, 0)
-        if (eventKeySystemUUID == GST_PROTECTION_UNSPECIFIED_SYSTEM_ID)
-            initDataType = "webm"_s;
-#endif
-        weakThis->m_player->initializationDataEncountered(initDataType,
-            ArrayBuffer::create(reinterpret_cast<const uint8_t*>(initData.characters8()), initData.sizeInBytes()));
+        GST_DEBUG("scheduling initializationDataEncountered event of size %lu", initData.payload()->size());
+        GST_MEMDUMP("init datas", reinterpret_cast<const uint8_t*>(initData.payload()->data()), initData.payload()->size());
+        weakThis->m_player->initializationDataEncountered(initData.payloadContainerType(), initData.payload()->tryCreateArrayBuffer());
     });
 }
 
@@ -1309,7 +1225,9 @@
 
 void MediaPlayerPrivateGStreamerBase::attemptToDecryptWithLocalInstance()
 {
-    // FIXME.
+    bool eventHandled = gst_element_send_event(pipeline(), gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM_OOB,
+        gst_structure_new("attempt-to-decrypt", "cdm-instance", G_TYPE_POINTER, m_cdmInstance.get(), nullptr)));
+    GST_DEBUG("attempting to decrypt, event handled %s", boolForPrinting(eventHandled));
 }
 
 void MediaPlayerPrivateGStreamerBase::dispatchDecryptionKey(GstBuffer* buffer)
@@ -1316,8 +1234,7 @@
 {
     bool eventHandled = gst_element_send_event(pipeline(), gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM_OOB,
         gst_structure_new("drm-cipher", "key", GST_TYPE_BUFFER, buffer, nullptr)));
-    m_needToResendCredentials = m_handledProtectionEvents.size() > 0;
-    GST_TRACE("emitted decryption cipher key on pipeline, event handled %s, need to resend credentials %s", boolForPrinting(eventHandled), boolForPrinting(m_needToResendCredentials));
+    GST_TRACE("emitted decryption cipher key on pipeline, event handled %s", boolForPrinting(eventHandled));
 }
 
 void MediaPlayerPrivateGStreamerBase::dispatchCDMInstance()
@@ -1333,7 +1250,11 @@
         GST_DEBUG_OBJECT(pipeline(), "event %u already handled", GST_EVENT_SEQNUM(event));
         return;
     }
-    initializationDataEncountered(event);
+    GST_DEBUG_OBJECT(pipeline(), "handling event %u from MSE", GST_EVENT_SEQNUM(event));
+    const char* eventKeySystemUUID = nullptr;
+    GstBuffer* initData = nullptr;
+    gst_event_parse_protection(event, &eventKeySystemUUID, &initData, nullptr);
+    initializationDataEncountered({eventKeySystemUUID, initData});
 }
 
 void MediaPlayerPrivateGStreamerBase::setWaitingForKey(bool waitingForKey)

Modified: trunk/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamerBase.h (238130 => 238131)


--- trunk/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamerBase.h	2018-11-13 14:35:23 UTC (rev 238130)
+++ trunk/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamerBase.h	2018-11-13 14:45:31 UTC (rev 238131)
@@ -26,6 +26,7 @@
 #if ENABLE(VIDEO) && USE(GSTREAMER)
 
 #include "GStreamerCommon.h"
+#include "GStreamerEMEUtilities.h"
 #include "MainThreadNotifier.h"
 #include "MediaPlayerPrivate.h"
 #include "PlatformLayer.h"
@@ -152,7 +153,7 @@
     void attemptToDecryptWithLocalInstance();
     void attemptToDecryptWithInstance(CDMInstance&) override;
     void dispatchCDMInstance();
-    void initializationDataEncountered(GstEvent*);
+    void initializationDataEncountered(InitData&&);
     void setWaitingForKey(bool);
     bool waitingForKey() const override;
 #endif
@@ -275,7 +276,6 @@
     Condition m_protectionCondition;
     RefPtr<const CDMInstance> m_cdmInstance;
     HashSet<uint32_t> m_handledProtectionEvents;
-    bool m_needToResendCredentials { false };
     bool m_waitingForKey { false };
 #endif
 };

Modified: trunk/Source/WebCore/platform/graphics/gstreamer/eme/GStreamerEMEUtilities.h (238130 => 238131)


--- trunk/Source/WebCore/platform/graphics/gstreamer/eme/GStreamerEMEUtilities.h	2018-11-13 14:35:23 UTC (rev 238130)
+++ trunk/Source/WebCore/platform/graphics/gstreamer/eme/GStreamerEMEUtilities.h	2018-11-13 14:45:31 UTC (rev 238131)
@@ -24,6 +24,7 @@
 #if ENABLE(ENCRYPTED_MEDIA) && USE(GSTREAMER)
 
 #include "GStreamerCommon.h"
+#include "SharedBuffer.h"
 #include <gst/gst.h>
 #include <wtf/text/WTFString.h>
 
@@ -30,9 +31,85 @@
 #define WEBCORE_GSTREAMER_EME_UTILITIES_CLEARKEY_UUID "1077efec-c0b2-4d02-ace3-3c1e52e2fb4b"
 
 namespace WebCore {
+class InitData {
+public:
+    InitData()
+        : m_payload(SharedBuffer::create()) { }
 
-using InitData = String;
+    // FIXME: We should have an enum for system uuids for better type safety.
+    InitData(const String& systemId, GstBuffer* initData)
+        : m_systemId(systemId)
+    {
+        GstMappedBuffer mappedInitData(initData, GST_MAP_READ);
+        if (!mappedInitData) {
+            GST_ERROR("cannot map %s protection data", systemId.utf8().data());
+            ASSERT_NOT_REACHED();
+        }
+        m_payload = SharedBuffer::create(mappedInitData.data(), mappedInitData.size());
+    }
 
+    void append(InitData&& initData)
+    {
+        // FIXME: There is some confusion here about how to detect the
+        // correct "initialization data type", if the system ID is
+        // GST_PROTECTION_UNSPECIFIED_SYSTEM_ID, then we know it came
+        // from WebM. If the system id is specified with one of the
+        // defined ClearKey / Playready / Widevine / etc UUIDs, then
+        // we know it's MP4. For the latter case, it does not matter
+        // which of the UUIDs it is, so we just overwrite it. This is
+        // a quirk of how GStreamer provides protection events, and
+        // it's not very robust, so be careful here!
+        m_systemId = initData.m_systemId;
+
+        m_payload->append(*initData.payload());
+    }
+
+    const RefPtr<SharedBuffer> payload() const { return m_payload; }
+    const String& systemId() const { return m_systemId; }
+    String payloadContainerType() const
+    {
+#if GST_CHECK_VERSION(1, 15, 0)
+        if (m_systemId == GST_PROTECTION_UNSPECIFIED_SYSTEM_ID)
+            return "webm"_s;
+#endif
+        return "cenc"_s;
+    }
+
+private:
+    String m_systemId;
+    RefPtr<SharedBuffer> m_payload;
+};
+
+class ProtectionSystemEvents {
+public:
+    using EventVector = Vector<GRefPtr<GstEvent>>;
+
+    explicit ProtectionSystemEvents(GstMessage* message)
+    {
+        const GstStructure* structure = gst_message_get_structure(message);
+
+        const GValue* streamEncryptionEventsList = gst_structure_get_value(structure, "stream-encryption-events");
+        ASSERT(streamEncryptionEventsList && GST_VALUE_HOLDS_LIST(streamEncryptionEventsList));
+        unsigned numEvents = gst_value_list_get_size(streamEncryptionEventsList);
+        m_events.reserveInitialCapacity(numEvents);
+        for (unsigned i = 0; i < numEvents; ++i)
+            m_events.uncheckedAppend(GRefPtr<GstEvent>(static_cast<GstEvent*>(g_value_get_boxed(gst_value_list_get_value(streamEncryptionEventsList, i)))));
+        const GValue* streamEncryptionAllowedSystemsValue = gst_structure_get_value(structure, "available-stream-encryption-systems");
+        const char** streamEncryptionAllowedSystems = reinterpret_cast<const char**>(g_value_get_boxed(streamEncryptionAllowedSystemsValue));
+        if (streamEncryptionAllowedSystems) {
+            for (unsigned i = 0; streamEncryptionAllowedSystems[i]; ++i)
+                m_availableSystems.append(streamEncryptionAllowedSystems[i]);
+        }
+    }
+    const EventVector& events() const { return m_events; }
+    const Vector<String>& availableSystems() const { return m_availableSystems; }
+
+private:
+    EventVector m_events;
+    Vector<String> m_availableSystems;
+};
+
+
 class GStreamerEMEUtilities {
 
 public:

Modified: trunk/Source/WebCore/platform/graphics/gstreamer/eme/WebKitCommonEncryptionDecryptorGStreamer.cpp (238130 => 238131)


--- trunk/Source/WebCore/platform/graphics/gstreamer/eme/WebKitCommonEncryptionDecryptorGStreamer.cpp	2018-11-13 14:35:23 UTC (rev 238130)
+++ trunk/Source/WebCore/platform/graphics/gstreamer/eme/WebKitCommonEncryptionDecryptorGStreamer.cpp	2018-11-13 14:45:31 UTC (rev 238131)
@@ -26,6 +26,7 @@
 #if ENABLE(ENCRYPTED_MEDIA) && USE(GSTREAMER)
 
 #include "GStreamerCommon.h"
+#include <CDMInstance.h>
 #include <wtf/Condition.h>
 #include <wtf/PrintStream.h>
 #include <wtf/RunLoop.h>
@@ -33,7 +34,7 @@
 #define WEBKIT_MEDIA_CENC_DECRYPT_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), WEBKIT_TYPE_MEDIA_CENC_DECRYPT, WebKitMediaCommonEncryptionDecryptPrivate))
 struct _WebKitMediaCommonEncryptionDecryptPrivate {
     GRefPtr<GstEvent> protectionEvent;
-
+    RefPtr<WebCore::CDMInstance> cdmInstance;
     bool keyReceived;
     bool waitingForKey { false };
     Lock mutex;
@@ -206,9 +207,9 @@
             return GST_FLOW_NOT_SUPPORTED;
         }
         // Send "drm-cdm-instance-needed" message to the player to resend the CDMInstance if available and inform we are waiting for key.
-        gst_element_post_message(GST_ELEMENT(self), gst_message_new_element(GST_OBJECT(self), gst_structure_new_empty("drm-cdm-instance-needed")));
         priv->waitingForKey = true;
         gst_element_post_message(GST_ELEMENT(self), gst_message_new_element(GST_OBJECT(self), gst_structure_new_empty("drm-waiting-for-key")));
+        gst_element_post_message(GST_ELEMENT(self), gst_message_new_element(GST_OBJECT(self), gst_structure_new_empty("drm-cdm-instance-needed")));
 
         priv->condition.waitFor(priv->mutex, Seconds(5), [priv] {
             return priv->keyReceived;
@@ -306,8 +307,24 @@
     WebKitMediaCommonEncryptionDecryptClass* klass = WEBKIT_MEDIA_CENC_DECRYPT_GET_CLASS(self);
     gboolean result = FALSE;
 
+
     switch (GST_EVENT_TYPE(event)) {
     case GST_EVENT_CUSTOM_DOWNSTREAM_OOB: {
+        // FIXME: https://bugs.webkit.org/show_bug.cgi?id=191355
+        // We should be handling protection events in this class in
+        // addition to out-of-band data. In regular playback, after a
+        // preferred system ID context is set, any future protection
+        // events will not be handled by the demuxer, so the must be
+        // handled in here.
+        const GstStructure* structure = gst_event_get_structure(event);
+        gst_structure_get(structure, "cdm-instance", G_TYPE_POINTER, &priv->cdmInstance, nullptr);
+        if (!priv->cdmInstance) {
+            GST_ERROR_OBJECT(self, "No CDM instance received");
+            result = FALSE;
+            break;
+        }
+        GST_DEBUG_OBJECT(self, "received a cdm instance %p", priv->cdmInstance.get());
+
         if (klass->handleKeyResponse(self, event)) {
             GST_DEBUG_OBJECT(self, "key received");
             priv->keyReceived = true;

Modified: trunk/Source/WebCore/platform/graphics/gstreamer/mse/MediaPlayerPrivateGStreamerMSE.cpp (238130 => 238131)


--- trunk/Source/WebCore/platform/graphics/gstreamer/mse/MediaPlayerPrivateGStreamerMSE.cpp	2018-11-13 14:35:23 UTC (rev 238130)
+++ trunk/Source/WebCore/platform/graphics/gstreamer/mse/MediaPlayerPrivateGStreamerMSE.cpp	2018-11-13 14:45:31 UTC (rev 238131)
@@ -933,6 +933,7 @@
         GUniquePtr<GstStructure> structure(gst_structure_new_empty("drm-cipher-clearkey"));
         gst_structure_set_value(structure.get(), "key-ids", &keyIDList);
         gst_structure_set_value(structure.get(), "key-values", &keyValueList);
+        gst_structure_set(structure.get(), "cdm-instance", G_TYPE_POINTER, &instance, nullptr);
 
         gst_element_send_event(m_playbackPipeline->pipeline(), gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM_OOB, structure.release()));
     }
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to