Changeset 231089 in webkit
- Timestamp:
- Apr 27, 2018 12:33:53 AM (6 years ago)
- Location:
- trunk/Source/WebCore
- Files:
-
- 6 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/WebCore/ChangeLog
r231088 r231089 1 2018-04-27 Yacine Bandou <yacine.bandou_ext@softathome.com> 2 3 [EME][GStreamer] Move the decryptor from AppendPipeline to PlaybackPipeline. 4 https://bugs.webkit.org/show_bug.cgi?id=181855 5 6 Reviewed by Xabier Rodriguez-Calvar. 7 8 The goal of this move is to handle the limitation of SVP (Secure Video Path) memory size. 9 10 When the decryptor is in the AppendPipeline and we use SVP, we buffer in MediaSource queue 11 the decrypted GstBuffers that are in SVP memory. 12 This behavior cause an out-of-memory error, because we are limited in SVP memory size. 13 14 By moving the decryptor in PlaybackPipeline, we avoid to buffer the decrypted GstBuffers 15 which use the SVP memory and we buffer the encrypted GstBuffers that are in system memory. 16 17 This new architecture also allows to start the buffering before obtaining the DRM license 18 and it makes easier to manage dynamic change of the license or Key. 19 20 The decryptor is auto plugged by GStreamer playbin in PlaybackPipeline. 21 22 SVP: Secure Video Path also named trusted or protected video path, it is a memory which is 23 protected by a hardware access control engine, it is not accessible to other unauthorised 24 software or hardware components. 25 26 Tests: 27 media/encrypted-media/clearKey/clearKey-cenc-audio-playback-mse.html 28 media/encrypted-media/clearKey/clearKey-cenc-video-playback-mse.html 29 30 * platform/graphics/gstreamer/eme/WebKitCommonEncryptionDecryptorGStreamer.cpp: 31 (webkitMediaCommonEncryptionDecryptSinkEventHandler): 32 * platform/graphics/gstreamer/mse/AppendPipeline.cpp: 33 (WebCore::dumpAppendState): 34 (WebCore::AppendPipeline::AppendPipeline): 35 (WebCore::AppendPipeline::handleNeedContextSyncMessage): 36 (WebCore::AppendPipeline::handleAppsrcNeedDataReceived): 37 (WebCore::AppendPipeline::setAppendState): 38 (WebCore::AppendPipeline::parseDemuxerSrcPadCaps): 39 (WebCore::AppendPipeline::appsinkNewSample): 40 (WebCore::AppendPipeline::connectDemuxerSrcPadToAppsinkFromAnyThread): 41 (WebCore::AppendPipeline::disconnectDemuxerSrcPadFromAppsinkFromAnyThread): 42 (WebCore::appendPipelineElementMessageCallback): Deleted. 43 (WebCore::AppendPipeline::handleElementMessage): Deleted. 44 (WebCore::AppendPipeline::dispatchPendingDecryptionStructure): Deleted. 45 (WebCore::AppendPipeline::dispatchDecryptionStructure): Deleted. 46 * platform/graphics/gstreamer/mse/AppendPipeline.h: 47 * platform/graphics/gstreamer/mse/MediaPlayerPrivateGStreamerMSE.cpp: 48 (WebCore::MediaPlayerPrivateGStreamerMSE::attemptToDecryptWithInstance): 49 * platform/graphics/gstreamer/mse/PlaybackPipeline.cpp: 50 1 51 2018-04-27 Yacine Bandou <yacine.bandou_ext@softathome.com> 2 52 -
trunk/Source/WebCore/platform/graphics/gstreamer/eme/WebKitCommonEncryptionDecryptorGStreamer.cpp
r231088 r231089 300 300 301 301 switch (GST_EVENT_TYPE(event)) { 302 case GST_EVENT_PROTECTION: {303 const char* systemId = nullptr;304 305 gst_event_parse_protection(event, &systemId, nullptr, nullptr);306 GST_TRACE_OBJECT(self, "received protection event for %s", systemId);307 308 if (!g_strcmp0(systemId, klass->protectionSystemId)) {309 GST_DEBUG_OBJECT(self, "sending protection event to the pipeline");310 gst_element_post_message(GST_ELEMENT(self),311 gst_message_new_element(GST_OBJECT(self),312 gst_structure_new("drm-key-needed", "event", GST_TYPE_EVENT, event, nullptr)));313 }314 315 gst_event_unref(event);316 result = TRUE;317 break;318 }319 302 case GST_EVENT_CUSTOM_DOWNSTREAM_OOB: { 320 303 if (klass->handleKeyResponse(self, event)) { -
trunk/Source/WebCore/platform/graphics/gstreamer/mse/AppendPipeline.cpp
r230625 r231089 56 56 case AppendPipeline::AppendState::Ongoing: 57 57 return "Ongoing"; 58 case AppendPipeline::AppendState::KeyNegotiation:59 return "KeyNegotiation";60 58 case AppendPipeline::AppendState::DataStarve: 61 59 return "DataStarve"; … … 94 92 } 95 93 96 #if ENABLE(ENCRYPTED_MEDIA)97 static void appendPipelineElementMessageCallback(GstBus*, GstMessage* message, AppendPipeline* appendPipeline)98 {99 appendPipeline->handleElementMessage(message);100 }101 #endif102 103 94 static void appendPipelineStateChangeMessageCallback(GstBus*, GstMessage* message, AppendPipeline* appendPipeline) 104 95 { … … 132 123 g_signal_connect(m_bus.get(), "sync-message::need-context", G_CALLBACK(appendPipelineNeedContextMessageCallback), this); 133 124 g_signal_connect(m_bus.get(), "message::application", G_CALLBACK(appendPipelineApplicationMessageCallback), this); 134 #if ENABLE(ENCRYPTED_MEDIA)135 g_signal_connect(m_bus.get(), "message::element", G_CALLBACK(appendPipelineElementMessageCallback), this);136 #endif137 125 g_signal_connect(m_bus.get(), "message::state-changed", G_CALLBACK(appendPipelineStateChangeMessageCallback), this); 138 126 … … 276 264 gst_message_parse_context_type(message, &contextType); 277 265 GST_TRACE("context type: %s", contextType); 278 if (!g_strcmp0(contextType, "drm-preferred-decryption-system-id")279 && m_appendState != AppendPipeline::AppendState::KeyNegotiation)280 setAppendState(AppendPipeline::AppendState::KeyNegotiation);281 266 282 267 // MediaPlayerPrivateGStreamerBase will take care of setting up encryption. … … 329 314 ASSERT_NOT_REACHED(); 330 315 } 331 332 #if ENABLE(ENCRYPTED_MEDIA)333 void AppendPipeline::handleElementMessage(GstMessage* message)334 {335 ASSERT(WTF::isMainThread());336 337 const GstStructure* structure = gst_message_get_structure(message);338 GST_TRACE("%s message from %s", gst_structure_get_name(structure), GST_MESSAGE_SRC_NAME(message));339 if (m_playerPrivate && gst_structure_has_name(structure, "drm-key-needed")) {340 if (m_appendState != AppendPipeline::AppendState::KeyNegotiation)341 setAppendState(AppendPipeline::AppendState::KeyNegotiation);342 343 GST_DEBUG("sending drm-key-needed message from %s to the player", GST_MESSAGE_SRC_NAME(message));344 GRefPtr<GstEvent> event;345 gst_structure_get(structure, "event", GST_TYPE_EVENT, &event.outPtr(), nullptr);346 m_playerPrivate->handleProtectionEvent(event.get());347 }348 }349 #endif350 316 351 317 void AppendPipeline::handleStateChangeMessage(GstMessage* message) … … 374 340 } 375 341 376 ASSERT(m_appendState == AppendState:: KeyNegotiation || m_appendState == AppendState::Ongoing || m_appendState == AppendState::Sampling);342 ASSERT(m_appendState == AppendState::Ongoing || m_appendState == AppendState::Sampling); 377 343 ASSERT(!m_appsrcNeedDataReceived); 378 344 … … 432 398 // | | `->Aborting-->NotStarted 433 399 // | `->Sampling-···->Sampling-->LastSample-->NotStarted 434 // | | `->Aborting-->NotStarted 435 // | `->KeyNegotiation-->Ongoing-->[...] 400 // | `->Aborting-->NotStarted 436 401 // `->Aborting-->NotStarted 437 402 AppendState oldAppendState = m_appendState; … … 469 434 } 470 435 break; 471 case AppendState::KeyNegotiation:472 switch (newAppendState) {473 case AppendState::Ongoing:474 case AppendState::Invalid:475 ok = true;476 break;477 default:478 break;479 }480 break;481 436 case AppendState::Ongoing: 482 437 switch (newAppendState) { 483 case AppendState::KeyNegotiation:484 438 case AppendState::Sampling: 485 439 case AppendState::Invalid: … … 583 537 m_demuxerSrcPadCaps = adoptGRef(demuxerSrcPadCaps); 584 538 m_streamType = WebCore::MediaSourceStreamTypeGStreamer::Unknown; 585 #if ENABLE(ENCRYPTED_MEDIA) 586 if (areEncryptedCaps(m_demuxerSrcPadCaps.get())) { 587 // Any previous decryptor should have been removed from the pipeline by disconnectFromAppSinkFromStreamingThread() 588 ASSERT(!m_decryptor); 589 GstStructure* structure = gst_caps_get_structure(m_demuxerSrcPadCaps.get(), 0); 590 m_decryptor = GStreamerEMEUtilities::createDecryptor(gst_structure_get_string(structure, "protection-system")); 591 if (!m_decryptor) { 592 GST_ERROR("decryptor not found for caps: %" GST_PTR_FORMAT, m_demuxerSrcPadCaps.get()); 593 return; 594 } 595 } 596 #endif 539 597 540 const char* originalMediaType = capsMediaType(m_demuxerSrcPadCaps.get()); 598 541 if (!MediaPlayerPrivateGStreamerMSE::supportsCodec(originalMediaType)) { … … 674 617 LockHolder locker(m_newSampleLock); 675 618 676 // If we were in KeyNegotiation but samples are coming, assume we're already OnGoing677 if (m_appendState == AppendState::KeyNegotiation)678 setAppendState(AppendState::Ongoing);679 680 619 // Ignore samples if we're not expecting them. Refuse processing if we're in Invalid state. 681 620 if (m_appendState != AppendState::Ongoing && m_appendState != AppendState::Sampling) { … … 1010 949 } 1011 950 1012 #if ENABLE(ENCRYPTED_MEDIA)1013 if (m_decryptor) {1014 gst_object_ref(m_decryptor.get());1015 gst_bin_add(GST_BIN(m_pipeline.get()), m_decryptor.get());1016 gst_element_sync_state_with_parent(m_decryptor.get());1017 1018 GRefPtr<GstPad> decryptorSinkPad = adoptGRef(gst_element_get_static_pad(m_decryptor.get(), "sink"));1019 GRefPtr<GstPad> decryptorSrcPad = adoptGRef(gst_element_get_static_pad(m_decryptor.get(), "src"));1020 1021 gst_pad_link(currentSrcPad.get(), decryptorSinkPad.get());1022 currentSrcPad = decryptorSrcPad;1023 }1024 #endif1025 1026 951 gst_pad_link(currentSrcPad.get(), appsinkSinkPad.get()); 1027 952 1028 953 gst_element_sync_state_with_parent(m_appsink.get()); 1029 954 1030 #if ENABLE(ENCRYPTED_MEDIA)1031 if (m_pendingDecryptionStructure)1032 dispatchPendingDecryptionStructure();1033 #endif1034 955 gst_element_set_state(m_pipeline.get(), GST_STATE_PAUSED); 1035 956 gst_element_sync_state_with_parent(m_appsink.get()); … … 1110 1031 GST_DEBUG("Disconnecting appsink"); 1111 1032 1112 #if ENABLE(ENCRYPTED_MEDIA)1113 if (m_decryptor) {1114 gst_element_set_state(m_decryptor.get(), GST_STATE_NULL);1115 gst_bin_remove(GST_BIN(m_pipeline.get()), m_decryptor.get());1116 m_decryptor = nullptr;1117 }1118 #endif1119 1120 1033 if (m_parser) { 1121 1034 gst_element_set_state(m_parser.get(), GST_STATE_NULL); … … 1126 1039 GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS(GST_BIN(m_pipeline.get()), GST_DEBUG_GRAPH_SHOW_ALL, "pad-removed-after"); 1127 1040 } 1128 1129 #if ENABLE(ENCRYPTED_MEDIA)1130 void AppendPipeline::dispatchPendingDecryptionStructure()1131 {1132 ASSERT(m_decryptor);1133 ASSERT(m_pendingDecryptionStructure);1134 ASSERT(m_appendState == AppendState::KeyNegotiation);1135 GST_TRACE("dispatching key to append pipeline %p", this);1136 1137 // Release the m_pendingDecryptionStructure object since1138 // gst_event_new_custom() takes over ownership of it.1139 gst_element_send_event(m_pipeline.get(), gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM_OOB, m_pendingDecryptionStructure.release()));1140 1141 setAppendState(AppendState::Ongoing);1142 }1143 1144 void AppendPipeline::dispatchDecryptionStructure(GUniquePtr<GstStructure>&& structure)1145 {1146 if (m_appendState == AppendState::KeyNegotiation) {1147 GST_TRACE("append pipeline %p in key negotiation", this);1148 m_pendingDecryptionStructure = WTFMove(structure);1149 if (m_decryptor)1150 dispatchPendingDecryptionStructure();1151 else1152 GST_TRACE("no decryptor yet, waiting for it");1153 } else1154 GST_TRACE("append pipeline %p not in key negotiation", this);1155 }1156 #endif1157 1041 1158 1042 static void appendPipelineAppsinkCapsChanged(GObject* appsinkPad, GParamSpec*, AppendPipeline* appendPipeline) -
trunk/Source/WebCore/platform/graphics/gstreamer/mse/AppendPipeline.h
r230625 r231089 43 43 class AppendPipeline : public ThreadSafeRefCounted<AppendPipeline> { 44 44 public: 45 enum class AppendState { Invalid, NotStarted, Ongoing, KeyNegotiation,DataStarve, Sampling, LastSample, Aborting };45 enum class AppendState { Invalid, NotStarted, Ongoing, DataStarve, Sampling, LastSample, Aborting }; 46 46 47 47 AppendPipeline(Ref<MediaSourceClientGStreamerMSE>, Ref<SourceBufferPrivateGStreamer>, MediaPlayerPrivateGStreamerMSE&); … … 51 51 void handleApplicationMessage(GstMessage*); 52 52 void handleStateChangeMessage(GstMessage*); 53 #if ENABLE(ENCRYPTED_MEDIA)54 void handleElementMessage(GstMessage*);55 #endif56 53 57 54 gint id(); … … 61 58 GstFlowReturn handleNewAppsinkSample(GstElement*); 62 59 GstFlowReturn pushNewBuffer(GstBuffer*); 63 #if ENABLE(ENCRYPTED_MEDIA)64 void dispatchDecryptionStructure(GUniquePtr<GstStructure>&&);65 #endif66 60 67 61 // Takes ownership of caps. … … 99 93 void removeAppsrcDataLeavingProbe(); 100 94 void setAppsrcDataLeavingProbe(); 101 #if ENABLE(ENCRYPTED_MEDIA)102 void dispatchPendingDecryptionStructure();103 #endif104 95 105 96 Ref<MediaSourceClientGStreamerMSE> m_mediaSourceClient; … … 119 110 GRefPtr<GstElement> m_demux; 120 111 GRefPtr<GstElement> m_parser; // Optional. 121 #if ENABLE(ENCRYPTED_MEDIA)122 GRefPtr<GstElement> m_decryptor;123 #endif124 112 // The demuxer has one src stream only, so only one appsink is needed and linked to it. 125 113 GRefPtr<GstElement> m_appsink; … … 156 144 157 145 GRefPtr<GstBuffer> m_pendingBuffer; 158 #if ENABLE(ENCRYPTED_MEDIA)159 GUniquePtr<GstStructure> m_pendingDecryptionStructure;160 #endif161 146 }; 162 147 -
trunk/Source/WebCore/platform/graphics/gstreamer/mse/MediaPlayerPrivateGStreamerMSE.cpp
r230625 r231089 956 956 gst_structure_set_value(structure.get(), "key-values", &keyValueList); 957 957 958 for (auto it : m_appendPipelinesMap) 959 it.value->dispatchDecryptionStructure(GUniquePtr<GstStructure>(gst_structure_copy(structure.get()))); 958 gst_element_send_event(m_playbackPipeline->pipeline(), gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM_OOB, gst_structure_copy(structure.get()))); 960 959 } 961 960 } -
trunk/Source/WebCore/platform/graphics/gstreamer/mse/PlaybackPipeline.cpp
r230909 r231089 181 181 GUniquePtr<gchar> parserBinName(g_strdup_printf("streamparser%u", padId)); 182 182 183 if (!g_strcmp0(mediaType, "video/x-h264")) { 183 if (areEncryptedCaps(caps)) { 184 GST_DEBUG("It's encrypted content, parsers are not needed before decrypting the content"); 185 } else if (!g_strcmp0(mediaType, "video/x-h264")) { 184 186 GRefPtr<GstCaps> filterCaps = adoptGRef(gst_caps_new_simple("video/x-h264", "alignment", G_TYPE_STRING, "au", nullptr)); 185 187 GstElement* capsfilter = gst_element_factory_make("capsfilter", nullptr);
Note: See TracChangeset
for help on using the changeset viewer.