Unreviewed, rolling out r231089.
https://bugs.webkit.org/show_bug.cgi?id=185071
Broke and made crash some WPE EME tests (Requested by calvaris
on #webkit).
Reverted changeset:
"[EME][GStreamer] Move the decryptor from AppendPipeline to
PlaybackPipeline."
https://bugs.webkit.org/show_bug.cgi?id=181855
https://trac.webkit.org/changeset/231089
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@231091 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog
index 624d5ac..cf702c9 100644
--- a/Source/WebCore/ChangeLog
+++ b/Source/WebCore/ChangeLog
@@ -1,3 +1,18 @@
+2018-04-27 Commit Queue <commit-queue@webkit.org>
+
+ Unreviewed, rolling out r231089.
+ https://bugs.webkit.org/show_bug.cgi?id=185071
+
+ Broke and made crash some WPE EME tests (Requested by calvaris
+ on #webkit).
+
+ Reverted changeset:
+
+ "[EME][GStreamer] Move the decryptor from AppendPipeline to
+ PlaybackPipeline."
+ https://bugs.webkit.org/show_bug.cgi?id=181855
+ https://trac.webkit.org/changeset/231089
+
2018-04-27 Yacine Bandou <yacine.bandou_ext@softathome.com>
[EME][GStreamer] Move the decryptor from AppendPipeline to PlaybackPipeline.
diff --git a/Source/WebCore/platform/graphics/gstreamer/eme/WebKitCommonEncryptionDecryptorGStreamer.cpp b/Source/WebCore/platform/graphics/gstreamer/eme/WebKitCommonEncryptionDecryptorGStreamer.cpp
index 8d1b84e..33a330a 100644
--- a/Source/WebCore/platform/graphics/gstreamer/eme/WebKitCommonEncryptionDecryptorGStreamer.cpp
+++ b/Source/WebCore/platform/graphics/gstreamer/eme/WebKitCommonEncryptionDecryptorGStreamer.cpp
@@ -299,6 +299,23 @@
gboolean result = FALSE;
switch (GST_EVENT_TYPE(event)) {
+ case GST_EVENT_PROTECTION: {
+ const char* systemId = nullptr;
+
+ gst_event_parse_protection(event, &systemId, nullptr, nullptr);
+ GST_TRACE_OBJECT(self, "received protection event for %s", systemId);
+
+ 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)));
+ }
+
+ gst_event_unref(event);
+ result = TRUE;
+ break;
+ }
case GST_EVENT_CUSTOM_DOWNSTREAM_OOB: {
if (klass->handleKeyResponse(self, event)) {
GST_DEBUG_OBJECT(self, "key received");
diff --git a/Source/WebCore/platform/graphics/gstreamer/mse/AppendPipeline.cpp b/Source/WebCore/platform/graphics/gstreamer/mse/AppendPipeline.cpp
index 691f0c8..c2508c7 100644
--- a/Source/WebCore/platform/graphics/gstreamer/mse/AppendPipeline.cpp
+++ b/Source/WebCore/platform/graphics/gstreamer/mse/AppendPipeline.cpp
@@ -55,6 +55,8 @@
return "NotStarted";
case AppendPipeline::AppendState::Ongoing:
return "Ongoing";
+ case AppendPipeline::AppendState::KeyNegotiation:
+ return "KeyNegotiation";
case AppendPipeline::AppendState::DataStarve:
return "DataStarve";
case AppendPipeline::AppendState::Sampling:
@@ -91,6 +93,13 @@
appendPipeline->handleApplicationMessage(message);
}
+#if ENABLE(ENCRYPTED_MEDIA)
+static void appendPipelineElementMessageCallback(GstBus*, GstMessage* message, AppendPipeline* appendPipeline)
+{
+ appendPipeline->handleElementMessage(message);
+}
+#endif
+
static void appendPipelineStateChangeMessageCallback(GstBus*, GstMessage* message, AppendPipeline* appendPipeline)
{
appendPipeline->handleStateChangeMessage(message);
@@ -122,6 +131,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
g_signal_connect(m_bus.get(), "message::state-changed", G_CALLBACK(appendPipelineStateChangeMessageCallback), this);
// We assign the created instances here instead of adoptRef() because gst_bin_add_many()
@@ -263,6 +275,9 @@
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")
+ && m_appendState != AppendPipeline::AppendState::KeyNegotiation)
+ setAppendState(AppendPipeline::AppendState::KeyNegotiation);
// MediaPlayerPrivateGStreamerBase will take care of setting up encryption.
if (m_playerPrivate)
@@ -314,6 +329,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::handleStateChangeMessage(GstMessage* message)
{
ASSERT(WTF::isMainThread());
@@ -339,7 +373,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");
@@ -397,7 +431,8 @@
// NotStarted-->Ongoing-->DataStarve-->NotStarted
// | | `->Aborting-->NotStarted
// | `->Sampling-···->Sampling-->LastSample-->NotStarted
- // | `->Aborting-->NotStarted
+ // | | `->Aborting-->NotStarted
+ // | `->KeyNegotiation-->Ongoing-->[...]
// `->Aborting-->NotStarted
AppendState oldAppendState = m_appendState;
AppendState nextAppendState = AppendState::Invalid;
@@ -433,8 +468,19 @@
break;
}
break;
+ case AppendState::KeyNegotiation:
+ switch (newAppendState) {
+ case AppendState::Ongoing:
+ case AppendState::Invalid:
+ ok = true;
+ break;
+ default:
+ break;
+ }
+ break;
case AppendState::Ongoing:
switch (newAppendState) {
+ case AppendState::KeyNegotiation:
case AppendState::Sampling:
case AppendState::Invalid:
ok = true;
@@ -536,7 +582,18 @@
m_demuxerSrcPadCaps = adoptGRef(demuxerSrcPadCaps);
m_streamType = WebCore::MediaSourceStreamTypeGStreamer::Unknown;
-
+#if ENABLE(ENCRYPTED_MEDIA)
+ if (areEncryptedCaps(m_demuxerSrcPadCaps.get())) {
+ // Any previous decryptor should have been removed from the pipeline by disconnectFromAppSinkFromStreamingThread()
+ ASSERT(!m_decryptor);
+ GstStructure* structure = gst_caps_get_structure(m_demuxerSrcPadCaps.get(), 0);
+ m_decryptor = GStreamerEMEUtilities::createDecryptor(gst_structure_get_string(structure, "protection-system"));
+ if (!m_decryptor) {
+ GST_ERROR("decryptor not found for caps: %" GST_PTR_FORMAT, m_demuxerSrcPadCaps.get());
+ return;
+ }
+ }
+#endif
const char* originalMediaType = capsMediaType(m_demuxerSrcPadCaps.get());
if (!MediaPlayerPrivateGStreamerMSE::supportsCodec(originalMediaType)) {
m_presentationSize = WebCore::FloatSize();
@@ -616,6 +673,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));
@@ -948,10 +1009,28 @@
currentSrcPad = parserSrcPad;
}
+#if ENABLE(ENCRYPTED_MEDIA)
+ if (m_decryptor) {
+ gst_object_ref(m_decryptor.get());
+ gst_bin_add(GST_BIN(m_pipeline.get()), m_decryptor.get());
+ gst_element_sync_state_with_parent(m_decryptor.get());
+
+ GRefPtr<GstPad> decryptorSinkPad = adoptGRef(gst_element_get_static_pad(m_decryptor.get(), "sink"));
+ GRefPtr<GstPad> decryptorSrcPad = adoptGRef(gst_element_get_static_pad(m_decryptor.get(), "src"));
+
+ gst_pad_link(currentSrcPad.get(), decryptorSinkPad.get());
+ currentSrcPad = decryptorSrcPad;
+ }
+#endif
+
gst_pad_link(currentSrcPad.get(), appsinkSinkPad.get());
gst_element_sync_state_with_parent(m_appsink.get());
+#if ENABLE(ENCRYPTED_MEDIA)
+ if (m_pendingDecryptionStructure)
+ dispatchPendingDecryptionStructure();
+#endif
gst_element_set_state(m_pipeline.get(), GST_STATE_PAUSED);
gst_element_sync_state_with_parent(m_appsink.get());
@@ -1030,6 +1109,14 @@
GST_DEBUG("Disconnecting appsink");
+#if ENABLE(ENCRYPTED_MEDIA)
+ if (m_decryptor) {
+ gst_element_set_state(m_decryptor.get(), GST_STATE_NULL);
+ gst_bin_remove(GST_BIN(m_pipeline.get()), m_decryptor.get());
+ m_decryptor = nullptr;
+ }
+#endif
+
if (m_parser) {
gst_element_set_state(m_parser.get(), GST_STATE_NULL);
gst_bin_remove(GST_BIN(m_pipeline.get()), m_parser.get());
@@ -1039,6 +1126,35 @@
GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS(GST_BIN(m_pipeline.get()), GST_DEBUG_GRAPH_SHOW_ALL, "pad-removed-after");
}
+#if ENABLE(ENCRYPTED_MEDIA)
+void AppendPipeline::dispatchPendingDecryptionStructure()
+{
+ ASSERT(m_decryptor);
+ ASSERT(m_pendingDecryptionStructure);
+ ASSERT(m_appendState == AppendState::KeyNegotiation);
+ GST_TRACE("dispatching key to append pipeline %p", this);
+
+ // Release the m_pendingDecryptionStructure object since
+ // gst_event_new_custom() takes over ownership of it.
+ gst_element_send_event(m_pipeline.get(), gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM_OOB, m_pendingDecryptionStructure.release()));
+
+ setAppendState(AppendState::Ongoing);
+}
+
+void AppendPipeline::dispatchDecryptionStructure(GUniquePtr<GstStructure>&& structure)
+{
+ if (m_appendState == AppendState::KeyNegotiation) {
+ GST_TRACE("append pipeline %p in key negotiation", this);
+ m_pendingDecryptionStructure = WTFMove(structure);
+ if (m_decryptor)
+ dispatchPendingDecryptionStructure();
+ else
+ GST_TRACE("no decryptor yet, waiting for it");
+ } else
+ GST_TRACE("append pipeline %p not in key negotiation", this);
+}
+#endif
+
static void appendPipelineAppsinkCapsChanged(GObject* appsinkPad, GParamSpec*, AppendPipeline* appendPipeline)
{
GstStructure* structure = gst_structure_new_empty("appsink-caps-changed");
diff --git a/Source/WebCore/platform/graphics/gstreamer/mse/AppendPipeline.h b/Source/WebCore/platform/graphics/gstreamer/mse/AppendPipeline.h
index 995c129..8330466 100644
--- a/Source/WebCore/platform/graphics/gstreamer/mse/AppendPipeline.h
+++ b/Source/WebCore/platform/graphics/gstreamer/mse/AppendPipeline.h
@@ -42,7 +42,7 @@
class AppendPipeline : public ThreadSafeRefCounted<AppendPipeline> {
public:
- enum class AppendState { Invalid, NotStarted, Ongoing, DataStarve, Sampling, LastSample, Aborting };
+ enum class AppendState { Invalid, NotStarted, Ongoing, KeyNegotiation, DataStarve, Sampling, LastSample, Aborting };
AppendPipeline(Ref<MediaSourceClientGStreamerMSE>, Ref<SourceBufferPrivateGStreamer>, MediaPlayerPrivateGStreamerMSE&);
virtual ~AppendPipeline();
@@ -50,6 +50,9 @@
void handleNeedContextSyncMessage(GstMessage*);
void handleApplicationMessage(GstMessage*);
void handleStateChangeMessage(GstMessage*);
+#if ENABLE(ENCRYPTED_MEDIA)
+ void handleElementMessage(GstMessage*);
+#endif
gint id();
AppendState appendState() { return m_appendState; }
@@ -57,6 +60,9 @@
GstFlowReturn handleNewAppsinkSample(GstElement*);
GstFlowReturn pushNewBuffer(GstBuffer*);
+#if ENABLE(ENCRYPTED_MEDIA)
+ void dispatchDecryptionStructure(GUniquePtr<GstStructure>&&);
+#endif
// Takes ownership of caps.
void parseDemuxerSrcPadCaps(GstCaps*);
@@ -92,6 +98,9 @@
void handleAppsrcNeedDataReceived();
void removeAppsrcDataLeavingProbe();
void setAppsrcDataLeavingProbe();
+#if ENABLE(ENCRYPTED_MEDIA)
+ void dispatchPendingDecryptionStructure();
+#endif
Ref<MediaSourceClientGStreamerMSE> m_mediaSourceClient;
Ref<SourceBufferPrivateGStreamer> m_sourceBufferPrivate;
@@ -109,6 +118,9 @@
GRefPtr<GstElement> m_appsrc;
GRefPtr<GstElement> m_demux;
GRefPtr<GstElement> m_parser; // Optional.
+#if ENABLE(ENCRYPTED_MEDIA)
+ GRefPtr<GstElement> m_decryptor;
+#endif
// The demuxer has one src stream only, so only one appsink is needed and linked to it.
GRefPtr<GstElement> m_appsink;
@@ -143,6 +155,9 @@
RefPtr<WebCore::TrackPrivateBase> m_track;
GRefPtr<GstBuffer> m_pendingBuffer;
+#if ENABLE(ENCRYPTED_MEDIA)
+ GUniquePtr<GstStructure> m_pendingDecryptionStructure;
+#endif
};
} // namespace WebCore.
diff --git a/Source/WebCore/platform/graphics/gstreamer/mse/MediaPlayerPrivateGStreamerMSE.cpp b/Source/WebCore/platform/graphics/gstreamer/mse/MediaPlayerPrivateGStreamerMSE.cpp
index 0436325..a30811f 100644
--- a/Source/WebCore/platform/graphics/gstreamer/mse/MediaPlayerPrivateGStreamerMSE.cpp
+++ b/Source/WebCore/platform/graphics/gstreamer/mse/MediaPlayerPrivateGStreamerMSE.cpp
@@ -955,7 +955,8 @@
gst_structure_set_value(structure.get(), "key-ids", &keyIDList);
gst_structure_set_value(structure.get(), "key-values", &keyValueList);
- gst_element_send_event(m_playbackPipeline->pipeline(), gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM_OOB, gst_structure_copy(structure.get())));
+ for (auto it : m_appendPipelinesMap)
+ it.value->dispatchDecryptionStructure(GUniquePtr<GstStructure>(gst_structure_copy(structure.get())));
}
}
#endif
diff --git a/Source/WebCore/platform/graphics/gstreamer/mse/PlaybackPipeline.cpp b/Source/WebCore/platform/graphics/gstreamer/mse/PlaybackPipeline.cpp
index 2b69971..06d5862 100644
--- a/Source/WebCore/platform/graphics/gstreamer/mse/PlaybackPipeline.cpp
+++ b/Source/WebCore/platform/graphics/gstreamer/mse/PlaybackPipeline.cpp
@@ -180,9 +180,7 @@
GUniquePtr<gchar> parserBinName(g_strdup_printf("streamparser%u", padId));
- if (areEncryptedCaps(caps)) {
- GST_DEBUG("It's encrypted content, parsers are not needed before decrypting the content");
- } else if (!g_strcmp0(mediaType, "video/x-h264")) {
+ if (!g_strcmp0(mediaType, "video/x-h264")) {
GRefPtr<GstCaps> filterCaps = adoptGRef(gst_caps_new_simple("video/x-h264", "alignment", G_TYPE_STRING, "au", nullptr));
GstElement* capsfilter = gst_element_factory_make("capsfilter", nullptr);
g_object_set(capsfilter, "caps", filterCaps.get(), nullptr);