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
+