Diff
Modified: trunk/Source/WebCore/ChangeLog (221223 => 221224)
--- trunk/Source/WebCore/ChangeLog 2017-08-26 08:01:24 UTC (rev 221223)
+++ trunk/Source/WebCore/ChangeLog 2017-08-26 08:29:00 UTC (rev 221224)
@@ -1,3 +1,67 @@
+2017-08-26 Xabier Rodriguez Calvar <[email protected]>
+
+ [EME][GStreamer] Connect CDM to GStreamer
+ https://bugs.webkit.org/show_bug.cgi?id=175983
+
+ Reviewed by Žan Doberšek.
+
+ This is still a version that will need some changes for some other
+ use cases but it should be enough to begin with some passes in the
+ tests and some basic use cases.
+
+ We use the attach CDMInstance interface in the private player to
+ get the instance in time for the initializationDataEncountered
+ event, which is handled when the demuxer reports synchronously the
+ events even before configuring the decryptors. We wait there in
+ case we don't have the CDMInstance attached (which contains info
+ about the key system now) and when we get it we report it back to
+ the demuxer and continue sending the event.
+
+ We also handled the events when handled by the decryptors but for
+ now this will remain a FIXME. The events handled by the
+ AppendPipeline will end up here too for now.
+
+ The CDM instance is created with the key system because some CDMs
+ can handle more than one, not ClearKey yet but others in the
+ (near) future.
+
+ MockCDMFactory is adapted to the changes as expected.
+
+ * Modules/encryptedmedia/CDM.cpp:
+ (WebCore::CDM::CDM):
+ * platform/encryptedmedia/CDMFactory.h:
+ * platform/encryptedmedia/CDMInstance.h:
+ * platform/encryptedmedia/clearkey/CDMClearKey.cpp:
+ (WebCore::CDMFactoryClearKey::createCDM):
+ (WebCore::CDMInstanceClearKey::keySystem const):
+ * platform/encryptedmedia/clearkey/CDMClearKey.h:
+ * platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp:
+ (WebCore::MediaPlayerPrivateGStreamer::handleMessage):
+ * platform/graphics/gstreamer/MediaPlayerPrivateGStreamerBase.cpp:
+ (WebCore::MediaPlayerPrivateGStreamerBase::~MediaPlayerPrivateGStreamerBase):
+ (WebCore::extractEventsAndSystemsFromMessage):
+ (WebCore::MediaPlayerPrivateGStreamerBase::handleSyncMessage):
+ (WebCore::MediaPlayerPrivateGStreamerBase::cdmInstanceAttached):
+ (WebCore::MediaPlayerPrivateGStreamerBase::cdmInstanceDetached):
+ (WebCore::MediaPlayerPrivateGStreamerBase::attemptToDecryptWithInstance):
+ (WebCore::MediaPlayerPrivateGStreamerBase::attemptToDecryptWithLocalInstance):
+ (WebCore::MediaPlayerPrivateGStreamerBase::dispatchDecryptionKey):
+ (WebCore::MediaPlayerPrivateGStreamerBase::handleProtectionEvent):
+ * platform/graphics/gstreamer/MediaPlayerPrivateGStreamerBase.h:
+ * platform/graphics/gstreamer/mse/AppendPipeline.cpp:
+ (WebCore::appendPipelineElementMessageCallback):
+ (WebCore::AppendPipeline::AppendPipeline):
+ (WebCore::AppendPipeline::~AppendPipeline):
+ (WebCore::AppendPipeline::handleNeedContextSyncMessage):
+ (WebCore::AppendPipeline::handleElementMessage):
+ (WebCore::AppendPipeline::handleAppsrcNeedDataReceived):
+ (WebCore::AppendPipeline::appsinkNewSample):
+ * platform/graphics/gstreamer/mse/AppendPipeline.h:
+ * testing/MockCDMFactory.cpp:
+ (WebCore::MockCDMFactory::createCDM):
+ (WebCore::MockCDMInstance::keySystem const):
+ * testing/MockCDMFactory.h:
+
2017-08-26 Zan Dobersek <[email protected]>
[WebCrypto] Push WorkQueue dispatches for RSA algorithms into shared code
Modified: trunk/Source/WebCore/Modules/encryptedmedia/CDM.cpp (221223 => 221224)
--- trunk/Source/WebCore/Modules/encryptedmedia/CDM.cpp 2017-08-26 08:01:24 UTC (rev 221223)
+++ trunk/Source/WebCore/Modules/encryptedmedia/CDM.cpp 2017-08-26 08:29:00 UTC (rev 221224)
@@ -64,7 +64,7 @@
ASSERT(supportsKeySystem(keySystem));
for (auto* factory : CDMFactory::registeredFactories()) {
if (factory->supportsKeySystem(keySystem)) {
- m_private = factory->createCDM();
+ m_private = factory->createCDM(keySystem);
break;
}
}
Modified: trunk/Source/WebCore/platform/encryptedmedia/CDMFactory.h (221223 => 221224)
--- trunk/Source/WebCore/platform/encryptedmedia/CDMFactory.h 2017-08-26 08:01:24 UTC (rev 221223)
+++ trunk/Source/WebCore/platform/encryptedmedia/CDMFactory.h 2017-08-26 08:29:00 UTC (rev 221224)
@@ -40,7 +40,7 @@
class CDMFactory {
public:
virtual ~CDMFactory() { };
- virtual std::unique_ptr<CDMPrivate> createCDM() = 0;
+ virtual std::unique_ptr<CDMPrivate> createCDM(const String&) = 0;
virtual bool supportsKeySystem(const String&) = 0;
static Vector<CDMFactory*>& registeredFactories();
Modified: trunk/Source/WebCore/platform/encryptedmedia/CDMInstance.h (221223 => 221224)
--- trunk/Source/WebCore/platform/encryptedmedia/CDMInstance.h 2017-08-26 08:01:24 UTC (rev 221223)
+++ trunk/Source/WebCore/platform/encryptedmedia/CDMInstance.h 2017-08-26 08:29:00 UTC (rev 221224)
@@ -94,6 +94,8 @@
virtual void removeSessionData(const String& sessionId, LicenseType, RemoveSessionDataCallback) = 0;
virtual void storeRecordOfKeyUsage(const String& sessionId) = 0;
+
+ virtual const String& keySystem() const = 0;
};
} // namespace WebCore
Modified: trunk/Source/WebCore/platform/encryptedmedia/clearkey/CDMClearKey.cpp (221223 => 221224)
--- trunk/Source/WebCore/platform/encryptedmedia/clearkey/CDMClearKey.cpp 2017-08-26 08:01:24 UTC (rev 221223)
+++ trunk/Source/WebCore/platform/encryptedmedia/clearkey/CDMClearKey.cpp 2017-08-26 08:29:00 UTC (rev 221224)
@@ -47,8 +47,13 @@
CDMFactoryClearKey::CDMFactoryClearKey() = default;
CDMFactoryClearKey::~CDMFactoryClearKey() = default;
-std::unique_ptr<CDMPrivate> CDMFactoryClearKey::createCDM()
+std::unique_ptr<CDMPrivate> CDMFactoryClearKey::createCDM(const String& keySystem)
{
+#ifdef NDEBUG
+ UNUSED_PARAM(keySystem);
+#else
+ ASSERT(supportsKeySystem(keySystem));
+#endif
return std::unique_ptr<CDMPrivate>(new CDMPrivateClearKey);
}
@@ -208,6 +213,13 @@
{
}
+const String& CDMInstanceClearKey::keySystem() const
+{
+ static const String s_keySystem("org.w3.clearkey");
+
+ return s_keySystem;
+}
+
} // namespace WebCore
#endif // ENABLE(ENCRYPTED_MEDIA)
Modified: trunk/Source/WebCore/platform/encryptedmedia/clearkey/CDMClearKey.h (221223 => 221224)
--- trunk/Source/WebCore/platform/encryptedmedia/clearkey/CDMClearKey.h 2017-08-26 08:01:24 UTC (rev 221223)
+++ trunk/Source/WebCore/platform/encryptedmedia/clearkey/CDMClearKey.h 2017-08-26 08:29:00 UTC (rev 221224)
@@ -42,7 +42,7 @@
virtual ~CDMFactoryClearKey();
- std::unique_ptr<CDMPrivate> createCDM() override;
+ std::unique_ptr<CDMPrivate> createCDM(const String&) override;
bool supportsKeySystem(const String&) override;
private:
@@ -89,6 +89,8 @@
void closeSession(const String&, CloseSessionCallback) override;
void removeSessionData(const String&, LicenseType, RemoveSessionDataCallback) override;
void storeRecordOfKeyUsage(const String&) override;
+
+ const String& keySystem() const final;
};
} // namespace WebCore
Modified: trunk/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp (221223 => 221224)
--- trunk/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp 2017-08-26 08:01:24 UTC (rev 221223)
+++ trunk/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp 2017-08-26 08:29:00 UTC (rev 221224)
@@ -1050,6 +1050,14 @@
processMpegTsSection(section);
gst_mpegts_section_unref(section);
}
+#if ENABLE(ENCRYPTED_MEDIA)
+ else if (gst_structure_has_name(structure, "drm-key-needed")) {
+ GST_DEBUG("drm-key-needed message from %s", GST_MESSAGE_SRC_NAME(message));
+ GRefPtr<GstEvent> event;
+ gst_structure_get(structure, "event", GST_TYPE_EVENT, &event.outPtr(), nullptr);
+ handleProtectionEvent(event.get());
+ }
+#endif
}
#endif
break;
Modified: trunk/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamerBase.cpp (221223 => 221224)
--- trunk/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamerBase.cpp 2017-08-26 08:01:24 UTC (rev 221223)
+++ trunk/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamerBase.cpp 2017-08-26 08:29:00 UTC (rev 221224)
@@ -43,10 +43,18 @@
#include <wtf/text/AtomicString.h>
#include <wtf/text/CString.h>
#include <wtf/MathExtras.h>
+#include <wtf/UUID.h>
#include <gst/audio/streamvolume.h>
#include <gst/video/gstvideometa.h>
+#if ENABLE(ENCRYPTED_MEDIA)
+#include "CDMInstance.h"
+#include "GStreamerEMEUtilities.h"
+#include "SharedBuffer.h"
+#include "WebKitClearKeyDecryptorGStreamer.h"
+#endif
+
#if USE(GSTREAMER_GL)
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
#define GST_GL_CAPS_FORMAT "{ BGRx, BGRA }"
@@ -110,12 +118,6 @@
#endif
#endif // USE(TEXTURE_MAPPER_GL)
-#if ENABLE(ENCRYPTED_MEDIA)
-#include "GStreamerEMEUtilities.h"
-#include "SharedBuffer.h"
-#include "WebKitClearKeyDecryptorGStreamer.h"
-#endif
-
GST_DEBUG_CATEGORY(webkit_media_player_debug);
#define GST_CAT_DEFAULT webkit_media_player_debug
@@ -240,6 +242,9 @@
MediaPlayerPrivateGStreamerBase::~MediaPlayerPrivateGStreamerBase()
{
+#if ENABLE(ENCRYPTED_MEDIA)
+ m_protectionCondition.notifyAll();
+#endif
m_notifier->invalidate();
if (m_videoSink) {
@@ -273,6 +278,31 @@
m_pipeline = pipeline;
}
+#if ENABLE(ENCRYPTED_MEDIA)
+static std::pair<Vector<GRefPtr<GstEvent>>, Vector<String>> extractEventsAndSystemsFromMessage(GstMessage* message)
+{
+ const GstStructure* structure = gst_message_get_structure(message);
+
+ const GValue* streamEncryptionAllowedSystemsValue = gst_structure_get_value(structure, "stream-encryption-systems");
+ ASSERT(streamEncryptionAllowedSystemsValue && G_VALUE_HOLDS(streamEncryptionAllowedSystemsValue, G_TYPE_STRV));
+ const char** streamEncryptionAllowedSystems = reinterpret_cast<const char**>(g_value_get_boxed(streamEncryptionAllowedSystemsValue));
+ ASSERT(streamEncryptionAllowedSystems);
+ Vector<String> streamEncryptionAllowedSystemsVector;
+ unsigned i;
+ for (i = 0; streamEncryptionAllowedSystems[i]; ++i)
+ streamEncryptionAllowedSystemsVector.append(streamEncryptionAllowedSystems[i]);
+
+ const GValue* streamEncryptionEventsList = gst_structure_get_value(structure, "stream-encryption-events");
+ ASSERT(streamEncryptionEventsList && GST_VALUE_HOLDS_LIST(streamEncryptionEventsList));
+ unsigned streamEncryptionEventsListSize = gst_value_list_get_size(streamEncryptionEventsList);
+ Vector<GRefPtr<GstEvent>> streamEncryptionEventsVector;
+ for (i = 0; i < streamEncryptionEventsListSize; ++i)
+ streamEncryptionEventsVector.append(GRefPtr<GstEvent>(static_cast<GstEvent*>(g_value_get_boxed(gst_value_list_get_value(streamEncryptionEventsList, i)))));
+
+ return std::make_pair(streamEncryptionEventsVector, streamEncryptionAllowedSystemsVector);
+}
+#endif
+
bool MediaPlayerPrivateGStreamerBase::handleSyncMessage(GstMessage* message)
{
UNUSED_PARAM(message);
@@ -290,6 +320,78 @@
}
#endif // USE(GSTREAMER_GL)
+#if ENABLE(ENCRYPTED_MEDIA)
+ if (!g_strcmp0(contextType, "drm-preferred-decryption-system-id")) {
+ if (isMainThread()) {
+ GST_ERROR("can't handle drm-preferred-decryption-system-id need context message in the main thread");
+ ASSERT_NOT_REACHED();
+ return false;
+ }
+ GST_DEBUG("handling drm-preferred-decryption-system-id need context message");
+ LockHolder lock(m_protectionMutex);
+ std::pair<Vector<GRefPtr<GstEvent>>, Vector<String>> streamEncryptionInformation = extractEventsAndSystemsFromMessage(message);
+ GST_TRACE("found %" G_GSIZE_FORMAT " protection events", streamEncryptionInformation.first.size());
+ Vector<uint8_t> concatenatedInitDataChunks;
+ unsigned concatenatedInitDataChunksNumber = 0;
+ String eventKeySystemIdString;
+
+ for (auto& event : streamEncryptionInformation.first) {
+ GST_TRACE("handling protection event %u", GST_EVENT_SEQNUM(event.get()));
+ const char* eventKeySystemId = nullptr;
+ GstBuffer* data = ""
+ gst_event_parse_protection(event.get(), &eventKeySystemId, &data, nullptr);
+
+ GstMapInfo mapInfo;
+ if (!gst_buffer_map(data, &mapInfo, GST_MAP_READ)) {
+ GST_WARNING("cannot map %s protection data", eventKeySystemId);
+ break;
+ }
+ GST_TRACE("appending init data for %s of size %" G_GSIZE_FORMAT, eventKeySystemId, mapInfo.size);
+ GST_MEMDUMP("init data", reinterpret_cast<const unsigned char *>(mapInfo.data), mapInfo.size);
+ concatenatedInitDataChunks.append(mapInfo.data, mapInfo.size);
+ ++concatenatedInitDataChunksNumber;
+ eventKeySystemIdString = eventKeySystemId;
+ if (streamEncryptionInformation.second.contains(eventKeySystemId)) {
+ GST_TRACE("considering init data handled for %s", eventKeySystemId);
+ m_handledProtectionEvents.add(GST_EVENT_SEQNUM(event.get()));
+ }
+ gst_buffer_unmap(data, &mapInfo);
+ }
+
+ if (!concatenatedInitDataChunksNumber)
+ return false;
+
+ if (concatenatedInitDataChunksNumber > 1)
+ eventKeySystemIdString = emptyString();
+
+ String sessionId(createCanonicalUUIDString());
+
+ RunLoop::main().dispatch([this, eventKeySystemIdString, sessionId, initData = WTFMove(concatenatedInitDataChunks)] {
+ GST_DEBUG("scheduling initializationDataEncountered event for %s with concatenated init datas size of %" G_GSIZE_FORMAT, eventKeySystemIdString.utf8().data(), initData.size());
+ GST_MEMDUMP("init datas", initData.data(), initData.size());
+
+ m_player->initializationDataEncountered(ASCIILiteral("cenc"), ArrayBuffer::create(initData.data(), initData.size()));
+ });
+
+ GST_INFO("waiting for a CDM instance");
+ m_protectionCondition.waitFor(m_protectionMutex, Seconds(4), [this] {
+ return this->m_cdmInstance;
+ });
+ if (m_cdmInstance && !m_cdmInstance->keySystem().isEmpty()) {
+ const char* preferredKeySystemUuid = GStreamerEMEUtilities::keySystemToUuid(m_cdmInstance->keySystem());
+ GST_INFO("working with %s, continuing with %s on %s", m_cdmInstance->keySystem().utf8().data(), preferredKeySystemUuid, GST_MESSAGE_SRC_NAME(message));
+
+ GRefPtr<GstContext> context = adoptGRef(gst_context_new("drm-preferred-decryption-system-id", FALSE));
+ GstStructure* contextStructure = gst_context_writable_structure(context.get());
+ gst_structure_set(contextStructure, "decryption-system-id", G_TYPE_STRING, preferredKeySystemUuid, nullptr);
+ gst_element_set_context(GST_ELEMENT(GST_MESSAGE_SRC(message)), context.get());
+ } else
+ GST_WARNING("no proper CDM instance attached");
+
+ return true;
+ }
+#endif // ENABLE(ENCRYPTED_MEDIA)
+
return false;
}
@@ -1044,6 +1146,65 @@
return static_cast<unsigned>(position);
}
+#if ENABLE(ENCRYPTED_MEDIA)
+void MediaPlayerPrivateGStreamerBase::cdmInstanceAttached(const CDMInstance& instance)
+{
+ ASSERT(!m_cdmInstance);
+ m_cdmInstance = &instance;
+ GST_DEBUG("CDM instance %p set", m_cdmInstance.get());
+ m_protectionCondition.notifyAll();
+}
+
+void MediaPlayerPrivateGStreamerBase::cdmInstanceDetached(const CDMInstance& instance)
+{
+#ifdef NDEBUG
+ UNUSED_PARAM(instance);
+#endif
+ ASSERT(m_cdmInstance.get() == &instance);
+ GST_DEBUG("detaching CDM instance %p", m_cdmInstance.get());
+ m_cdmInstance = nullptr;
+ m_protectionCondition.notifyAll();
+}
+
+void MediaPlayerPrivateGStreamerBase::attemptToDecryptWithInstance(const CDMInstance& instance)
+{
+ ASSERT(m_cdmInstance.get() == &instance);
+ GST_TRACE("instance %p, current stored %p", &instance, m_cdmInstance.get());
+ attemptToDecryptWithLocalInstance();
+}
+
+void MediaPlayerPrivateGStreamerBase::attemptToDecryptWithLocalInstance()
+{
+ // FIXME.
+}
+
+void MediaPlayerPrivateGStreamerBase::dispatchDecryptionKey(GstBuffer* buffer)
+{
+ bool eventHandled = gst_element_send_event(m_pipeline.get(), gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM_OOB,
+ gst_structure_new("drm-cipher", "key", GST_TYPE_BUFFER, buffer, nullptr)));
+ m_needToResendCredentials = m_handledProtectionEvents.size() > 0;
+ GST_TRACE("emitted decryption cipher key on pipeline, event handled %s, need to resend credentials %s", boolForPrinting(eventHandled), boolForPrinting(m_needToResendCredentials));
+}
+
+void MediaPlayerPrivateGStreamerBase::handleProtectionEvent(GstEvent* event)
+{
+ if (m_handledProtectionEvents.contains(GST_EVENT_SEQNUM(event))) {
+ GST_DEBUG("event %u already handled", GST_EVENT_SEQNUM(event));
+ m_handledProtectionEvents.remove(GST_EVENT_SEQNUM(event));
+ if (m_needToResendCredentials) {
+ GST_DEBUG("resending credentials");
+ attemptToDecryptWithLocalInstance();
+ }
+ return;
+ }
+
+ const gchar* eventKeySystemId = nullptr;
+ gst_event_parse_protection(event, &eventKeySystemId, nullptr, nullptr);
+ GST_WARNING("FIXME: unhandled protection event for %s", eventKeySystemId);
+ ASSERT_NOT_REACHED();
+}
+#endif
+
bool MediaPlayerPrivateGStreamerBase::supportsKeySystem(const String& keySystem, const String& mimeType)
{
bool result = false;
Modified: trunk/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamerBase.h (221223 => 221224)
--- trunk/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamerBase.h 2017-08-26 08:01:24 UTC (rev 221223)
+++ trunk/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamerBase.h 2017-08-26 08:29:00 UTC (rev 221224)
@@ -120,6 +120,15 @@
#endif
#endif
+#if ENABLE(ENCRYPTED_MEDIA)
+ void cdmInstanceAttached(const CDMInstance&) override;
+ void cdmInstanceDetached(const CDMInstance&) override;
+ void dispatchDecryptionKey(GstBuffer*);
+ void handleProtectionEvent(GstEvent*);
+ void attemptToDecryptWithLocalInstance();
+ void attemptToDecryptWithInstance(const CDMInstance&) override;
+#endif
+
static bool supportsKeySystem(const String& keySystem, const String& mimeType);
static MediaPlayer::SupportsType extendedSupportsType(const MediaEngineSupportParameters&, MediaPlayer::SupportsType);
@@ -219,6 +228,14 @@
#endif
ImageOrientation m_videoSourceOrientation;
+
+#if ENABLE(ENCRYPTED_MEDIA)
+ Lock m_protectionMutex;
+ Condition m_protectionCondition;
+ RefPtr<const CDMInstance> m_cdmInstance;
+ HashSet<uint32_t> m_handledProtectionEvents;
+ bool m_needToResendCredentials { false };
+#endif
};
}
Modified: trunk/Source/WebCore/platform/graphics/gstreamer/mse/AppendPipeline.cpp (221223 => 221224)
--- trunk/Source/WebCore/platform/graphics/gstreamer/mse/AppendPipeline.cpp 2017-08-26 08:01:24 UTC (rev 221223)
+++ trunk/Source/WebCore/platform/graphics/gstreamer/mse/AppendPipeline.cpp 2017-08-26 08:29:00 UTC (rev 221224)
@@ -93,6 +93,13 @@
appendPipeline->handleApplicationMessage(message);
}
+#if ENABLE(ENCRYPTED_MEDIA)
+static void appendPipelineElementMessageCallback(GstBus*, GstMessage* message, AppendPipeline* appendPipeline)
+{
+ appendPipeline->handleElementMessage(message);
+}
+#endif
+
AppendPipeline::AppendPipeline(Ref<MediaSourceClientGStreamerMSE> mediaSourceClient, Ref<SourceBufferPrivateGStreamer> sourceBufferPrivate, MediaPlayerPrivateGStreamerMSE& playerPrivate)
: m_mediaSourceClient(mediaSourceClient.get())
, m_sourceBufferPrivate(sourceBufferPrivate.get())
@@ -119,6 +126,9 @@
g_signal_connect(m_bus.get(), "sync-message::need-context", G_CALLBACK(appendPipelineNeedContextMessageCallback), this);
g_signal_connect(m_bus.get(), "message::application", G_CALLBACK(appendPipelineApplicationMessageCallback), this);
+#if ENABLE(ENCRYPTED_MEDIA)
+ g_signal_connect(m_bus.get(), "message::element", G_CALLBACK(appendPipelineElementMessageCallback), this);
+#endif
// We assign the created instances here instead of adoptRef() because gst_bin_add_many()
// below will already take the initial reference and we need an additional one for us.
@@ -180,6 +190,8 @@
if (m_pipeline) {
ASSERT(m_bus);
+ g_signal_handlers_disconnect_by_func(m_bus.get(), reinterpret_cast<gpointer>(appendPipelineNeedContextMessageCallback), this);
+ gst_bus_disable_sync_message_emission(m_bus.get());
gst_bus_remove_signal_watch(m_bus.get());
gst_element_set_state(m_pipeline.get(), GST_STATE_NULL);
m_pipeline = nullptr;
@@ -249,7 +261,8 @@
const gchar* contextType = nullptr;
gst_message_parse_context_type(message, &contextType);
GST_TRACE("context type: %s", contextType);
- if (!g_strcmp0(contextType, "drm-preferred-decryption-system-id"))
+ if (!g_strcmp0(contextType, "drm-preferred-decryption-system-id")
+ && m_appendState != AppendPipeline::AppendState::KeyNegotiation)
setAppendState(AppendPipeline::AppendState::KeyNegotiation);
// MediaPlayerPrivateGStreamerBase will take care of setting up encryption.
@@ -302,6 +315,25 @@
ASSERT_NOT_REACHED();
}
+#if ENABLE(ENCRYPTED_MEDIA)
+void AppendPipeline::handleElementMessage(GstMessage* message)
+{
+ ASSERT(WTF::isMainThread());
+
+ const GstStructure* structure = gst_message_get_structure(message);
+ GST_TRACE("%s message from %s", gst_structure_get_name(structure), GST_MESSAGE_SRC_NAME(message));
+ if (m_playerPrivate && gst_structure_has_name(structure, "drm-key-needed")) {
+ if (m_appendState != AppendPipeline::AppendState::KeyNegotiation)
+ setAppendState(AppendPipeline::AppendState::KeyNegotiation);
+
+ GST_DEBUG("sending drm-key-needed message from %s to the player", GST_MESSAGE_SRC_NAME(message));
+ GRefPtr<GstEvent> event;
+ gst_structure_get(structure, "event", GST_TYPE_EVENT, &event.outPtr(), nullptr);
+ m_playerPrivate->handleProtectionEvent(event.get());
+ }
+}
+#endif
+
void AppendPipeline::handleAppsrcNeedDataReceived()
{
if (!m_appsrcAtLeastABufferLeft) {
@@ -309,7 +341,7 @@
return;
}
- ASSERT(m_appendState == AppendState::Ongoing || m_appendState == AppendState::Sampling);
+ ASSERT(m_appendState == AppendState::KeyNegotiation || m_appendState == AppendState::Ongoing || m_appendState == AppendState::Sampling);
ASSERT(!m_appsrcNeedDataReceived);
GST_TRACE("received need-data from appsrc");
@@ -647,6 +679,10 @@
{
LockHolder locker(m_newSampleLock);
+ // If we were in KeyNegotiation but samples are coming, assume we're already OnGoing
+ if (m_appendState == AppendState::KeyNegotiation)
+ setAppendState(AppendState::Ongoing);
+
// Ignore samples if we're not expecting them. Refuse processing if we're in Invalid state.
if (m_appendState != AppendState::Ongoing && m_appendState != AppendState::Sampling) {
GST_WARNING("Unexpected sample, appendState=%s", dumpAppendState(m_appendState));
Modified: trunk/Source/WebCore/platform/graphics/gstreamer/mse/AppendPipeline.h (221223 => 221224)
--- trunk/Source/WebCore/platform/graphics/gstreamer/mse/AppendPipeline.h 2017-08-26 08:01:24 UTC (rev 221223)
+++ trunk/Source/WebCore/platform/graphics/gstreamer/mse/AppendPipeline.h 2017-08-26 08:29:00 UTC (rev 221224)
@@ -50,6 +50,9 @@
void handleNeedContextSyncMessage(GstMessage*);
void handleApplicationMessage(GstMessage*);
+#if ENABLE(ENCRYPTED_MEDIA)
+ void handleElementMessage(GstMessage*);
+#endif
gint id();
AppendState appendState() { return m_appendState; }
Modified: trunk/Source/WebCore/testing/MockCDMFactory.cpp (221223 => 221224)
--- trunk/Source/WebCore/testing/MockCDMFactory.cpp 2017-08-26 08:01:24 UTC (rev 221223)
+++ trunk/Source/WebCore/testing/MockCDMFactory.cpp 2017-08-26 08:29:00 UTC (rev 221224)
@@ -96,7 +96,7 @@
m_supportedDataTypes.append(type);
}
-std::unique_ptr<CDMPrivate> MockCDMFactory::createCDM()
+std::unique_ptr<CDMPrivate> MockCDMFactory::createCDM(const String&)
{
return std::make_unique<MockCDM>(m_weakPtrFactory.createWeakPtr());
}
@@ -377,6 +377,13 @@
// FIXME: This should be implemented along with the support for persistent-usage-record sessions.
}
+const String& MockCDMInstance::keySystem() const
+{
+ static const String s_keySystem("org.webkit.mock");
+
+ return s_keySystem;
}
+}
+
#endif
Modified: trunk/Source/WebCore/testing/MockCDMFactory.h (221223 => 221224)
--- trunk/Source/WebCore/testing/MockCDMFactory.h 2017-08-26 08:01:24 UTC (rev 221223)
+++ trunk/Source/WebCore/testing/MockCDMFactory.h 2017-08-26 08:29:00 UTC (rev 221224)
@@ -78,7 +78,7 @@
private:
MockCDMFactory();
- std::unique_ptr<CDMPrivate> createCDM() final;
+ std::unique_ptr<CDMPrivate> createCDM(const String&) final;
bool supportsKeySystem(const String&) final;
MediaKeysRequirement m_distinctiveIdentifiersRequirement { MediaKeysRequirement::Optional };
@@ -140,6 +140,8 @@
void removeSessionData(const String&, LicenseType, RemoveSessionDataCallback) final;
void storeRecordOfKeyUsage(const String&) final;
+ const String& keySystem() const final;
+
WeakPtr<MockCDM> m_cdm;
bool m_distinctiveIdentifiersAllowed { true };
bool m_persistentStateAllowed { true };