Title: [221224] trunk/Source/WebCore
Revision
221224
Author
[email protected]
Date
2017-08-26 01:29:00 -0700 (Sat, 26 Aug 2017)

Log Message

[EME][GStreamer] Connect CDM to GStreamer
https://bugs.webkit.org/show_bug.cgi?id=175983

Reviewed by Žan Doberšek.

This is still a version that will need some changes for some other
use cases but it should be enough to begin with some passes in the
tests and some basic use cases.

We use the attach CDMInstance interface in the private player to
get the instance in time for the initializationDataEncountered
event, which is handled when the demuxer reports synchronously the
events even before configuring the decryptors. We wait there in
case we don't have the CDMInstance attached (which contains info
about the key system now) and when we get it we report it back to
the demuxer and continue sending the event.

We also handled the events when handled by the decryptors but for
now this will remain a FIXME. The events handled by the
AppendPipeline will end up here too for now.

The CDM instance is created with the key system because some CDMs
can handle more than one, not ClearKey yet but others in the
(near) future.

MockCDMFactory is adapted to the changes as expected.

* Modules/encryptedmedia/CDM.cpp:
(WebCore::CDM::CDM):
* platform/encryptedmedia/CDMFactory.h:
* platform/encryptedmedia/CDMInstance.h:
* platform/encryptedmedia/clearkey/CDMClearKey.cpp:
(WebCore::CDMFactoryClearKey::createCDM):
(WebCore::CDMInstanceClearKey::keySystem const):
* platform/encryptedmedia/clearkey/CDMClearKey.h:
* platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp:
(WebCore::MediaPlayerPrivateGStreamer::handleMessage):
* platform/graphics/gstreamer/MediaPlayerPrivateGStreamerBase.cpp:
(WebCore::MediaPlayerPrivateGStreamerBase::~MediaPlayerPrivateGStreamerBase):
(WebCore::extractEventsAndSystemsFromMessage):
(WebCore::MediaPlayerPrivateGStreamerBase::handleSyncMessage):
(WebCore::MediaPlayerPrivateGStreamerBase::cdmInstanceAttached):
(WebCore::MediaPlayerPrivateGStreamerBase::cdmInstanceDetached):
(WebCore::MediaPlayerPrivateGStreamerBase::attemptToDecryptWithInstance):
(WebCore::MediaPlayerPrivateGStreamerBase::attemptToDecryptWithLocalInstance):
(WebCore::MediaPlayerPrivateGStreamerBase::dispatchDecryptionKey):
(WebCore::MediaPlayerPrivateGStreamerBase::handleProtectionEvent):
* platform/graphics/gstreamer/MediaPlayerPrivateGStreamerBase.h:
* platform/graphics/gstreamer/mse/AppendPipeline.cpp:
(WebCore::appendPipelineElementMessageCallback):
(WebCore::AppendPipeline::AppendPipeline):
(WebCore::AppendPipeline::~AppendPipeline):
(WebCore::AppendPipeline::handleNeedContextSyncMessage):
(WebCore::AppendPipeline::handleElementMessage):
(WebCore::AppendPipeline::handleAppsrcNeedDataReceived):
(WebCore::AppendPipeline::appsinkNewSample):
* platform/graphics/gstreamer/mse/AppendPipeline.h:
* testing/MockCDMFactory.cpp:
(WebCore::MockCDMFactory::createCDM):
(WebCore::MockCDMInstance::keySystem const):
* testing/MockCDMFactory.h:

Modified Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (221223 => 221224)


--- trunk/Source/WebCore/ChangeLog	2017-08-26 08:01:24 UTC (rev 221223)
+++ trunk/Source/WebCore/ChangeLog	2017-08-26 08:29:00 UTC (rev 221224)
@@ -1,3 +1,67 @@
+2017-08-26  Xabier Rodriguez Calvar  <[email protected]>
+
+        [EME][GStreamer] Connect CDM to GStreamer
+        https://bugs.webkit.org/show_bug.cgi?id=175983
+
+        Reviewed by Žan Doberšek.
+
+        This is still a version that will need some changes for some other
+        use cases but it should be enough to begin with some passes in the
+        tests and some basic use cases.
+
+        We use the attach CDMInstance interface in the private player to
+        get the instance in time for the initializationDataEncountered
+        event, which is handled when the demuxer reports synchronously the
+        events even before configuring the decryptors. We wait there in
+        case we don't have the CDMInstance attached (which contains info
+        about the key system now) and when we get it we report it back to
+        the demuxer and continue sending the event.
+
+        We also handled the events when handled by the decryptors but for
+        now this will remain a FIXME. The events handled by the
+        AppendPipeline will end up here too for now.
+
+        The CDM instance is created with the key system because some CDMs
+        can handle more than one, not ClearKey yet but others in the
+        (near) future.
+
+        MockCDMFactory is adapted to the changes as expected.
+
+        * Modules/encryptedmedia/CDM.cpp:
+        (WebCore::CDM::CDM):
+        * platform/encryptedmedia/CDMFactory.h:
+        * platform/encryptedmedia/CDMInstance.h:
+        * platform/encryptedmedia/clearkey/CDMClearKey.cpp:
+        (WebCore::CDMFactoryClearKey::createCDM):
+        (WebCore::CDMInstanceClearKey::keySystem const):
+        * platform/encryptedmedia/clearkey/CDMClearKey.h:
+        * platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp:
+        (WebCore::MediaPlayerPrivateGStreamer::handleMessage):
+        * platform/graphics/gstreamer/MediaPlayerPrivateGStreamerBase.cpp:
+        (WebCore::MediaPlayerPrivateGStreamerBase::~MediaPlayerPrivateGStreamerBase):
+        (WebCore::extractEventsAndSystemsFromMessage):
+        (WebCore::MediaPlayerPrivateGStreamerBase::handleSyncMessage):
+        (WebCore::MediaPlayerPrivateGStreamerBase::cdmInstanceAttached):
+        (WebCore::MediaPlayerPrivateGStreamerBase::cdmInstanceDetached):
+        (WebCore::MediaPlayerPrivateGStreamerBase::attemptToDecryptWithInstance):
+        (WebCore::MediaPlayerPrivateGStreamerBase::attemptToDecryptWithLocalInstance):
+        (WebCore::MediaPlayerPrivateGStreamerBase::dispatchDecryptionKey):
+        (WebCore::MediaPlayerPrivateGStreamerBase::handleProtectionEvent):
+        * platform/graphics/gstreamer/MediaPlayerPrivateGStreamerBase.h:
+        * platform/graphics/gstreamer/mse/AppendPipeline.cpp:
+        (WebCore::appendPipelineElementMessageCallback):
+        (WebCore::AppendPipeline::AppendPipeline):
+        (WebCore::AppendPipeline::~AppendPipeline):
+        (WebCore::AppendPipeline::handleNeedContextSyncMessage):
+        (WebCore::AppendPipeline::handleElementMessage):
+        (WebCore::AppendPipeline::handleAppsrcNeedDataReceived):
+        (WebCore::AppendPipeline::appsinkNewSample):
+        * platform/graphics/gstreamer/mse/AppendPipeline.h:
+        * testing/MockCDMFactory.cpp:
+        (WebCore::MockCDMFactory::createCDM):
+        (WebCore::MockCDMInstance::keySystem const):
+        * testing/MockCDMFactory.h:
+
 2017-08-26  Zan Dobersek  <[email protected]>
 
         [WebCrypto] Push WorkQueue dispatches for RSA algorithms into shared code

Modified: trunk/Source/WebCore/Modules/encryptedmedia/CDM.cpp (221223 => 221224)


--- trunk/Source/WebCore/Modules/encryptedmedia/CDM.cpp	2017-08-26 08:01:24 UTC (rev 221223)
+++ trunk/Source/WebCore/Modules/encryptedmedia/CDM.cpp	2017-08-26 08:29:00 UTC (rev 221224)
@@ -64,7 +64,7 @@
     ASSERT(supportsKeySystem(keySystem));
     for (auto* factory : CDMFactory::registeredFactories()) {
         if (factory->supportsKeySystem(keySystem)) {
-            m_private = factory->createCDM();
+            m_private = factory->createCDM(keySystem);
             break;
         }
     }

Modified: trunk/Source/WebCore/platform/encryptedmedia/CDMFactory.h (221223 => 221224)


--- trunk/Source/WebCore/platform/encryptedmedia/CDMFactory.h	2017-08-26 08:01:24 UTC (rev 221223)
+++ trunk/Source/WebCore/platform/encryptedmedia/CDMFactory.h	2017-08-26 08:29:00 UTC (rev 221224)
@@ -40,7 +40,7 @@
 class CDMFactory {
 public:
     virtual ~CDMFactory() { };
-    virtual std::unique_ptr<CDMPrivate> createCDM() = 0;
+    virtual std::unique_ptr<CDMPrivate> createCDM(const String&) = 0;
     virtual bool supportsKeySystem(const String&) = 0;
 
     static Vector<CDMFactory*>& registeredFactories();

Modified: trunk/Source/WebCore/platform/encryptedmedia/CDMInstance.h (221223 => 221224)


--- trunk/Source/WebCore/platform/encryptedmedia/CDMInstance.h	2017-08-26 08:01:24 UTC (rev 221223)
+++ trunk/Source/WebCore/platform/encryptedmedia/CDMInstance.h	2017-08-26 08:29:00 UTC (rev 221224)
@@ -94,6 +94,8 @@
     virtual void removeSessionData(const String& sessionId, LicenseType, RemoveSessionDataCallback) = 0;
 
     virtual void storeRecordOfKeyUsage(const String& sessionId) = 0;
+
+    virtual const String& keySystem() const = 0;
 };
 
 } // namespace WebCore

Modified: trunk/Source/WebCore/platform/encryptedmedia/clearkey/CDMClearKey.cpp (221223 => 221224)


--- trunk/Source/WebCore/platform/encryptedmedia/clearkey/CDMClearKey.cpp	2017-08-26 08:01:24 UTC (rev 221223)
+++ trunk/Source/WebCore/platform/encryptedmedia/clearkey/CDMClearKey.cpp	2017-08-26 08:29:00 UTC (rev 221224)
@@ -47,8 +47,13 @@
 CDMFactoryClearKey::CDMFactoryClearKey() = default;
 CDMFactoryClearKey::~CDMFactoryClearKey() = default;
 
-std::unique_ptr<CDMPrivate> CDMFactoryClearKey::createCDM()
+std::unique_ptr<CDMPrivate> CDMFactoryClearKey::createCDM(const String& keySystem)
 {
+#ifdef NDEBUG
+    UNUSED_PARAM(keySystem);
+#else
+    ASSERT(supportsKeySystem(keySystem));
+#endif
     return std::unique_ptr<CDMPrivate>(new CDMPrivateClearKey);
 }
 
@@ -208,6 +213,13 @@
 {
 }
 
+const String& CDMInstanceClearKey::keySystem() const
+{
+    static const String s_keySystem("org.w3.clearkey");
+
+    return s_keySystem;
+}
+
 } // namespace WebCore
 
 #endif // ENABLE(ENCRYPTED_MEDIA)

Modified: trunk/Source/WebCore/platform/encryptedmedia/clearkey/CDMClearKey.h (221223 => 221224)


--- trunk/Source/WebCore/platform/encryptedmedia/clearkey/CDMClearKey.h	2017-08-26 08:01:24 UTC (rev 221223)
+++ trunk/Source/WebCore/platform/encryptedmedia/clearkey/CDMClearKey.h	2017-08-26 08:29:00 UTC (rev 221224)
@@ -42,7 +42,7 @@
 
     virtual ~CDMFactoryClearKey();
 
-    std::unique_ptr<CDMPrivate> createCDM() override;
+    std::unique_ptr<CDMPrivate> createCDM(const String&) override;
     bool supportsKeySystem(const String&) override;
 
 private:
@@ -89,6 +89,8 @@
     void closeSession(const String&, CloseSessionCallback) override;
     void removeSessionData(const String&, LicenseType, RemoveSessionDataCallback) override;
     void storeRecordOfKeyUsage(const String&) override;
+
+    const String& keySystem() const final;
 };
 
 } // namespace WebCore

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


--- trunk/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp	2017-08-26 08:01:24 UTC (rev 221223)
+++ trunk/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp	2017-08-26 08:29:00 UTC (rev 221224)
@@ -1050,6 +1050,14 @@
                 processMpegTsSection(section);
                 gst_mpegts_section_unref(section);
             }
+#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());
+            }
+#endif
         }
 #endif
         break;

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


--- trunk/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamerBase.cpp	2017-08-26 08:01:24 UTC (rev 221223)
+++ trunk/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamerBase.cpp	2017-08-26 08:29:00 UTC (rev 221224)
@@ -43,10 +43,18 @@
 #include <wtf/text/AtomicString.h>
 #include <wtf/text/CString.h>
 #include <wtf/MathExtras.h>
+#include <wtf/UUID.h>
 
 #include <gst/audio/streamvolume.h>
 #include <gst/video/gstvideometa.h>
 
+#if ENABLE(ENCRYPTED_MEDIA)
+#include "CDMInstance.h"
+#include "GStreamerEMEUtilities.h"
+#include "SharedBuffer.h"
+#include "WebKitClearKeyDecryptorGStreamer.h"
+#endif
+
 #if USE(GSTREAMER_GL)
 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
 #define GST_GL_CAPS_FORMAT "{ BGRx, BGRA }"
@@ -110,12 +118,6 @@
 #endif
 #endif // USE(TEXTURE_MAPPER_GL)
 
-#if ENABLE(ENCRYPTED_MEDIA)
-#include "GStreamerEMEUtilities.h"
-#include "SharedBuffer.h"
-#include "WebKitClearKeyDecryptorGStreamer.h"
-#endif
-
 GST_DEBUG_CATEGORY(webkit_media_player_debug);
 #define GST_CAT_DEFAULT webkit_media_player_debug
 
@@ -240,6 +242,9 @@
 
 MediaPlayerPrivateGStreamerBase::~MediaPlayerPrivateGStreamerBase()
 {
+#if ENABLE(ENCRYPTED_MEDIA)
+    m_protectionCondition.notifyAll();
+#endif
     m_notifier->invalidate();
 
     if (m_videoSink) {
@@ -273,6 +278,31 @@
     m_pipeline = pipeline;
 }
 
+#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* streamEncryptionAllowedSystemsValue = gst_structure_get_value(structure, "stream-encryption-systems");
+    ASSERT(streamEncryptionAllowedSystemsValue && G_VALUE_HOLDS(streamEncryptionAllowedSystemsValue, G_TYPE_STRV));
+    const char** streamEncryptionAllowedSystems = reinterpret_cast<const char**>(g_value_get_boxed(streamEncryptionAllowedSystemsValue));
+    ASSERT(streamEncryptionAllowedSystems);
+    Vector<String> streamEncryptionAllowedSystemsVector;
+    unsigned i;
+    for (i = 0; streamEncryptionAllowedSystems[i]; ++i)
+        streamEncryptionAllowedSystemsVector.append(streamEncryptionAllowedSystems[i]);
+
+    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;
+    for (i = 0; i < streamEncryptionEventsListSize; ++i)
+        streamEncryptionEventsVector.append(GRefPtr<GstEvent>(static_cast<GstEvent*>(g_value_get_boxed(gst_value_list_get_value(streamEncryptionEventsList, i)))));
+
+    return std::make_pair(streamEncryptionEventsVector, streamEncryptionAllowedSystemsVector);
+}
+#endif
+
 bool MediaPlayerPrivateGStreamerBase::handleSyncMessage(GstMessage* message)
 {
     UNUSED_PARAM(message);
@@ -290,6 +320,78 @@
     }
 #endif // USE(GSTREAMER_GL)
 
+#if ENABLE(ENCRYPTED_MEDIA)
+    if (!g_strcmp0(contextType, "drm-preferred-decryption-system-id")) {
+        if (isMainThread()) {
+            GST_ERROR("can't handle drm-preferred-decryption-system-id need context message in the main thread");
+            ASSERT_NOT_REACHED();
+            return false;
+        }
+        GST_DEBUG("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;
+
+        for (auto& event : streamEncryptionInformation.first) {
+            GST_TRACE("handling protection event %u", GST_EVENT_SEQNUM(event.get()));
+            const char* eventKeySystemId = nullptr;
+            GstBuffer* data = ""
+            gst_event_parse_protection(event.get(), &eventKeySystemId, &data, nullptr);
+
+            GstMapInfo mapInfo;
+            if (!gst_buffer_map(data, &mapInfo, GST_MAP_READ)) {
+                GST_WARNING("cannot map %s protection data", eventKeySystemId);
+                break;
+            }
+            GST_TRACE("appending init data for %s of size %" G_GSIZE_FORMAT, eventKeySystemId, mapInfo.size);
+            GST_MEMDUMP("init data", reinterpret_cast<const unsigned char *>(mapInfo.data), mapInfo.size);
+            concatenatedInitDataChunks.append(mapInfo.data, mapInfo.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()));
+            }
+            gst_buffer_unmap(data, &mapInfo);
+        }
+
+        if (!concatenatedInitDataChunksNumber)
+            return false;
+
+        if (concatenatedInitDataChunksNumber > 1)
+            eventKeySystemIdString = emptyString();
+
+        String sessionId(createCanonicalUUIDString());
+
+        RunLoop::main().dispatch([this, eventKeySystemIdString, sessionId, initData = WTFMove(concatenatedInitDataChunks)] {
+            GST_DEBUG("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());
+
+            m_player->initializationDataEncountered(ASCIILiteral("cenc"), ArrayBuffer::create(initData.data(), initData.size()));
+        });
+
+        GST_INFO("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("working with %s, continuing with %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());
+            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");
+
+        return true;
+    }
+#endif // ENABLE(ENCRYPTED_MEDIA)
+
     return false;
 }
 
@@ -1044,6 +1146,65 @@
     return static_cast<unsigned>(position);
 }
 
+#if ENABLE(ENCRYPTED_MEDIA)
+void MediaPlayerPrivateGStreamerBase::cdmInstanceAttached(const CDMInstance& instance)
+{
+    ASSERT(!m_cdmInstance);
+    m_cdmInstance = &instance;
+    GST_DEBUG("CDM instance %p set", m_cdmInstance.get());
+    m_protectionCondition.notifyAll();
+}
+
+void MediaPlayerPrivateGStreamerBase::cdmInstanceDetached(const CDMInstance& instance)
+{
+#ifdef NDEBUG
+    UNUSED_PARAM(instance);
+#endif
+    ASSERT(m_cdmInstance.get() == &instance);
+    GST_DEBUG("detaching CDM instance %p", m_cdmInstance.get());
+    m_cdmInstance = nullptr;
+    m_protectionCondition.notifyAll();
+}
+
+void MediaPlayerPrivateGStreamerBase::attemptToDecryptWithInstance(const CDMInstance& instance)
+{
+    ASSERT(m_cdmInstance.get() == &instance);
+    GST_TRACE("instance %p, current stored %p", &instance, m_cdmInstance.get());
+    attemptToDecryptWithLocalInstance();
+}
+
+void MediaPlayerPrivateGStreamerBase::attemptToDecryptWithLocalInstance()
+{
+    // FIXME.
+}
+
+void MediaPlayerPrivateGStreamerBase::dispatchDecryptionKey(GstBuffer* buffer)
+{
+    bool eventHandled = gst_element_send_event(m_pipeline.get(), 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));
+}
+
+void MediaPlayerPrivateGStreamerBase::handleProtectionEvent(GstEvent* event)
+{
+    if (m_handledProtectionEvents.contains(GST_EVENT_SEQNUM(event))) {
+        GST_DEBUG("event %u already handled", GST_EVENT_SEQNUM(event));
+        m_handledProtectionEvents.remove(GST_EVENT_SEQNUM(event));
+        if (m_needToResendCredentials) {
+            GST_DEBUG("resending credentials");
+            attemptToDecryptWithLocalInstance();
+        }
+        return;
+    }
+
+    const gchar* eventKeySystemId = nullptr;
+    gst_event_parse_protection(event, &eventKeySystemId, nullptr, nullptr);
+    GST_WARNING("FIXME: unhandled protection event for %s", eventKeySystemId);
+    ASSERT_NOT_REACHED();
+}
+#endif
+
 bool MediaPlayerPrivateGStreamerBase::supportsKeySystem(const String& keySystem, const String& mimeType)
 {
     bool result = false;

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


--- trunk/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamerBase.h	2017-08-26 08:01:24 UTC (rev 221223)
+++ trunk/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamerBase.h	2017-08-26 08:29:00 UTC (rev 221224)
@@ -120,6 +120,15 @@
 #endif
 #endif
 
+#if ENABLE(ENCRYPTED_MEDIA)
+    void cdmInstanceAttached(const CDMInstance&) override;
+    void cdmInstanceDetached(const CDMInstance&) override;
+    void dispatchDecryptionKey(GstBuffer*);
+    void handleProtectionEvent(GstEvent*);
+    void attemptToDecryptWithLocalInstance();
+    void attemptToDecryptWithInstance(const CDMInstance&) override;
+#endif
+
     static bool supportsKeySystem(const String& keySystem, const String& mimeType);
     static MediaPlayer::SupportsType extendedSupportsType(const MediaEngineSupportParameters&, MediaPlayer::SupportsType);
 
@@ -219,6 +228,14 @@
 #endif
 
     ImageOrientation m_videoSourceOrientation;
+
+#if ENABLE(ENCRYPTED_MEDIA)
+    Lock m_protectionMutex;
+    Condition m_protectionCondition;
+    RefPtr<const CDMInstance> m_cdmInstance;
+    HashSet<uint32_t> m_handledProtectionEvents;
+    bool m_needToResendCredentials { false };
+#endif
 };
 
 }

Modified: trunk/Source/WebCore/platform/graphics/gstreamer/mse/AppendPipeline.cpp (221223 => 221224)


--- trunk/Source/WebCore/platform/graphics/gstreamer/mse/AppendPipeline.cpp	2017-08-26 08:01:24 UTC (rev 221223)
+++ trunk/Source/WebCore/platform/graphics/gstreamer/mse/AppendPipeline.cpp	2017-08-26 08:29:00 UTC (rev 221224)
@@ -93,6 +93,13 @@
     appendPipeline->handleApplicationMessage(message);
 }
 
+#if ENABLE(ENCRYPTED_MEDIA)
+static void appendPipelineElementMessageCallback(GstBus*, GstMessage* message, AppendPipeline* appendPipeline)
+{
+    appendPipeline->handleElementMessage(message);
+}
+#endif
+
 AppendPipeline::AppendPipeline(Ref<MediaSourceClientGStreamerMSE> mediaSourceClient, Ref<SourceBufferPrivateGStreamer> sourceBufferPrivate, MediaPlayerPrivateGStreamerMSE& playerPrivate)
     : m_mediaSourceClient(mediaSourceClient.get())
     , m_sourceBufferPrivate(sourceBufferPrivate.get())
@@ -119,6 +126,9 @@
 
     g_signal_connect(m_bus.get(), "sync-message::need-context", G_CALLBACK(appendPipelineNeedContextMessageCallback), this);
     g_signal_connect(m_bus.get(), "message::application", G_CALLBACK(appendPipelineApplicationMessageCallback), this);
+#if ENABLE(ENCRYPTED_MEDIA)
+    g_signal_connect(m_bus.get(), "message::element", G_CALLBACK(appendPipelineElementMessageCallback), this);
+#endif
 
     // We assign the created instances here instead of adoptRef() because gst_bin_add_many()
     // below will already take the initial reference and we need an additional one for us.
@@ -180,6 +190,8 @@
 
     if (m_pipeline) {
         ASSERT(m_bus);
+        g_signal_handlers_disconnect_by_func(m_bus.get(), reinterpret_cast<gpointer>(appendPipelineNeedContextMessageCallback), this);
+        gst_bus_disable_sync_message_emission(m_bus.get());
         gst_bus_remove_signal_watch(m_bus.get());
         gst_element_set_state(m_pipeline.get(), GST_STATE_NULL);
         m_pipeline = nullptr;
@@ -249,7 +261,8 @@
     const gchar* contextType = nullptr;
     gst_message_parse_context_type(message, &contextType);
     GST_TRACE("context type: %s", contextType);
-    if (!g_strcmp0(contextType, "drm-preferred-decryption-system-id"))
+    if (!g_strcmp0(contextType, "drm-preferred-decryption-system-id")
+        && m_appendState != AppendPipeline::AppendState::KeyNegotiation)
         setAppendState(AppendPipeline::AppendState::KeyNegotiation);
 
     // MediaPlayerPrivateGStreamerBase will take care of setting up encryption.
@@ -302,6 +315,25 @@
     ASSERT_NOT_REACHED();
 }
 
+#if ENABLE(ENCRYPTED_MEDIA)
+void AppendPipeline::handleElementMessage(GstMessage* message)
+{
+    ASSERT(WTF::isMainThread());
+
+    const GstStructure* structure = gst_message_get_structure(message);
+    GST_TRACE("%s message from %s", gst_structure_get_name(structure), GST_MESSAGE_SRC_NAME(message));
+    if (m_playerPrivate && gst_structure_has_name(structure, "drm-key-needed")) {
+        if (m_appendState != AppendPipeline::AppendState::KeyNegotiation)
+            setAppendState(AppendPipeline::AppendState::KeyNegotiation);
+
+        GST_DEBUG("sending drm-key-needed message from %s to the player", GST_MESSAGE_SRC_NAME(message));
+        GRefPtr<GstEvent> event;
+        gst_structure_get(structure, "event", GST_TYPE_EVENT, &event.outPtr(), nullptr);
+        m_playerPrivate->handleProtectionEvent(event.get());
+    }
+}
+#endif
+
 void AppendPipeline::handleAppsrcNeedDataReceived()
 {
     if (!m_appsrcAtLeastABufferLeft) {
@@ -309,7 +341,7 @@
         return;
     }
 
-    ASSERT(m_appendState == AppendState::Ongoing || m_appendState == AppendState::Sampling);
+    ASSERT(m_appendState == AppendState::KeyNegotiation || m_appendState == AppendState::Ongoing || m_appendState == AppendState::Sampling);
     ASSERT(!m_appsrcNeedDataReceived);
 
     GST_TRACE("received need-data from appsrc");
@@ -647,6 +679,10 @@
     {
         LockHolder locker(m_newSampleLock);
 
+        // If we were in KeyNegotiation but samples are coming, assume we're already OnGoing
+        if (m_appendState == AppendState::KeyNegotiation)
+            setAppendState(AppendState::Ongoing);
+
         // Ignore samples if we're not expecting them. Refuse processing if we're in Invalid state.
         if (m_appendState != AppendState::Ongoing && m_appendState != AppendState::Sampling) {
             GST_WARNING("Unexpected sample, appendState=%s", dumpAppendState(m_appendState));

Modified: trunk/Source/WebCore/platform/graphics/gstreamer/mse/AppendPipeline.h (221223 => 221224)


--- trunk/Source/WebCore/platform/graphics/gstreamer/mse/AppendPipeline.h	2017-08-26 08:01:24 UTC (rev 221223)
+++ trunk/Source/WebCore/platform/graphics/gstreamer/mse/AppendPipeline.h	2017-08-26 08:29:00 UTC (rev 221224)
@@ -50,6 +50,9 @@
 
     void handleNeedContextSyncMessage(GstMessage*);
     void handleApplicationMessage(GstMessage*);
+#if ENABLE(ENCRYPTED_MEDIA)
+    void handleElementMessage(GstMessage*);
+#endif
 
     gint id();
     AppendState appendState() { return m_appendState; }

Modified: trunk/Source/WebCore/testing/MockCDMFactory.cpp (221223 => 221224)


--- trunk/Source/WebCore/testing/MockCDMFactory.cpp	2017-08-26 08:01:24 UTC (rev 221223)
+++ trunk/Source/WebCore/testing/MockCDMFactory.cpp	2017-08-26 08:29:00 UTC (rev 221224)
@@ -96,7 +96,7 @@
         m_supportedDataTypes.append(type);
 }
 
-std::unique_ptr<CDMPrivate> MockCDMFactory::createCDM()
+std::unique_ptr<CDMPrivate> MockCDMFactory::createCDM(const String&)
 {
     return std::make_unique<MockCDM>(m_weakPtrFactory.createWeakPtr());
 }
@@ -377,6 +377,13 @@
     // FIXME: This should be implemented along with the support for persistent-usage-record sessions.
 }
 
+const String& MockCDMInstance::keySystem() const
+{
+    static const String s_keySystem("org.webkit.mock");
+
+    return s_keySystem;
 }
 
+}
+
 #endif

Modified: trunk/Source/WebCore/testing/MockCDMFactory.h (221223 => 221224)


--- trunk/Source/WebCore/testing/MockCDMFactory.h	2017-08-26 08:01:24 UTC (rev 221223)
+++ trunk/Source/WebCore/testing/MockCDMFactory.h	2017-08-26 08:29:00 UTC (rev 221224)
@@ -78,7 +78,7 @@
 
 private:
     MockCDMFactory();
-    std::unique_ptr<CDMPrivate> createCDM() final;
+    std::unique_ptr<CDMPrivate> createCDM(const String&) final;
     bool supportsKeySystem(const String&) final;
 
     MediaKeysRequirement m_distinctiveIdentifiersRequirement { MediaKeysRequirement::Optional };
@@ -140,6 +140,8 @@
     void removeSessionData(const String&, LicenseType, RemoveSessionDataCallback) final;
     void storeRecordOfKeyUsage(const String&) final;
 
+    const String& keySystem() const final;
+
     WeakPtr<MockCDM> m_cdm;
     bool m_distinctiveIdentifiersAllowed { true };
     bool m_persistentStateAllowed { true };
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to