Title: [211562] trunk
Revision
211562
Author
calva...@igalia.com
Date
2017-02-02 08:54:48 -0800 (Thu, 02 Feb 2017)

Log Message

[EME][GStreamer] Fixed decryptor selection
https://bugs.webkit.org/show_bug.cgi?id=167588

Reviewed by Žan Doberšek.

Source/WebCore:

GStreamer selected a decryptor automatically but we need to be
able to tell it which decryptor we want because one file can be
encrypted with more than one system and the one we want to use can
depend on what the user tells us.

Now when the demuxer is about to select the demuxer, it runs a
GstContext query with the events, which are forwarded through the
EME api to the application, which will answer the the
generateKeyRequest and then we can instruct the demuxer to select
the one we tell it, not the one that is selected automatically. If
the demuxer has already a preferred decryptor, the codepath will
be similar to the older one.

Something that is also fixed is the report of the keyneeded event,
which will contain all pssh boxes as requested by the spec.

* platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp:
(WebCore::MediaPlayerPrivateGStreamer::handleMessage): Intercept
the event and handle it.
* platform/graphics/gstreamer/MediaPlayerPrivateGStreamerBase.cpp:
(WebCore::MediaPlayerPrivateGStreamerBase::MediaPlayerPrivateGStreamerBase):
Initialize the CDM session.
(WebCore::MediaPlayerPrivateGStreamerBase::~MediaPlayerPrivateGStreamerBase):
Unlock the protection condition just in case and set CDM to null.
(WebCore::extractEventsAndSystemsFromMessage): Access the events
and accepted key systems coming at the message from the demuxer.
(WebCore::MediaPlayerPrivateGStreamerBase::handleSyncMessage):
Handle the protection event not as an element event but as a
context request. It also concatenates all the initdatas in case
there is more than one. The event is sent in the main thread and
the current one blocks until a timeout is hit or the
generateKeyRequest is called.
(WebCore::MediaPlayerPrivateGStreamerBase::handleProtectionEvent):
Check if the event was already handled and if not, run the need
key event.
(WebCore::MediaPlayerPrivateGStreamerBase::receivedGenerateKeyRequest):
Notify the that the query arrived so that we can unlock the
demuxer thread.
(WebCore::keySystemIdToUuid): Translates ids to uuids, meaning
the ones coming from JS to the ones coming from the media engine.
* platform/graphics/gstreamer/MediaPlayerPrivateGStreamerBase.h:
Attributes and methods.
* platform/graphics/gstreamer/eme/WebKitClearKeyDecryptorGStreamer.cpp:
(webkit_media_clear_key_decrypt_class_init):
(webKitMediaClearKeyDecryptorRequestDecryptionKey): Deleted.
* platform/graphics/gstreamer/eme/WebKitClearKeyDecryptorGStreamer.h:
Added the ui and uuid.
* platform/graphics/gstreamer/eme/WebKitCommonEncryptionDecryptorGStreamer.cpp:
(webkitMediaCommonEncryptionDecryptSinkEventHandler): Do not rely
on the subclass, just forward the event to the pipeline inside a message.
* platform/graphics/gstreamer/eme/WebKitCommonEncryptionDecryptorGStreamer.h:
Remove unused function signature.
* platform/graphics/gstreamer/mse/AppendPipeline.cpp:
(WebCore::appendPipelineNeedContextMessageCallback): Renamed from
appendPipelineElementMessageCallback.
(WebCore::AppendPipeline::AppendPipeline): Connect to the
need-context message instead of the element one.
(WebCore::AppendPipeline::dispatchPendingDecryptionKey):
Dispatches the drm-cypher message if there is one pending.
(WebCore::AppendPipeline::dispatchDecryptionKey): Dispatches the
drm-cypher.
(WebCore::AppendPipeline::handleNeedContextSyncMessage): Handles
the need-context event instead of the element one.
(WebCore::AppendPipeline::connectDemuxerSrcPadToAppsinkFromAnyThread):
Dispatches the key to the pipeline if there's any pending.
(WebCore::appendPipelineElementMessageCallback): Deleted.
(WebCore::AppendPipeline::handleElementMessage): Deleted.
* platform/graphics/gstreamer/mse/AppendPipeline.h: New methods
and attributes.
* platform/graphics/gstreamer/mse/MediaPlayerPrivateGStreamerMSE.cpp:
(WebCore::MediaPlayerPrivateGStreamerMSE::dispatchDecryptionKey):
Use the dispatchDecryptionKey method of the AppendPipeline.

Tools:

This patches are pending at https://bugzilla.gnome.org/show_bug.cgi?id=770107

* gtk/jhbuild.modules: Added patches to gstreamer and
gst-plugins-good packages.
* gtk/patches/gst-plugins-good-0004-qtdemux-add-context-for-a-preferred-protection.patch: Added.
* gtk/patches/gstreamer-0001-protection-added-function-to-filter-system-ids.patch: Added.

Modified Paths

Added Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (211561 => 211562)


--- trunk/Source/WebCore/ChangeLog	2017-02-02 16:30:28 UTC (rev 211561)
+++ trunk/Source/WebCore/ChangeLog	2017-02-02 16:54:48 UTC (rev 211562)
@@ -1,3 +1,83 @@
+2017-02-02  Xabier Rodriguez Calvar  <calva...@igalia.com>
+
+        [EME][GStreamer] Fixed decryptor selection
+        https://bugs.webkit.org/show_bug.cgi?id=167588
+
+        Reviewed by Žan Doberšek.
+
+        GStreamer selected a decryptor automatically but we need to be
+        able to tell it which decryptor we want because one file can be
+        encrypted with more than one system and the one we want to use can
+        depend on what the user tells us.
+
+        Now when the demuxer is about to select the demuxer, it runs a
+        GstContext query with the events, which are forwarded through the
+        EME api to the application, which will answer the the
+        generateKeyRequest and then we can instruct the demuxer to select
+        the one we tell it, not the one that is selected automatically. If
+        the demuxer has already a preferred decryptor, the codepath will
+        be similar to the older one.
+
+        Something that is also fixed is the report of the keyneeded event,
+        which will contain all pssh boxes as requested by the spec.
+
+        * platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp:
+        (WebCore::MediaPlayerPrivateGStreamer::handleMessage): Intercept
+        the event and handle it.
+        * platform/graphics/gstreamer/MediaPlayerPrivateGStreamerBase.cpp:
+        (WebCore::MediaPlayerPrivateGStreamerBase::MediaPlayerPrivateGStreamerBase):
+        Initialize the CDM session.
+        (WebCore::MediaPlayerPrivateGStreamerBase::~MediaPlayerPrivateGStreamerBase):
+        Unlock the protection condition just in case and set CDM to null.
+        (WebCore::extractEventsAndSystemsFromMessage): Access the events
+        and accepted key systems coming at the message from the demuxer.
+        (WebCore::MediaPlayerPrivateGStreamerBase::handleSyncMessage):
+        Handle the protection event not as an element event but as a
+        context request. It also concatenates all the initdatas in case
+        there is more than one. The event is sent in the main thread and
+        the current one blocks until a timeout is hit or the
+        generateKeyRequest is called.
+        (WebCore::MediaPlayerPrivateGStreamerBase::handleProtectionEvent):
+        Check if the event was already handled and if not, run the need
+        key event.
+        (WebCore::MediaPlayerPrivateGStreamerBase::receivedGenerateKeyRequest):
+        Notify the that the query arrived so that we can unlock the
+        demuxer thread.
+        (WebCore::keySystemIdToUuid): Translates ids to uuids, meaning
+        the ones coming from JS to the ones coming from the media engine.
+        * platform/graphics/gstreamer/MediaPlayerPrivateGStreamerBase.h:
+        Attributes and methods.
+        * platform/graphics/gstreamer/eme/WebKitClearKeyDecryptorGStreamer.cpp:
+        (webkit_media_clear_key_decrypt_class_init):
+        (webKitMediaClearKeyDecryptorRequestDecryptionKey): Deleted.
+        * platform/graphics/gstreamer/eme/WebKitClearKeyDecryptorGStreamer.h:
+        Added the ui and uuid.
+        * platform/graphics/gstreamer/eme/WebKitCommonEncryptionDecryptorGStreamer.cpp:
+        (webkitMediaCommonEncryptionDecryptSinkEventHandler): Do not rely
+        on the subclass, just forward the event to the pipeline inside a message.
+        * platform/graphics/gstreamer/eme/WebKitCommonEncryptionDecryptorGStreamer.h:
+        Remove unused function signature.
+        * platform/graphics/gstreamer/mse/AppendPipeline.cpp:
+        (WebCore::appendPipelineNeedContextMessageCallback): Renamed from
+        appendPipelineElementMessageCallback.
+        (WebCore::AppendPipeline::AppendPipeline): Connect to the
+        need-context message instead of the element one.
+        (WebCore::AppendPipeline::dispatchPendingDecryptionKey):
+        Dispatches the drm-cypher message if there is one pending.
+        (WebCore::AppendPipeline::dispatchDecryptionKey): Dispatches the
+        drm-cypher.
+        (WebCore::AppendPipeline::handleNeedContextSyncMessage): Handles
+        the need-context event instead of the element one.
+        (WebCore::AppendPipeline::connectDemuxerSrcPadToAppsinkFromAnyThread):
+        Dispatches the key to the pipeline if there's any pending.
+        (WebCore::appendPipelineElementMessageCallback): Deleted.
+        (WebCore::AppendPipeline::handleElementMessage): Deleted.
+        * platform/graphics/gstreamer/mse/AppendPipeline.h: New methods
+        and attributes.
+        * platform/graphics/gstreamer/mse/MediaPlayerPrivateGStreamerMSE.cpp:
+        (WebCore::MediaPlayerPrivateGStreamerMSE::dispatchDecryptionKey):
+        Use the dispatchDecryptionKey method of the AppendPipeline.
+
 2017-02-02  Joseph Pecoraro  <pecor...@apple.com>
 
         Removed unused EventHandler members

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


--- trunk/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp	2017-02-02 16:30:28 UTC (rev 211561)
+++ trunk/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp	2017-02-02 16:54:48 UTC (rev 211562)
@@ -1048,6 +1048,14 @@
                 m_player->client().requestInstallMissingPlugins(String::fromUTF8(detail.get()), String::fromUTF8(description.get()), *m_missingPluginsCallback);
             }
         }
+#if ENABLE(LEGACY_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
 #if ENABLE(VIDEO_TRACK) && USE(GSTREAMER_MPEGTS)
         else {
             GstMpegtsSection* section = gst_message_parse_mpegts_section(message);

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


--- trunk/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamerBase.cpp	2017-02-02 16:30:28 UTC (rev 211561)
+++ trunk/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamerBase.cpp	2017-02-02 16:54:48 UTC (rev 211562)
@@ -38,6 +38,8 @@
 #include "VideoSinkGStreamer.h"
 #include "WebKitWebSourceGStreamer.h"
 #include <wtf/glib/GMutexLocker.h>
+#include <wtf/glib/GUniquePtr.h>
+#include <wtf/text/AtomicString.h>
 #include <wtf/text/CString.h>
 #include <wtf/MathExtras.h>
 
@@ -91,6 +93,7 @@
 #endif
 
 #if ENABLE(LEGACY_ENCRYPTED_MEDIA) || ENABLE(ENCRYPTED_MEDIA)
+#include "SharedBuffer.h"
 #include "WebKitClearKeyDecryptorGStreamer.h"
 #if ENABLE(LEGACY_ENCRYPTED_MEDIA)
 #include "UUID.h"
@@ -107,6 +110,10 @@
 
 namespace WebCore {
 
+#if ENABLE(LEGACY_ENCRYPTED_MEDIA)
+static AtomicString keySystemIdToUuid(const AtomicString&);
+#endif
+
 void registerWebKitGStreamerElements()
 {
 #if ENABLE(LEGACY_ENCRYPTED_MEDIA) || ENABLE(ENCRYPTED_MEDIA)
@@ -201,6 +208,9 @@
     , m_drawTimer(RunLoop::main(), this, &MediaPlayerPrivateGStreamerBase::repaint)
 #endif
     , m_usingFallbackVideoSink(false)
+#if ENABLE(LEGACY_ENCRYPTED_MEDIA)
+    , m_cdmSession(0)
+#endif
 {
     g_mutex_init(&m_sampleMutex);
 #if USE(COORDINATED_GRAPHICS_THREADED)
@@ -210,6 +220,9 @@
 
 MediaPlayerPrivateGStreamerBase::~MediaPlayerPrivateGStreamerBase()
 {
+#if ENABLE(LEGACY_ENCRYPTED_MEDIA)
+    m_protectionCondition.notifyOne();
+#endif
     m_notifier.cancelPendingNotifications();
 
     if (m_videoSink) {
@@ -233,6 +246,10 @@
     if (client())
         client()->platformLayerWillBeDestroyed();
 #endif
+
+#if ENABLE(LEGACY_ENCRYPTED_MEDIA)
+    m_cdmSession = nullptr;
+#endif
 }
 
 void MediaPlayerPrivateGStreamerBase::setPipeline(GstElement* pipeline)
@@ -240,10 +257,34 @@
     m_pipeline = pipeline;
 }
 
+#if ENABLE(LEGACY_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);
-#if USE(GSTREAMER_GL)
     if (GST_MESSAGE_TYPE(message) != GST_MESSAGE_NEED_CONTEXT)
         return false;
 
@@ -250,21 +291,32 @@
     const gchar* contextType;
     gst_message_parse_context_type(message, &contextType);
 
+#if USE(GSTREAMER_GL)
     GRefPtr<GstContext> elementContext = adoptGRef(requestGLContext(contextType, this));
-    if (!elementContext)
-        return false;
-
-    gst_element_set_context(GST_ELEMENT(message->src), elementContext.get());
-    return true;
-#else
-    UNUSED_PARAM(message);
+    if (elementContext) {
+        gst_element_set_context(GST_ELEMENT(message->src), elementContext.get());
+        return true;
+    }
 #endif // USE(GSTREAMER_GL)
 
-#if ENABLE(LEGACY_ENCRYPTED_MEDIA) || ENABLE(ENCRYPTED_MEDIA)
-    if (GST_MESSAGE_TYPE(message) == GST_MESSAGE_ELEMENT) {
-        const GstStructure* structure = gst_message_get_structure(message);
-        if (gst_structure_has_name(structure, "drm-key-needed")) {
-            GST_DEBUG("handling drm-key-needed message");
+#if ENABLE(LEGACY_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");
+        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);
 
             // Here we receive the DRM init data from the pipeline: we will emit
             // the needkey event with that data and the browser might create a
@@ -273,24 +325,55 @@
             // DRM challenge to the browser and wait for an update. If on the
             // contrary no session was created we won't wait and let the pipeline
             // error out by itself.
-            GRefPtr<GstBuffer> data;
-            GUniqueOutPtr<gchar> keySystemId;
-            gboolean valid = gst_structure_get(structure, "data", GST_TYPE_BUFFER, &data.outPtr(),
-                "key-system-id", G_TYPE_STRING, &keySystemId.outPtr(), nullptr);
             GstMapInfo mapInfo;
-            if (UNLIKELY(!valid || !gst_buffer_map(data.get(), &mapInfo, GST_MAP_READ)))
-                return false;
+            if (!gst_buffer_map(data, &mapInfo, GST_MAP_READ)) {
+                GST_WARNING("cannot map %s protection data", eventKeySystemId);
+                break;
+            }
 
-#if ENABLE(LEGACY_ENCRYPTED_MEDIA)
-            GST_DEBUG("scheduling keyNeeded event");
+            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();
+
+        RunLoop::main().dispatch([this, eventKeySystemIdString, initData = WTFMove(concatenatedInitDataChunks)] {
+            GST_DEBUG("scheduling keyNeeded 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());
+
             // FIXME: Provide a somehow valid sessionId.
-            RefPtr<Uint8Array> initData = Uint8Array::create(reinterpret_cast<const unsigned char *>(mapInfo.data), mapInfo.size);
-            needKey(initData);
-#endif
+            RefPtr<Uint8Array> initDataArray = Uint8Array::create(initData.data(), initData.size());
+            needKey(initDataArray);
+        });
 
-            gst_buffer_unmap(data.get(), &mapInfo);
-            return true;
-        }
+        GST_INFO("waiting for a key request to arrive");
+        LockHolder lock(m_protectionMutex);
+        m_protectionCondition.waitFor(m_protectionMutex, Seconds(4), [this] {
+            return !this->m_lastGenerateKeyRequestKeySystemUuid.isEmpty();
+        });
+        if (!m_lastGenerateKeyRequestKeySystemUuid.isEmpty()) {
+            GST_INFO("got a key request, continuing with %s on %s", m_lastGenerateKeyRequestKeySystemUuid.utf8().data(), 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, m_lastGenerateKeyRequestKeySystemUuid.utf8().data(), nullptr);
+            gst_element_set_context(GST_ELEMENT(GST_MESSAGE_SRC(message)), context.get());
+        } else
+            GST_WARNING("did not get a proper key request");
+
+        return true;
     }
 #endif // ENABLE(LEGACY_ENCRYPTED_MEDIA)
 
@@ -1139,6 +1222,46 @@
 {
 }
 
+void MediaPlayerPrivateGStreamerBase::handleProtectionEvent(GstEvent* event)
+{
+    if (m_handledProtectionEvents.contains(GST_EVENT_SEQNUM(event))) {
+        GST_TRACE("event %u already handled", GST_EVENT_SEQNUM(event));
+        m_handledProtectionEvents.remove(GST_EVENT_SEQNUM(event));
+        return;
+    }
+
+    const gchar* eventKeySystemId = nullptr;
+    GstBuffer* data = ""
+    gst_event_parse_protection(event, &eventKeySystemId, &data, nullptr);
+
+    GstMapInfo mapInfo;
+    if (!gst_buffer_map(data, &mapInfo, GST_MAP_READ)) {
+        GST_WARNING("cannot map %s protection data", eventKeySystemId);
+        return;
+    }
+
+    GST_DEBUG("scheduling keyNeeded event for %s with init data size of %" G_GSIZE_FORMAT, eventKeySystemId, mapInfo.size);
+    GST_MEMDUMP("init datas", mapInfo.data, mapInfo.size);
+    RefPtr<Uint8Array> initDataArray = Uint8Array::create(mapInfo.data, mapInfo.size);
+    needKey(initDataArray);
+    gst_buffer_unmap(data, &mapInfo);
+}
+
+void MediaPlayerPrivateGStreamerBase::receivedGenerateKeyRequest(const String& keySystem)
+{
+    GST_DEBUG("received generate key request for %s", keySystem.utf8().data());
+    m_lastGenerateKeyRequestKeySystemUuid = keySystemIdToUuid(keySystem);
+    m_protectionCondition.notifyOne();
+}
+
+static AtomicString keySystemIdToUuid(const AtomicString& id)
+{
+    if (equalIgnoringASCIICase(id, CLEAR_KEY_PROTECTION_SYSTEM_ID))
+        return AtomicString(CLEAR_KEY_PROTECTION_SYSTEM_UUID);
+
+    return { };
+}
+
 std::unique_ptr<CDMSession> MediaPlayerPrivateGStreamerBase::createSession(const String& keySystem, CDMSessionClient*)
 {
     GST_INFO("Requested CDMSession for KeySystem %s: Returning null.", keySystem.utf8().data());

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


--- trunk/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamerBase.h	2017-02-02 16:30:28 UTC (rev 211561)
+++ trunk/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamerBase.h	2017-02-02 16:54:48 UTC (rev 211562)
@@ -123,9 +123,11 @@
 
 #if ENABLE(LEGACY_ENCRYPTED_MEDIA)
     void needKey(RefPtr<Uint8Array>);
-    void setCDMSession(CDMSession*);
-    void keyAdded();
+    void setCDMSession(CDMSession*) override;
+    void keyAdded() override;
     virtual void dispatchDecryptionKey(GstBuffer*);
+    void handleProtectionEvent(GstEvent*);
+    void receivedGenerateKeyRequest(const String&);
 #endif
 
     static bool supportsKeySystem(const String& keySystem, const String& mimeType);
@@ -139,6 +141,8 @@
     void setVideoSourceOrientation(const ImageOrientation&);
     GstElement* pipeline() const { return m_pipeline.get(); }
 
+    virtual bool handleSyncMessage(GstMessage*);
+
 protected:
     MediaPlayerPrivateGStreamerBase(MediaPlayer*);
     virtual GstElement* createVideoSink();
@@ -164,8 +168,6 @@
 
     void setPipeline(GstElement*);
 
-    virtual bool handleSyncMessage(GstMessage*);
-
     void triggerRepaint(GstSample*);
     void repaint();
 
@@ -229,8 +231,12 @@
 
     ImageOrientation m_videoSourceOrientation;
 #if ENABLE(LEGACY_ENCRYPTED_MEDIA)
-    std::unique_ptr<CDMSession> createSession(const String&, CDMSessionClient*);
+    std::unique_ptr<CDMSession> createSession(const String&, CDMSessionClient*) override;
     CDMSession* m_cdmSession;
+    Lock m_protectionMutex;
+    Condition m_protectionCondition;
+    String m_lastGenerateKeyRequestKeySystemUuid;
+    HashSet<uint32_t> m_handledProtectionEvents;
 #endif
 #if USE(GSTREAMER_GL)
     std::unique_ptr<VideoTextureCopierGStreamer> m_videoTextureCopier;

Modified: trunk/Source/WebCore/platform/graphics/gstreamer/eme/WebKitClearKeyDecryptorGStreamer.cpp (211561 => 211562)


--- trunk/Source/WebCore/platform/graphics/gstreamer/eme/WebKitClearKeyDecryptorGStreamer.cpp	2017-02-02 16:30:28 UTC (rev 211561)
+++ trunk/Source/WebCore/platform/graphics/gstreamer/eme/WebKitClearKeyDecryptorGStreamer.cpp	2017-02-02 16:54:48 UTC (rev 211562)
@@ -38,7 +38,6 @@
 };
 
 static void webKitMediaClearKeyDecryptorFinalize(GObject*);
-static void webKitMediaClearKeyDecryptorRequestDecryptionKey(WebKitMediaCommonEncryptionDecrypt* self, GstBuffer*);
 static gboolean webKitMediaClearKeyDecryptorHandleKeyResponse(WebKitMediaCommonEncryptionDecrypt* self, GstEvent*);
 static gboolean webKitMediaClearKeyDecryptorSetupCipher(WebKitMediaCommonEncryptionDecrypt*);
 static gboolean webKitMediaClearKeyDecryptorDecrypt(WebKitMediaCommonEncryptionDecrypt*, GstBuffer* iv, GstBuffer* sample, unsigned subSamplesCount, GstBuffer* subSamples);
@@ -47,13 +46,11 @@
 GST_DEBUG_CATEGORY_STATIC(webkit_media_clear_key_decrypt_debug_category);
 #define GST_CAT_DEFAULT webkit_media_clear_key_decrypt_debug_category
 
-#define CLEAR_KEY_PROTECTION_SYSTEM_ID "58147ec8-0423-4659-92e6-f52c5ce8c3cc"
-
 static GstStaticPadTemplate sinkTemplate = GST_STATIC_PAD_TEMPLATE("sink",
     GST_PAD_SINK,
     GST_PAD_ALWAYS,
-    GST_STATIC_CAPS("application/x-cenc, original-media-type=(string)video/x-h264, protection-system=(string)" CLEAR_KEY_PROTECTION_SYSTEM_ID "; "
-    "application/x-cenc, original-media-type=(string)audio/mpeg, protection-system=(string)" CLEAR_KEY_PROTECTION_SYSTEM_ID));
+    GST_STATIC_CAPS("application/x-cenc, original-media-type=(string)video/x-h264, protection-system=(string)" CLEAR_KEY_PROTECTION_SYSTEM_UUID "; "
+    "application/x-cenc, original-media-type=(string)audio/mpeg, protection-system=(string)" CLEAR_KEY_PROTECTION_SYSTEM_UUID));
 
 static GstStaticPadTemplate srcTemplate = GST_STATIC_PAD_TEMPLATE("src",
     GST_PAD_SRC,
@@ -82,8 +79,7 @@
         "webkitclearkey", 0, "ClearKey decryptor");
 
     WebKitMediaCommonEncryptionDecryptClass* cencClass = WEBKIT_MEDIA_CENC_DECRYPT_CLASS(klass);
-    cencClass->protectionSystemId = CLEAR_KEY_PROTECTION_SYSTEM_ID;
-    cencClass->requestDecryptionKey = GST_DEBUG_FUNCPTR(webKitMediaClearKeyDecryptorRequestDecryptionKey);
+    cencClass->protectionSystemId = CLEAR_KEY_PROTECTION_SYSTEM_UUID;
     cencClass->handleKeyResponse = GST_DEBUG_FUNCPTR(webKitMediaClearKeyDecryptorHandleKeyResponse);
     cencClass->setupCipher = GST_DEBUG_FUNCPTR(webKitMediaClearKeyDecryptorSetupCipher);
     cencClass->decrypt = GST_DEBUG_FUNCPTR(webKitMediaClearKeyDecryptorDecrypt);
@@ -119,14 +115,6 @@
     GST_CALL_PARENT(G_OBJECT_CLASS, finalize, (object));
 }
 
-static void webKitMediaClearKeyDecryptorRequestDecryptionKey(WebKitMediaCommonEncryptionDecrypt* self, GstBuffer* initDataBuffer)
-{
-    gst_element_post_message(GST_ELEMENT(self),
-        gst_message_new_element(GST_OBJECT(self),
-            gst_structure_new("drm-key-needed", "data", GST_TYPE_BUFFER, initDataBuffer,
-                "key-system-id", G_TYPE_STRING, "org.w3.clearkey", nullptr)));
-}
-
 static gboolean webKitMediaClearKeyDecryptorHandleKeyResponse(WebKitMediaCommonEncryptionDecrypt* self, GstEvent* event)
 {
     WebKitMediaClearKeyDecryptPrivate* priv = WEBKIT_MEDIA_CK_DECRYPT_GET_PRIVATE(WEBKIT_MEDIA_CK_DECRYPT(self));

Modified: trunk/Source/WebCore/platform/graphics/gstreamer/eme/WebKitClearKeyDecryptorGStreamer.h (211561 => 211562)


--- trunk/Source/WebCore/platform/graphics/gstreamer/eme/WebKitClearKeyDecryptorGStreamer.h	2017-02-02 16:30:28 UTC (rev 211561)
+++ trunk/Source/WebCore/platform/graphics/gstreamer/eme/WebKitClearKeyDecryptorGStreamer.h	2017-02-02 16:54:48 UTC (rev 211562)
@@ -25,6 +25,9 @@
 
 #include "WebKitCommonEncryptionDecryptorGStreamer.h"
 
+#define CLEAR_KEY_PROTECTION_SYSTEM_UUID "58147ec8-0423-4659-92e6-f52c5ce8c3cc"
+#define CLEAR_KEY_PROTECTION_SYSTEM_ID "org.w3.clearkey"
+
 G_BEGIN_DECLS
 
 #define WEBKIT_TYPE_MEDIA_CK_DECRYPT          (webkit_media_clear_key_decrypt_get_type())

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


--- trunk/Source/WebCore/platform/graphics/gstreamer/eme/WebKitCommonEncryptionDecryptorGStreamer.cpp	2017-02-02 16:30:28 UTC (rev 211561)
+++ trunk/Source/WebCore/platform/graphics/gstreamer/eme/WebKitCommonEncryptionDecryptorGStreamer.cpp	2017-02-02 16:54:48 UTC (rev 211562)
@@ -292,30 +292,19 @@
 
     switch (GST_EVENT_TYPE(event)) {
     case GST_EVENT_PROTECTION: {
-        const char* systemId;
-        const char* origin;
-        GstBuffer* initDataBuffer;
+        const char* systemId = nullptr;
 
-        GST_DEBUG_OBJECT(self, "received protection event");
-        gst_event_parse_protection(event, &systemId, &initDataBuffer, &origin);
-        GST_DEBUG_OBJECT(self, "systemId: %s", systemId);
+        gst_event_parse_protection(event, &systemId, nullptr, nullptr);
+        GST_TRACE_OBJECT(self, "received protection event for %s", systemId);
 
-        if (!g_str_equal(systemId, klass->protectionSystemId)) {
-            gst_event_unref(event);
-            result = TRUE;
-            break;
+        if (!g_strcmp0(systemId, klass->protectionSystemId)) {
+            GST_DEBUG_OBJECT(self, "sending protection event to the pipeline");
+            gst_element_post_message(GST_ELEMENT(self),
+                gst_message_new_element(GST_OBJECT(self),
+                    gst_structure_new("drm-key-needed", "event", GST_TYPE_EVENT, event, nullptr)));
         }
 
-        // Keep the event ref around so that the parsed event data
-        // remains valid until the drm-key-need message has been sent.
-        priv->protectionEvent = adoptGRef(event);
-        RunLoop::main().dispatch([self, initDataBuffer] {
-            WebKitMediaCommonEncryptionDecryptClass* klass = WEBKIT_MEDIA_CENC_DECRYPT_GET_CLASS(self);
-            if (klass) {
-                klass->requestDecryptionKey(self, initDataBuffer);
-                self->priv->protectionEvent = nullptr;
-            }});
-
+        gst_event_unref(event);
         result = TRUE;
         break;
     }

Modified: trunk/Source/WebCore/platform/graphics/gstreamer/eme/WebKitCommonEncryptionDecryptorGStreamer.h (211561 => 211562)


--- trunk/Source/WebCore/platform/graphics/gstreamer/eme/WebKitCommonEncryptionDecryptorGStreamer.h	2017-02-02 16:30:28 UTC (rev 211561)
+++ trunk/Source/WebCore/platform/graphics/gstreamer/eme/WebKitCommonEncryptionDecryptorGStreamer.h	2017-02-02 16:54:48 UTC (rev 211562)
@@ -53,7 +53,6 @@
     GstBaseTransformClass parentClass;
 
     const char* protectionSystemId;
-    void (*requestDecryptionKey)(WebKitMediaCommonEncryptionDecrypt*, GstBuffer* initData);
     gboolean (*handleKeyResponse)(WebKitMediaCommonEncryptionDecrypt*, GstEvent* event);
     gboolean (*setupCipher)(WebKitMediaCommonEncryptionDecrypt*);
     gboolean (*decrypt)(WebKitMediaCommonEncryptionDecrypt*, GstBuffer* ivBuffer, GstBuffer* buffer, unsigned subSamplesCount, GstBuffer* subSamplesBuffer);

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


--- trunk/Source/WebCore/platform/graphics/gstreamer/mse/AppendPipeline.cpp	2017-02-02 16:30:28 UTC (rev 211561)
+++ trunk/Source/WebCore/platform/graphics/gstreamer/mse/AppendPipeline.cpp	2017-02-02 16:54:48 UTC (rev 211562)
@@ -79,9 +79,10 @@
 static GstFlowReturn appendPipelineAppsinkNewSample(GstElement*, AppendPipeline*);
 static void appendPipelineAppsinkEOS(GstElement*, AppendPipeline*);
 
-static void appendPipelineElementMessageCallback(GstBus*, GstMessage* message, AppendPipeline* appendPipeline)
+static void appendPipelineNeedContextMessageCallback(GstBus*, GstMessage* message, AppendPipeline* appendPipeline)
 {
-    appendPipeline->handleElementMessage(message);
+    GST_TRACE("received callback");
+    appendPipeline->handleNeedContextSyncMessage(message);
 }
 
 static void appendPipelineApplicationMessageCallback(GstBus*, GstMessage* message, AppendPipeline* appendPipeline)
@@ -113,7 +114,7 @@
     gst_bus_add_signal_watch(m_bus.get());
     gst_bus_enable_sync_message_emission(m_bus.get());
 
-    g_signal_connect(m_bus.get(), "sync-message::element", G_CALLBACK(appendPipelineElementMessageCallback), this);
+    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);
 
     // We assign the created instances here instead of adoptRef() because gst_bin_add_many()
@@ -213,6 +214,33 @@
     m_demuxerSrcPadCaps = nullptr;
 };
 
+#if ENABLE(LEGACY_ENCRYPTED_MEDIA)
+void AppendPipeline::dispatchPendingDecryptionKey()
+{
+    ASSERT(m_decryptor);
+    ASSERT(m_pendingKey);
+    ASSERT(m_appendState == KeyNegotiation);
+    GST_TRACE("dispatching key to append pipeline %p", this);
+    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, m_pendingKey.get(), nullptr)));
+    m_pendingKey.clear();
+    setAppendState(AppendState::Ongoing);
+}
+
+void AppendPipeline::dispatchDecryptionKey(GstBuffer* buffer)
+{
+    if (m_appendState == AppendState::KeyNegotiation) {
+        GST_TRACE("append pipeline %p in key negotiation", this);
+        m_pendingKey = buffer;
+        if (m_decryptor)
+            dispatchPendingDecryptionKey();
+        else
+            GST_TRACE("no decryptor yet, waiting for it");
+    } else
+        GST_TRACE("append pipeline %p not in key negotiation", this);
+}
+#endif
+
 void AppendPipeline::clearPlayerPrivate()
 {
     ASSERT(WTF::isMainThread());
@@ -240,12 +268,12 @@
         gst_element_set_state(m_pipeline.get(), GST_STATE_NULL);
 }
 
-void AppendPipeline::handleElementMessage(GstMessage* message)
+void AppendPipeline::handleNeedContextSyncMessage(GstMessage* message)
 {
-    ASSERT(WTF::isMainThread());
-
-    const GstStructure* structure = gst_message_get_structure(message);
-    if (gst_structure_has_name(structure, "drm-key-needed"))
+    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"))
         setAppendState(AppendPipeline::AppendState::KeyNegotiation);
 
     // MediaPlayerPrivateGStreamerBase will take care of setting up encryption.
@@ -938,6 +966,11 @@
 
             gst_element_sync_state_with_parent(m_appsink.get());
             gst_element_sync_state_with_parent(m_decryptor.get());
+
+#if ENABLE(LEGACY_ENCRYPTED_MEDIA)
+            if (m_pendingKey)
+                dispatchPendingDecryptionKey();
+#endif
         } else {
 #endif
             gst_pad_link(demuxerSrcPad, appsinkSinkPad.get());

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


--- trunk/Source/WebCore/platform/graphics/gstreamer/mse/AppendPipeline.h	2017-02-02 16:30:28 UTC (rev 211561)
+++ trunk/Source/WebCore/platform/graphics/gstreamer/mse/AppendPipeline.h	2017-02-02 16:54:48 UTC (rev 211562)
@@ -47,7 +47,7 @@
     AppendPipeline(Ref<MediaSourceClientGStreamerMSE>, Ref<SourceBufferPrivateGStreamer>, MediaPlayerPrivateGStreamerMSE&);
     virtual ~AppendPipeline();
 
-    void handleElementMessage(GstMessage*);
+    void handleNeedContextSyncMessage(GstMessage*);
     void handleApplicationMessage(GstMessage*);
 
     gint id();
@@ -56,6 +56,9 @@
 
     GstFlowReturn handleNewAppsinkSample(GstElement*);
     GstFlowReturn pushNewBuffer(GstBuffer*);
+#if ENABLE(LEGACY_ENCRYPTED_MEDIA)
+    void dispatchDecryptionKey(GstBuffer*);
+#endif
 
     // Takes ownership of caps.
     void parseDemuxerSrcPadCaps(GstCaps*);
@@ -91,6 +94,9 @@
     void handleAppsrcNeedDataReceived();
     void removeAppsrcDataLeavingProbe();
     void setAppsrcDataLeavingProbe();
+#if ENABLE(LEGACY_ENCRYPTED_MEDIA)
+    void dispatchPendingDecryptionKey();
+#endif
 
 private:
     Ref<MediaSourceClientGStreamerMSE> m_mediaSourceClient;
@@ -146,6 +152,9 @@
     RefPtr<WebCore::TrackPrivateBase> m_track;
 
     GRefPtr<GstBuffer> m_pendingBuffer;
+#if ENABLE(LEGACY_ENCRYPTED_MEDIA)
+    GRefPtr<GstBuffer> m_pendingKey;
+#endif
 };
 
 } // namespace WebCore.

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


--- trunk/Source/WebCore/platform/graphics/gstreamer/mse/MediaPlayerPrivateGStreamerMSE.cpp	2017-02-02 16:30:28 UTC (rev 211561)
+++ trunk/Source/WebCore/platform/graphics/gstreamer/mse/MediaPlayerPrivateGStreamerMSE.cpp	2017-02-02 16:54:48 UTC (rev 211562)
@@ -804,15 +804,8 @@
 #if ENABLE(LEGACY_ENCRYPTED_MEDIA)
 void MediaPlayerPrivateGStreamerMSE::dispatchDecryptionKey(GstBuffer* buffer)
 {
-    for (auto iterator : m_appendPipelinesMap) {
-        if (iterator.value->appendState() == AppendPipeline::AppendState::KeyNegotiation) {
-            GST_TRACE("append pipeline %p in key negotiation, setting key", iterator.value.get());
-            gst_element_send_event(iterator.value->pipeline(), gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM_OOB,
-                gst_structure_new("drm-cipher", "key", GST_TYPE_BUFFER, buffer, nullptr)));
-            iterator.value->setAppendState(AppendPipeline::AppendState::Ongoing);
-        } else
-            GST_TRACE("append pipeline %p not in key negotiation", iterator.value.get());
-    }
+    for (auto it : m_appendPipelinesMap)
+        it.value->dispatchDecryptionKey(buffer);
 }
 #endif
 

Modified: trunk/Tools/ChangeLog (211561 => 211562)


--- trunk/Tools/ChangeLog	2017-02-02 16:30:28 UTC (rev 211561)
+++ trunk/Tools/ChangeLog	2017-02-02 16:54:48 UTC (rev 211562)
@@ -1,3 +1,17 @@
+2017-02-02  Xabier Rodriguez Calvar  <calva...@igalia.com>
+
+        [EME][GStreamer] Fixed decryptor selection
+        https://bugs.webkit.org/show_bug.cgi?id=167588
+
+        Reviewed by Žan Doberšek.
+
+        This patches are pending at https://bugzilla.gnome.org/show_bug.cgi?id=770107
+
+        * gtk/jhbuild.modules: Added patches to gstreamer and
+        gst-plugins-good packages.
+        * gtk/patches/gst-plugins-good-0004-qtdemux-add-context-for-a-preferred-protection.patch: Added.
+        * gtk/patches/gstreamer-0001-protection-added-function-to-filter-system-ids.patch: Added.
+
 2017-02-01  Dewei Zhu  <dewei_...@apple.com>
 
         Make run-benchmark script supports 'config' key in test plan.

Modified: trunk/Tools/gtk/jhbuild.modules (211561 => 211562)


--- trunk/Tools/gtk/jhbuild.modules	2017-02-02 16:30:28 UTC (rev 211561)
+++ trunk/Tools/gtk/jhbuild.modules	2017-02-02 16:54:48 UTC (rev 211562)
@@ -361,7 +361,9 @@
     <branch module="gstreamer/gstreamer-${version}.tar.xz" version="1.8.0"
             repo="gstreamer"
             hash="sha256:947a314a212b5d94985d89b43440dbe66b696e12bbdf9a2f78967b98d74abedc"
-            md5sum="6846d7289ec323c38c49b818171e955a"/>
+            md5sum="6846d7289ec323c38c49b818171e955a">
+      <patch file="gstreamer-0001-protection-added-function-to-filter-system-ids.patch" strip="1"/>
+    </branch>
   </autotools>
 
   <autotools id="gst-plugins-base"
@@ -397,6 +399,7 @@
       <patch file="gst-plugins-good-0001-rtpbin-pipeline-gets-an-EOS-when-any-rtpsources-byes.patch" strip="1"/>
       <patch file="gst-plugins-good-0002-rtpbin-avoid-generating-errors-when-rtcp-messages-ar.patch" strip="1"/>
       <patch file="gst-plugins-good-0003-rtpbin-receive-bundle-support.patch" strip="1"/>
+      <patch file="gst-plugins-good-0004-qtdemux-add-context-for-a-preferred-protection.patch" strip="1"/>
     </branch>
   </autotools>
 

Added: trunk/Tools/gtk/patches/gst-plugins-good-0004-qtdemux-add-context-for-a-preferred-protection.patch (0 => 211562)


--- trunk/Tools/gtk/patches/gst-plugins-good-0004-qtdemux-add-context-for-a-preferred-protection.patch	                        (rev 0)
+++ trunk/Tools/gtk/patches/gst-plugins-good-0004-qtdemux-add-context-for-a-preferred-protection.patch	2017-02-02 16:54:48 UTC (rev 211562)
@@ -0,0 +1,319 @@
+From 5562a03c58a06339df2bf0a55cb39be7321094dd Mon Sep 17 00:00:00 2001
+From: Xabier Rodriguez Calvar <calva...@igalia.com>
+Date: Fri, 16 Sep 2016 16:08:18 +0200
+Subject: [PATCH] qtdemux: add context for a preferred protection
+
+qtdemux selected the first system corresponding to a working GStreamer
+decryptor. With this change, before selecting that decryptor, qtdemux
+will check if it has context (a preferred decryptor id) and if not, it
+will request it.
+
+The request includes track-id, available key system ids for the
+available decryptors and event the events so that the init data is
+accessible.
+---
+ gst/isomp4/qtdemux.c | 209 +++++++++++++++++++++++++++++++++++++++++++++++++--
+ gst/isomp4/qtdemux.h |   1 +
+ 2 files changed, 204 insertions(+), 6 deletions(-)
+
+diff --git a/gst/isomp4/qtdemux.c b/gst/isomp4/qtdemux.c
+index 782ad2f..f56872a 100644
+--- a/gst/isomp4/qtdemux.c
++++ b/gst/isomp4/qtdemux.c
+@@ -477,6 +477,8 @@ static GstIndex *gst_qtdemux_get_index (GstElement * element);
+ #endif
+ static GstStateChangeReturn gst_qtdemux_change_state (GstElement * element,
+     GstStateChange transition);
++static void gst_qtdemux_set_context (GstElement * element,
++    GstContext * context);
+ static gboolean qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent);
+ static gboolean qtdemux_sink_activate_mode (GstPad * sinkpad,
+     GstObject * parent, GstPadMode mode, gboolean active);
+@@ -569,6 +571,7 @@ gst_qtdemux_class_init (GstQTDemuxClass * klass)
+   gstelement_class->set_index = GST_DEBUG_FUNCPTR (gst_qtdemux_set_index);
+   gstelement_class->get_index = GST_DEBUG_FUNCPTR (gst_qtdemux_get_index);
+ #endif
++  gstelement_class->set_context = GST_DEBUG_FUNCPTR (gst_qtdemux_set_context);
+ 
+   gst_tag_register_musicbrainz_tags ();
+ 
+@@ -628,6 +631,7 @@ gst_qtdemux_init (GstQTDemux * qtdemux)
+   qtdemux->cenc_aux_sample_count = 0;
+   qtdemux->protection_system_ids = NULL;
+   qtdemux->always_honor_tfdt = FALSE;
++  qtdemux->preferred_protection_system_id = NULL;
+   g_queue_init (&qtdemux->protection_event_queue);
+   gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
+   qtdemux->flowcombiner = gst_flow_combiner_new ();
+@@ -2023,6 +2027,10 @@ gst_qtdemux_reset (GstQTDemux * qtdemux, gboolean hard)
+     g_queue_foreach (&qtdemux->protection_event_queue, (GFunc) gst_event_unref,
+         NULL);
+     g_queue_clear (&qtdemux->protection_event_queue);
++    if (qtdemux->preferred_protection_system_id) {
++      g_free (qtdemux->preferred_protection_system_id);
++      qtdemux->preferred_protection_system_id = NULL;
++    }
+   }
+   qtdemux->offset = 0;
+   gst_adapter_clear (qtdemux->adapter);
+@@ -2454,6 +2462,29 @@ gst_qtdemux_change_state (GstElement * element, GstStateChange transition)
+ }
+ 
+ static void
++gst_qtdemux_set_context (GstElement * element, GstContext * context)
++{
++  GstQTDemux *qtdemux = GST_QTDEMUX (element);
++
++  g_return_if_fail (GST_IS_CONTEXT (context));
++
++  if (g_strcmp0 (gst_context_get_context_type (context),
++          "drm-preferred-decryption-system-id") == 0) {
++    const GstStructure *s;
++
++    s = gst_context_get_structure (context);
++    qtdemux->preferred_protection_system_id =
++        g_strdup (gst_structure_get_string (s, "decryption-system-id"));
++    GST_DEBUG_OBJECT (element, "set preferred decryption system to %s",
++        qtdemux->preferred_protection_system_id);
++  }
++
++  GST_TRACE_OBJECT (element, "chaining set_context to superclass %p or %p",
++      GST_ELEMENT_GET_CLASS (element), parent_class);
++  GST_ELEMENT_CLASS (parent_class)->set_context (element, context);
++}
++
++static void
+ qtdemux_parse_ftyp (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
+ {
+   /* counts as header data */
+@@ -3433,6 +3464,8 @@ qtdemux_parse_pssh (GstQTDemux * qtdemux, GNode * node)
+   event = gst_event_new_protection (sysid_string, pssh,
+       (parent_box_type == FOURCC_moov) ? "isobmff/moov" : "isobmff/moof");
+   for (i = 0; i < qtdemux->n_streams; ++i) {
++    GST_TRACE_OBJECT (qtdemux,
++        "adding protection event for stream %d and system %s", i, sysid_string);
+     g_queue_push_tail (&qtdemux->streams[i]->protection_scheme_event_queue,
+         gst_event_ref (event));
+   }
+@@ -5033,6 +5066,12 @@ gst_qtdemux_decorate_and_push_buffer (GstQTDemux * qtdemux,
+     GstEvent *event;
+ 
+     while ((event = g_queue_pop_head (&stream->protection_scheme_event_queue))) {
++#if (!GST_DISABLE_GST_DEBUG)
++      const gchar *system_id = NULL;
++      gst_event_parse_protection (event, &system_id, NULL, NULL);
++      GST_TRACE_OBJECT (qtdemux, "pushing again protection event for system %s",
++          system_id);
++#endif
+       gst_pad_push_event (stream->pad, event);
+     }
+ 
+@@ -6987,11 +7026,148 @@ qtdemux_do_allocation (GstQTDemux * qtdemux, QtDemuxStream * stream)
+ }
+ 
+ static gboolean
++pad_query (const GValue * item, GValue * value, gpointer user_data)
++{
++  GstPad *pad = g_value_get_object (item);
++  GstQuery *query = user_data;
++  gboolean res;
++
++  res = gst_pad_peer_query (pad, query);
++
++  if (res) {
++    g_value_set_boolean (value, TRUE);
++    return FALSE;
++  }
++
++  GST_INFO_OBJECT (pad, "pad peer query failed");
++  return TRUE;
++}
++
++static gboolean
++gst_qtdemux_run_query (GstElement * element, GstQuery * query,
++    GstPadDirection direction)
++{
++  GstIterator *it;
++  GstIteratorFoldFunction func = pad_query;
++  GValue res = { 0, };
++
++  g_value_init (&res, G_TYPE_BOOLEAN);
++  g_value_set_boolean (&res, FALSE);
++
++  /* Ask neighbor */
++  if (direction == GST_PAD_SRC)
++    it = gst_element_iterate_src_pads (element);
++  else
++    it = gst_element_iterate_sink_pads (element);
++
++  while (gst_iterator_fold (it, func, &res, query) == GST_ITERATOR_RESYNC)
++    gst_iterator_resync (it);
++
++  gst_iterator_free (it);
++
++  return g_value_get_boolean (&res);
++}
++
++static void
++gst_qtdemux_request_protection_context_if_needed (GstQTDemux * qtdemux,
++    QtDemuxStream * stream)
++{
++  GstQuery *query;
++  GstContext *ctxt;
++  GstElement *element = GST_ELEMENT (qtdemux);
++  GstStructure *st;
++  gchar **filtered_sys_ids;
++  GValue event_list = G_VALUE_INIT;
++  GList *walk;
++
++  /* 1. Check if we already have the context. */
++  if (qtdemux->preferred_protection_system_id != NULL) {
++    GST_LOG_OBJECT (element,
++        "already have the protection context, no need to request it again");
++    return;
++  }
++
++  GST_TRACE_OBJECT (qtdemux, "currently we have detected %u protection systems",
++      qtdemux->protection_system_ids->len);
++  g_ptr_array_add (qtdemux->protection_system_ids, NULL);
++  filtered_sys_ids = gst_protection_filter_systems_by_available_decryptors (
++      (const gchar **) qtdemux->protection_system_ids->pdata);
++  g_ptr_array_remove_index (qtdemux->protection_system_ids,
++      qtdemux->protection_system_ids->len - 1);
++  if (filtered_sys_ids == NULL || filtered_sys_ids[0] == NULL) {
++    GST_LOG_OBJECT (qtdemux, "no suitable decryptors found, not issuing the "
++        "context request");
++    g_strfreev (filtered_sys_ids);
++    return;
++  }
++  GST_TRACE_OBJECT (qtdemux, "found suitable decryptors, running the context "
++      "request");
++
++  if (stream->protection_scheme_event_queue.length) {
++    GST_TRACE_OBJECT (qtdemux, "using stream event queue, length %u",
++        stream->protection_scheme_event_queue.length);
++    walk = stream->protection_scheme_event_queue.tail;
++  } else {
++    GST_TRACE_OBJECT (qtdemux, "using demuxer event queue, length %u",
++        qtdemux->protection_event_queue.length);
++    walk = qtdemux->protection_event_queue.tail;
++  }
++
++  g_value_init (&event_list, GST_TYPE_LIST);
++  for (; walk; walk = g_list_previous (walk)) {
++    GValue *event_value = g_new0 (GValue, 1);
++    g_value_init (event_value, GST_TYPE_EVENT);
++    g_value_set_boxed (event_value, walk->data);
++    gst_value_list_append_and_take_value (&event_list, event_value);
++  }
++
++  /*  2a) Query downstream with GST_QUERY_CONTEXT for the context and
++   *      check if downstream already has a context of the specific type
++   *  2b) Query upstream as above.
++   */
++  query = gst_query_new_context ("drm-preferred-decryption-system-id");
++  st = (GstStructure *) gst_query_get_structure (query);
++  gst_structure_set (st, "track-id", G_TYPE_UINT, stream->track_id,
++      "stream-encryption-systems", G_TYPE_STRV, filtered_sys_ids, NULL);
++  gst_structure_set_value (st, "stream-encryption-events", &event_list);
++  if (gst_qtdemux_run_query (element, query, GST_PAD_SRC)) {
++    gst_query_parse_context (query, &ctxt);
++    GST_INFO_OBJECT (element, "found context (%p) in downstream query", ctxt);
++    gst_element_set_context (element, ctxt);
++  } else if (gst_qtdemux_run_query (element, query, GST_PAD_SINK)) {
++    gst_query_parse_context (query, &ctxt);
++    GST_INFO_OBJECT (element, "found context (%p) in upstream query", ctxt);
++    gst_element_set_context (element, ctxt);
++  } else {
++    /* 3) Post a GST_MESSAGE_NEED_CONTEXT message on the bus with
++     *    the required context type and afterwards check if a
++     *    usable context was set now as in 1). The message could
++     *    be handled by the parent bins of the element and the
++     *    application.
++     */
++    GstMessage *msg;
++
++    GST_INFO_OBJECT (element, "posting need context message");
++    msg = gst_message_new_need_context (GST_OBJECT_CAST (element),
++        "drm-preferred-decryption-system-id");
++    st = (GstStructure *) gst_message_get_structure (msg);
++    gst_structure_set (st, "track-id", G_TYPE_UINT, stream->track_id,
++        "stream-encryption-systems", G_TYPE_STRV, filtered_sys_ids, NULL);
++    gst_structure_set_value (st, "stream-encryption-events", &event_list);
++    gst_element_post_message (element, msg);
++  }
++
++  g_strfreev (filtered_sys_ids);
++  g_value_unset (&event_list);
++  gst_query_unref (query);
++}
++
++static gboolean
+ gst_qtdemux_configure_protected_caps (GstQTDemux * qtdemux,
+     QtDemuxStream * stream)
+ {
+   GstStructure *s;
+-  const gchar *selected_system;
++  const gchar *selected_system = NULL;
+ 
+   g_return_val_if_fail (qtdemux != NULL, FALSE);
+   g_return_val_if_fail (stream != NULL, FALSE);
+@@ -7006,17 +7182,38 @@ gst_qtdemux_configure_protected_caps (GstQTDemux * qtdemux,
+         "cenc protection system information has been found");
+     return FALSE;
+   }
+-  g_ptr_array_add (qtdemux->protection_system_ids, NULL);
+-  selected_system = gst_protection_select_system ((const gchar **)
+-      qtdemux->protection_system_ids->pdata);
+-  g_ptr_array_remove_index (qtdemux->protection_system_ids,
+-      qtdemux->protection_system_ids->len - 1);
++
++  gst_qtdemux_request_protection_context_if_needed (qtdemux, stream);
++  if (qtdemux->preferred_protection_system_id != NULL) {
++    guint i;
++    for (i = 0; i < qtdemux->protection_system_ids->len; i++) {
++      if (g_strcmp0 (g_ptr_array_index (qtdemux->protection_system_ids, i),
++              qtdemux->preferred_protection_system_id) == 0) {
++        const gchar *preferred_system_array[] =
++            { qtdemux->preferred_protection_system_id, NULL };
++        selected_system = gst_protection_select_system (preferred_system_array);
++        break;
++      }
++    }
++  }
++
++  if (!selected_system) {
++    g_ptr_array_add (qtdemux->protection_system_ids, NULL);
++    selected_system = gst_protection_select_system ((const gchar **)
++        qtdemux->protection_system_ids->pdata);
++    g_ptr_array_remove_index (qtdemux->protection_system_ids,
++        qtdemux->protection_system_ids->len - 1);
++  }
++
+   if (!selected_system) {
+     GST_ERROR_OBJECT (qtdemux, "stream is protected, but no "
+         "suitable decryptor element has been found");
+     return FALSE;
+   }
+ 
++  GST_DEBUG_OBJECT (qtdemux, "selected protection system is %s",
++      selected_system);
++
+   s = gst_caps_get_structure (stream->caps, 0);
+   if (!gst_structure_has_name (s, "application/x-cenc")) {
+     gst_structure_set (s,
+diff --git a/gst/isomp4/qtdemux.h b/gst/isomp4/qtdemux.h
+index ecf0c63..0c53437 100644
+--- a/gst/isomp4/qtdemux.h
++++ b/gst/isomp4/qtdemux.h
+@@ -153,6 +153,7 @@ struct _GstQTDemux {
+   guint64 cenc_aux_info_offset;
+   guint8 *cenc_aux_info_sizes;
+   guint32 cenc_aux_sample_count;
++  gchar *preferred_protection_system_id;
+ 
+   gboolean always_honor_tfdt;
+ };
+-- 
+2.11.0
+

Added: trunk/Tools/gtk/patches/gstreamer-0001-protection-added-function-to-filter-system-ids.patch (0 => 211562)


--- trunk/Tools/gtk/patches/gstreamer-0001-protection-added-function-to-filter-system-ids.patch	                        (rev 0)
+++ trunk/Tools/gtk/patches/gstreamer-0001-protection-added-function-to-filter-system-ids.patch	2017-02-02 16:54:48 UTC (rev 211562)
@@ -0,0 +1,77 @@
+From 7772eb350591682b6a315c8a87a58131f731f1d4 Mon Sep 17 00:00:00 2001
+From: Xabier Rodriguez Calvar <calva...@igalia.com>
+Date: Wed, 19 Oct 2016 16:44:16 +0200
+Subject: [PATCH] protection: added function to filter system ids
+
+gst_protection_filter_systems_by_available_decryptors takes an array of
+strings and returns a new array of strings filtered by the avaible
+decryptors for them so the ones you get are the ones that you should be
+able to decrypt.
+---
+ gst/gstprotection.c | 36 ++++++++++++++++++++++++++++++++++++
+ gst/gstprotection.h |  2 ++
+ 2 files changed, 38 insertions(+)
+
+diff --git a/gst/gstprotection.c b/gst/gstprotection.c
+index 8ee52ea..2d7e5e0 100644
+--- a/gst/gstprotection.c
++++ b/gst/gstprotection.c
+@@ -191,6 +191,42 @@ gst_protection_select_system (const gchar ** system_identifiers)
+   return retval;
+ }
+ 
++gchar **
++gst_protection_filter_systems_by_available_decryptors (const gchar **
++    system_identifiers)
++{
++  GList *decryptors, *walk;
++  gchar **retval;
++  guint i = 0, decryptors_number;
++
++  decryptors =
++      gst_element_factory_list_get_elements (GST_ELEMENT_FACTORY_TYPE_DECRYPTOR,
++      GST_RANK_MARGINAL);
++
++  decryptors_number = g_list_length (decryptors);
++  retval = g_new (gchar *, decryptors_number + 1);
++
++  GST_TRACE ("found %u decrytors", decryptors_number);
++
++  for (walk = decryptors; walk; walk = g_list_next (walk)) {
++    GstElementFactory *fact = (GstElementFactory *) walk->data;
++
++    const char *found_sys_id =
++        gst_protection_factory_check (fact, system_identifiers);
++    GST_TRACE ("factory %s is valid for %s", GST_OBJECT_NAME (fact),
++        found_sys_id);
++
++    if (found_sys_id) {
++      retval[i++] = g_strdup (found_sys_id);
++    }
++  }
++  retval[i] = NULL;
++
++  gst_plugin_feature_list_free (decryptors);
++
++  return retval;
++}
++
+ static const gchar *
+ gst_protection_factory_check (GstElementFactory * fact,
+     const gchar ** system_identifiers)
+diff --git a/gst/gstprotection.h b/gst/gstprotection.h
+index f2f54c4..95976c5 100644
+--- a/gst/gstprotection.h
++++ b/gst/gstprotection.h
+@@ -66,6 +66,8 @@ GstProtectionMeta *gst_buffer_add_protection_meta (GstBuffer * buffer,
+     GstStructure * info);
+ 
+ const gchar *gst_protection_select_system (const gchar ** system_identifiers);
++gchar ** gst_protection_filter_systems_by_available_decryptors (
++    const gchar ** system_identifiers);
+ 
+ G_END_DECLS
+ #endif /* __GST_PROTECTION_META_H__ */
+-- 
+2.10.2
+
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to