Changeset 238738 in webkit


Ignore:
Timestamp:
Nov 30, 2018 8:21:35 AM (5 years ago)
Author:
calvaris@igalia.com
Message:

[GStreamer][EME] CDMInstance should be shipped as a GstContext to the decryptors
https://bugs.webkit.org/show_bug.cgi?id=192075

Reviewed by Philippe Normand.

So far, we were shipping the CDMInstance in an event to the
decryptors and they were requesting it with bus messages when it
was not found. Now we ship it with a GstContext that is set to the
pipeline and read from the decryptors, which is now always
available.

As a consequence of changing this flow, the attemptToDecrypt one
was affected as well because it was tied to CDMInstance
shipment. A workaround was added: when the decryptors send the
waitingForKey, an attemptToDecrypt will be performed. A FIXME was
added for this. A subconsequence is that
attemptToDecryptWithInstance is reworked to rely always in
attemptToDecryptWithLocal instance, the former becomes final and
the latter virtual.

This is a rework, no new tests needed.

  • platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp:

(WebCore::MediaPlayerPrivateGStreamer::handleMessage):

  • platform/graphics/gstreamer/MediaPlayerPrivateGStreamerBase.cpp:

(WebCore::MediaPlayerPrivateGStreamerBase::cdmInstanceAttached):
(WebCore::MediaPlayerPrivateGStreamerBase::cdmInstanceDetached):
(WebCore::MediaPlayerPrivateGStreamerBase::attemptToDecryptWithLocalInstance):
(WebCore::MediaPlayerPrivateGStreamerBase::dispatchCDMInstance): Deleted.

  • platform/graphics/gstreamer/MediaPlayerPrivateGStreamerBase.h:
  • platform/graphics/gstreamer/eme/WebKitCommonEncryptionDecryptorGStreamer.cpp:

(webkit_media_common_encryption_decrypt_class_init):
(webkitMediaCommonEncryptionDecryptTransformInPlace):
(webkitMediaCommonEncryptionDecryptIsCDMInstanceAvailable):
(webkitMediaCommonEncryptionDecryptSinkEventHandler):
(webKitMediaCommonEncryptionDecryptorSetContext):

  • platform/graphics/gstreamer/mse/MediaPlayerPrivateGStreamerMSE.cpp:

(WebCore::MediaPlayerPrivateGStreamerMSE::attemptToDecryptWithLocalInstance):
(WebCore::MediaPlayerPrivateGStreamerMSE::attemptToDecryptWithInstance): Deleted.

  • platform/graphics/gstreamer/mse/MediaPlayerPrivateGStreamerMSE.h:
Location:
trunk/Source/WebCore
Files:
7 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r238737 r238738  
     12018-11-30  Xabier Rodriguez Calvar  <calvaris@igalia.com>
     2
     3        [GStreamer][EME] CDMInstance should be shipped as a GstContext to the decryptors
     4        https://bugs.webkit.org/show_bug.cgi?id=192075
     5
     6        Reviewed by Philippe Normand.
     7
     8        So far, we were shipping the CDMInstance in an event to the
     9        decryptors and they were requesting it with bus messages when it
     10        was not found. Now we ship it with a GstContext that is set to the
     11        pipeline and read from the decryptors, which is now always
     12        available.
     13
     14        As a consequence of changing this flow, the attemptToDecrypt one
     15        was affected as well because it was tied to CDMInstance
     16        shipment. A workaround was added: when the decryptors send the
     17        waitingForKey, an attemptToDecrypt will be performed. A FIXME was
     18        added for this. A subconsequence is that
     19        attemptToDecryptWithInstance is reworked to rely always in
     20        attemptToDecryptWithLocal instance, the former becomes final and
     21        the latter virtual.
     22
     23        This is a rework, no new tests needed.
     24
     25        * platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp:
     26        (WebCore::MediaPlayerPrivateGStreamer::handleMessage):
     27        * platform/graphics/gstreamer/MediaPlayerPrivateGStreamerBase.cpp:
     28        (WebCore::MediaPlayerPrivateGStreamerBase::cdmInstanceAttached):
     29        (WebCore::MediaPlayerPrivateGStreamerBase::cdmInstanceDetached):
     30        (WebCore::MediaPlayerPrivateGStreamerBase::attemptToDecryptWithLocalInstance):
     31        (WebCore::MediaPlayerPrivateGStreamerBase::dispatchCDMInstance): Deleted.
     32        * platform/graphics/gstreamer/MediaPlayerPrivateGStreamerBase.h:
     33        * platform/graphics/gstreamer/eme/WebKitCommonEncryptionDecryptorGStreamer.cpp:
     34        (webkit_media_common_encryption_decrypt_class_init):
     35        (webkitMediaCommonEncryptionDecryptTransformInPlace):
     36        (webkitMediaCommonEncryptionDecryptIsCDMInstanceAvailable):
     37        (webkitMediaCommonEncryptionDecryptSinkEventHandler):
     38        (webKitMediaCommonEncryptionDecryptorSetContext):
     39        * platform/graphics/gstreamer/mse/MediaPlayerPrivateGStreamerMSE.cpp:
     40        (WebCore::MediaPlayerPrivateGStreamerMSE::attemptToDecryptWithLocalInstance):
     41        (WebCore::MediaPlayerPrivateGStreamerMSE::attemptToDecryptWithInstance): Deleted.
     42        * platform/graphics/gstreamer/mse/MediaPlayerPrivateGStreamerMSE.h:
     43
    1442018-11-30  Zalan Bujtas  <zalan@apple.com>
    245
  • trunk/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp

    r238396 r238738  
    13301330            GST_DEBUG_OBJECT(pipeline(), "drm-waiting-for-key message from %s", GST_MESSAGE_SRC_NAME(message));
    13311331            setWaitingForKey(true);
     1332            // FIXME: The decryptors should be able to attempt to decrypt after being created and linked in a pipeline but currently they are not and current
     1333            // architecture does not make this very easy. Fortunately, the arch will change soon and it does not pay off to fix this now with something that could be
     1334            // more convoluted. In the meantime, force attempt to decrypt when they get blocked.
     1335            attemptToDecryptWithLocalInstance();
    13321336        } else if (gst_structure_has_name(structure, "drm-key-received")) {
    13331337            GST_DEBUG_OBJECT(pipeline(), "drm-key-received message from %s", GST_MESSAGE_SRC_NAME(message));
    13341338            setWaitingForKey(false);
    1335         } else if (gst_structure_has_name(structure, "drm-cdm-instance-needed")) {
    1336             GST_DEBUG_OBJECT(pipeline(), "drm-cdm-instance-needed message from %s", GST_MESSAGE_SRC_NAME(message));
    1337             dispatchCDMInstance();
    13381339        }
    13391340#endif
  • trunk/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamerBase.cpp

    r238282 r238738  
    11981198void MediaPlayerPrivateGStreamerBase::cdmInstanceAttached(CDMInstance& instance)
    11991199{
     1200    ASSERT(isMainThread());
     1201
     1202    if (m_cdmInstance == &instance)
     1203        return;
     1204
     1205    if (!m_pipeline) {
     1206        GST_ERROR("no pipeline yet");
     1207        ASSERT_NOT_REACHED();
     1208        return;
     1209    }
     1210
     1211    m_cdmInstance = &instance;
     1212
     1213    GRefPtr<GstContext> context = adoptGRef(gst_context_new("drm-cdm-instance", FALSE));
     1214    GstStructure* contextStructure = gst_context_writable_structure(context.get());
     1215    gst_structure_set(contextStructure, "cdm-instance", G_TYPE_POINTER, m_cdmInstance.get(), nullptr);
     1216    gst_element_set_context(GST_ELEMENT(m_pipeline.get()), context.get());
     1217
     1218    GST_DEBUG_OBJECT(m_pipeline.get(), "CDM instance %p dispatched as context", m_cdmInstance.get());
     1219
     1220    m_protectionCondition.notifyAll();
     1221}
     1222
     1223void MediaPlayerPrivateGStreamerBase::cdmInstanceDetached(CDMInstance& instance)
     1224{
     1225    ASSERT(isMainThread());
     1226
    12001227    if (m_cdmInstance != &instance) {
    1201         m_cdmInstance = &instance;
    1202         GST_DEBUG_OBJECT(pipeline(), "CDM instance %p set", m_cdmInstance.get());
    1203         m_protectionCondition.notifyAll();
    1204     }
    1205 }
    1206 
    1207 void MediaPlayerPrivateGStreamerBase::cdmInstanceDetached(CDMInstance& instance)
    1208 {
    1209 #ifdef NDEBUG
    1210     UNUSED_PARAM(instance);
    1211 #endif
    1212     if (m_cdmInstance == &instance) {
    1213         GST_DEBUG_OBJECT(pipeline(), "detaching CDM instance %p", m_cdmInstance.get());
    1214         m_cdmInstance = nullptr;
    1215         m_protectionCondition.notifyAll();
    1216     }
     1228        GST_WARNING("passed CDMInstance %p is different from stored one %p", &instance, m_cdmInstance.get());
     1229        ASSERT_NOT_REACHED();
     1230        return;
     1231    }
     1232
     1233    ASSERT(m_pipeline);
     1234
     1235    GST_DEBUG_OBJECT(m_pipeline.get(), "detaching CDM instance %p, setting empty context", m_cdmInstance.get());
     1236    m_cdmInstance = nullptr;
     1237
     1238    GRefPtr<GstContext> context = adoptGRef(gst_context_new("drm-cdm-instance", FALSE));
     1239    gst_element_set_context(GST_ELEMENT(m_pipeline.get()), context.get());
     1240
     1241    m_protectionCondition.notifyAll();
    12171242}
    12181243
     
    12261251void MediaPlayerPrivateGStreamerBase::attemptToDecryptWithLocalInstance()
    12271252{
    1228     bool eventHandled = gst_element_send_event(pipeline(), gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM_OOB,
    1229         gst_structure_new("attempt-to-decrypt", "cdm-instance", G_TYPE_POINTER, m_cdmInstance.get(), nullptr)));
     1253    bool eventHandled = gst_element_send_event(pipeline(), gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM_OOB, gst_structure_new_empty("attempt-to-decrypt")));
    12301254    GST_DEBUG("attempting to decrypt, event handled %s", boolForPrinting(eventHandled));
    12311255}
     
    12361260        gst_structure_new("drm-cipher", "key", GST_TYPE_BUFFER, buffer, nullptr)));
    12371261    GST_TRACE("emitted decryption cipher key on pipeline, event handled %s", boolForPrinting(eventHandled));
    1238 }
    1239 
    1240 void MediaPlayerPrivateGStreamerBase::dispatchCDMInstance()
    1241 {
    1242     // This function dispatches the CDMInstance in GStreamer playback pipeline.
    1243     if (m_cdmInstance)
    1244         m_player->attemptToDecryptWithInstance(const_cast<CDMInstance&>(*m_cdmInstance.get()));
    12451262}
    12461263
  • trunk/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamerBase.h

    r238131 r238738  
    151151    void dispatchDecryptionKey(GstBuffer*);
    152152    void handleProtectionEvent(GstEvent*);
    153     void attemptToDecryptWithLocalInstance();
    154     void attemptToDecryptWithInstance(CDMInstance&) override;
    155     void dispatchCDMInstance();
     153    virtual void attemptToDecryptWithLocalInstance();
     154    void attemptToDecryptWithInstance(CDMInstance&) final;
    156155    void initializationDataEncountered(InitData&&);
    157156    void setWaitingForKey(bool);
  • trunk/Source/WebCore/platform/graphics/gstreamer/eme/WebKitCommonEncryptionDecryptorGStreamer.cpp

    r238131 r238738  
    3232#include <wtf/RunLoop.h>
    3333
     34using WebCore::CDMInstance;
     35
    3436#define WEBKIT_MEDIA_CENC_DECRYPT_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), WEBKIT_TYPE_MEDIA_CENC_DECRYPT, WebKitMediaCommonEncryptionDecryptPrivate))
    3537struct _WebKitMediaCommonEncryptionDecryptPrivate {
    3638    GRefPtr<GstEvent> protectionEvent;
    37     RefPtr<WebCore::CDMInstance> cdmInstance;
     39    RefPtr<CDMInstance> cdmInstance;
    3840    bool keyReceived;
    3941    bool waitingForKey { false };
     
    4345
    4446static GstStateChangeReturn webKitMediaCommonEncryptionDecryptorChangeState(GstElement*, GstStateChange transition);
     47static void webKitMediaCommonEncryptionDecryptorSetContext(GstElement*, GstContext*);
    4548static void webKitMediaCommonEncryptionDecryptorFinalize(GObject*);
    4649static GstCaps* webkitMediaCommonEncryptionDecryptTransformCaps(GstBaseTransform*, GstPadDirection, GstCaps*, GstCaps*);
     
    4851static gboolean webkitMediaCommonEncryptionDecryptSinkEventHandler(GstBaseTransform*, GstEvent*);
    4952static gboolean webkitMediaCommonEncryptionDecryptorQueryHandler(GstBaseTransform*, GstPadDirection, GstQuery*);
    50 
     53static bool webkitMediaCommonEncryptionDecryptIsCDMInstanceAvailable(WebKitMediaCommonEncryptionDecrypt*);
    5154
    5255GST_DEBUG_CATEGORY_STATIC(webkit_media_common_encryption_decrypt_debug_category);
     
    6669    GstElementClass* elementClass = GST_ELEMENT_CLASS(klass);
    6770    elementClass->change_state = GST_DEBUG_FUNCPTR(webKitMediaCommonEncryptionDecryptorChangeState);
     71    elementClass->set_context = GST_DEBUG_FUNCPTR(webKitMediaCommonEncryptionDecryptorSetContext);
    6872
    6973    GstBaseTransformClass* baseTransformClass = GST_BASE_TRANSFORM_CLASS(klass);
     
    210214        priv->waitingForKey = true;
    211215        gst_element_post_message(GST_ELEMENT(self), gst_message_new_element(GST_OBJECT(self), gst_structure_new_empty("drm-waiting-for-key")));
    212         gst_element_post_message(GST_ELEMENT(self), gst_message_new_element(GST_OBJECT(self), gst_structure_new_empty("drm-cdm-instance-needed")));
    213216
    214217        priv->condition.waitFor(priv->mutex, Seconds(5), [priv] {
     
    300303}
    301304
     305static bool webkitMediaCommonEncryptionDecryptIsCDMInstanceAvailable(WebKitMediaCommonEncryptionDecrypt* self)
     306{
     307    WebKitMediaCommonEncryptionDecryptPrivate* priv = WEBKIT_MEDIA_CENC_DECRYPT_GET_PRIVATE(self);
     308
     309    ASSERT(priv->mutex.isLocked());
     310
     311    if (!priv->cdmInstance) {
     312        GRefPtr<GstContext> context = adoptGRef(gst_element_get_context(GST_ELEMENT(self), "drm-cdm-instance"));
     313        // According to the GStreamer documentation, if we can't find the context, we should run a downstream query, then an upstream one and then send a bus
     314        // message. In this case that does not make a lot of sense since only the app (player) answers it, meaning that no query is going to solve it. A message
     315        // could be helpful but the player sets the context as soon as it gets the CDMInstance and if it does not have it, we have no way of asking for one as it is
     316        // something provided by crossplatform code. This means that we won't be able to answer the bus request in any way either. Summing up, neither queries nor bus
     317        // requests are useful here.
     318        if (context) {
     319            const GValue* value = gst_structure_get_value(gst_context_get_structure(context.get()), "cdm-instance");
     320            priv->cdmInstance = value ? reinterpret_cast<CDMInstance*>(g_value_get_pointer(value)) : nullptr;
     321            if (priv->cdmInstance)
     322                GST_DEBUG_OBJECT(self, "received new CDMInstance %p", priv->cdmInstance.get());
     323            else
     324                GST_TRACE_OBJECT(self, "former instance was detached");
     325        }
     326    }
     327
     328    GST_TRACE_OBJECT(self, "CDMInstance available %s", boolForPrinting(priv->cdmInstance.get()));
     329    return priv->cdmInstance;
     330}
    302331
    303332static gboolean webkitMediaCommonEncryptionDecryptSinkEventHandler(GstBaseTransform* trans, GstEvent* event)
     
    307336    WebKitMediaCommonEncryptionDecryptClass* klass = WEBKIT_MEDIA_CENC_DECRYPT_GET_CLASS(self);
    308337    gboolean result = FALSE;
    309 
    310338
    311339    switch (GST_EVENT_TYPE(event)) {
     
    317345        // events will not be handled by the demuxer, so the must be
    318346        // handled in here.
    319         const GstStructure* structure = gst_event_get_structure(event);
    320         gst_structure_get(structure, "cdm-instance", G_TYPE_POINTER, &priv->cdmInstance, nullptr);
    321         if (!priv->cdmInstance) {
    322             GST_ERROR_OBJECT(self, "No CDM instance received");
     347        LockHolder locker(priv->mutex);
     348        if (!webkitMediaCommonEncryptionDecryptIsCDMInstanceAvailable(self)) {
     349            GST_ERROR_OBJECT(self, "No CDM instance available");
    323350            result = FALSE;
    324351            break;
    325352        }
    326         GST_DEBUG_OBJECT(self, "received a cdm instance %p", priv->cdmInstance.get());
    327353
    328354        if (klass->handleKeyResponse(self, event)) {
     
    375401}
    376402
     403static void webKitMediaCommonEncryptionDecryptorSetContext(GstElement* element, GstContext* context)
     404{
     405    WebKitMediaCommonEncryptionDecrypt* self = WEBKIT_MEDIA_CENC_DECRYPT(element);
     406    WebKitMediaCommonEncryptionDecryptPrivate* priv = WEBKIT_MEDIA_CENC_DECRYPT_GET_PRIVATE(self);
     407
     408    if (gst_context_has_context_type(context, "drm-cdm-instance")) {
     409        const GValue* value = gst_structure_get_value(gst_context_get_structure(context), "cdm-instance");
     410        LockHolder locker(priv->mutex);
     411        priv->cdmInstance = value ? reinterpret_cast<CDMInstance*>(g_value_get_pointer(value)) : nullptr;
     412        GST_DEBUG_OBJECT(self, "received new CDMInstance %p", priv->cdmInstance.get());
     413        return;
     414    }
     415
     416    GST_ELEMENT_CLASS(parent_class)->set_context(element, context);
     417}
     418
    377419#endif // ENABLE(ENCRYPTED_MEDIA) && USE(GSTREAMER)
  • trunk/Source/WebCore/platform/graphics/gstreamer/mse/MediaPlayerPrivateGStreamerMSE.cpp

    r238412 r238738  
    910910
    911911#if ENABLE(ENCRYPTED_MEDIA)
    912 void MediaPlayerPrivateGStreamerMSE::attemptToDecryptWithInstance(CDMInstance& instance)
    913 {
    914     if (is<CDMInstanceClearKey>(instance)) {
    915         auto& ckInstance = downcast<CDMInstanceClearKey>(instance);
    916         if (ckInstance.keys().isEmpty())
     912void MediaPlayerPrivateGStreamerMSE::attemptToDecryptWithLocalInstance()
     913{
     914    if (is<CDMInstanceClearKey>(*m_cdmInstance)) {
     915        auto& clearkeyCDMInstance = downcast<CDMInstanceClearKey>(*m_cdmInstance);
     916        if (clearkeyCDMInstance.keys().isEmpty())
    917917            return;
    918918
     
    931931            };
    932932
    933         for (auto& key : ckInstance.keys()) {
     933        for (auto& key : clearkeyCDMInstance.keys()) {
    934934            appendBuffer(&keyIDList, *key.keyIDData);
    935935            appendBuffer(&keyValueList, *key.keyValueData);
     
    939939        gst_structure_set_value(structure.get(), "key-ids", &keyIDList);
    940940        gst_structure_set_value(structure.get(), "key-values", &keyValueList);
    941         gst_structure_set(structure.get(), "cdm-instance", G_TYPE_POINTER, &instance, nullptr);
    942941
    943942        gst_element_send_event(m_playbackPipeline->pipeline(), gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM_OOB, structure.release()));
  • trunk/Source/WebCore/platform/graphics/gstreamer/mse/MediaPlayerPrivateGStreamerMSE.h

    r235598 r238738  
    8787
    8888#if ENABLE(ENCRYPTED_MEDIA)
    89     void attemptToDecryptWithInstance(CDMInstance&) final;
     89    void attemptToDecryptWithLocalInstance() final;
    9090#endif
    9191
Note: See TracChangeset for help on using the changeset viewer.