[EME][GStreamer] The current EME implementation doesn't support the waitingforkey...
[WebKit-https.git] / Source / WebCore / platform / graphics / gstreamer / eme / WebKitCommonEncryptionDecryptorGStreamer.cpp
1 /* GStreamer ClearKey common encryption decryptor
2  *
3  * Copyright (C) 2013 YouView TV Ltd. <alex.ashley@youview.com>
4  * Copyright (C) 2016 Metrological
5  * Copyright (C) 2016 Igalia S.L
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public
18  * License along with this library; if not, write to the
19  * Free Software Foundation, Inc., 51 Franklin Street, Suite 500,
20  * Boston, MA 02110-1335, USA.
21  */
22
23 #include "config.h"
24 #include "WebKitCommonEncryptionDecryptorGStreamer.h"
25
26 #if ENABLE(ENCRYPTED_MEDIA) && USE(GSTREAMER)
27
28 #include "GStreamerCommon.h"
29 #include <wtf/Condition.h>
30 #include <wtf/RunLoop.h>
31
32 #define WEBKIT_MEDIA_CENC_DECRYPT_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), WEBKIT_TYPE_MEDIA_CENC_DECRYPT, WebKitMediaCommonEncryptionDecryptPrivate))
33 struct _WebKitMediaCommonEncryptionDecryptPrivate {
34     GRefPtr<GstEvent> protectionEvent;
35
36     bool keyReceived;
37     bool waitingForKey { false };
38     Lock mutex;
39     Condition condition;
40 };
41
42 static GstStateChangeReturn webKitMediaCommonEncryptionDecryptorChangeState(GstElement*, GstStateChange transition);
43 static void webKitMediaCommonEncryptionDecryptorFinalize(GObject*);
44 static GstCaps* webkitMediaCommonEncryptionDecryptTransformCaps(GstBaseTransform*, GstPadDirection, GstCaps*, GstCaps*);
45 static GstFlowReturn webkitMediaCommonEncryptionDecryptTransformInPlace(GstBaseTransform*, GstBuffer*);
46 static gboolean webkitMediaCommonEncryptionDecryptSinkEventHandler(GstBaseTransform*, GstEvent*);
47
48 static gboolean webKitMediaCommonEncryptionDecryptDefaultSetupCipher(WebKitMediaCommonEncryptionDecrypt*, GstBuffer*);
49 static void webKitMediaCommonEncryptionDecryptDefaultReleaseCipher(WebKitMediaCommonEncryptionDecrypt*);
50
51 GST_DEBUG_CATEGORY_STATIC(webkit_media_common_encryption_decrypt_debug_category);
52 #define GST_CAT_DEFAULT webkit_media_common_encryption_decrypt_debug_category
53
54 #define webkit_media_common_encryption_decrypt_parent_class parent_class
55 G_DEFINE_TYPE(WebKitMediaCommonEncryptionDecrypt, webkit_media_common_encryption_decrypt, GST_TYPE_BASE_TRANSFORM);
56
57 static void webkit_media_common_encryption_decrypt_class_init(WebKitMediaCommonEncryptionDecryptClass* klass)
58 {
59     GObjectClass* gobjectClass = G_OBJECT_CLASS(klass);
60     gobjectClass->finalize = webKitMediaCommonEncryptionDecryptorFinalize;
61
62     GST_DEBUG_CATEGORY_INIT(webkit_media_common_encryption_decrypt_debug_category,
63         "webkitcenc", 0, "Common Encryption base class");
64
65     GstElementClass* elementClass = GST_ELEMENT_CLASS(klass);
66     elementClass->change_state = GST_DEBUG_FUNCPTR(webKitMediaCommonEncryptionDecryptorChangeState);
67
68     GstBaseTransformClass* baseTransformClass = GST_BASE_TRANSFORM_CLASS(klass);
69     baseTransformClass->transform_ip = GST_DEBUG_FUNCPTR(webkitMediaCommonEncryptionDecryptTransformInPlace);
70     baseTransformClass->transform_caps = GST_DEBUG_FUNCPTR(webkitMediaCommonEncryptionDecryptTransformCaps);
71     baseTransformClass->transform_ip_on_passthrough = FALSE;
72     baseTransformClass->sink_event = GST_DEBUG_FUNCPTR(webkitMediaCommonEncryptionDecryptSinkEventHandler);
73
74     klass->setupCipher = GST_DEBUG_FUNCPTR(webKitMediaCommonEncryptionDecryptDefaultSetupCipher);
75     klass->releaseCipher = GST_DEBUG_FUNCPTR(webKitMediaCommonEncryptionDecryptDefaultReleaseCipher);
76
77     g_type_class_add_private(klass, sizeof(WebKitMediaCommonEncryptionDecryptPrivate));
78 }
79
80 static void webkit_media_common_encryption_decrypt_init(WebKitMediaCommonEncryptionDecrypt* self)
81 {
82     WebKitMediaCommonEncryptionDecryptPrivate* priv = WEBKIT_MEDIA_CENC_DECRYPT_GET_PRIVATE(self);
83
84     self->priv = priv;
85     new (priv) WebKitMediaCommonEncryptionDecryptPrivate();
86
87     GstBaseTransform* base = GST_BASE_TRANSFORM(self);
88     gst_base_transform_set_in_place(base, TRUE);
89     gst_base_transform_set_passthrough(base, FALSE);
90     gst_base_transform_set_gap_aware(base, FALSE);
91 }
92
93 static void webKitMediaCommonEncryptionDecryptorFinalize(GObject* object)
94 {
95     WebKitMediaCommonEncryptionDecrypt* self = WEBKIT_MEDIA_CENC_DECRYPT(object);
96     WebKitMediaCommonEncryptionDecryptPrivate* priv = self->priv;
97
98     priv->~WebKitMediaCommonEncryptionDecryptPrivate();
99     GST_CALL_PARENT(G_OBJECT_CLASS, finalize, (object));
100 }
101
102 static GstCaps* webkitMediaCommonEncryptionDecryptTransformCaps(GstBaseTransform* base, GstPadDirection direction, GstCaps* caps, GstCaps* filter)
103 {
104     if (direction == GST_PAD_UNKNOWN)
105         return nullptr;
106
107     GST_DEBUG_OBJECT(base, "direction: %s, caps: %" GST_PTR_FORMAT " filter: %" GST_PTR_FORMAT, (direction == GST_PAD_SRC) ? "src" : "sink", caps, filter);
108
109     GstCaps* transformedCaps = gst_caps_new_empty();
110     WebKitMediaCommonEncryptionDecrypt* self = WEBKIT_MEDIA_CENC_DECRYPT(base);
111     WebKitMediaCommonEncryptionDecryptClass* klass = WEBKIT_MEDIA_CENC_DECRYPT_GET_CLASS(self);
112
113     unsigned size = gst_caps_get_size(caps);
114     for (unsigned i = 0; i < size; ++i) {
115         GstStructure* incomingStructure = gst_caps_get_structure(caps, i);
116         GUniquePtr<GstStructure> outgoingStructure = nullptr;
117
118         if (direction == GST_PAD_SINK) {
119             if (!gst_structure_has_field(incomingStructure, "original-media-type"))
120                 continue;
121
122             outgoingStructure = GUniquePtr<GstStructure>(gst_structure_copy(incomingStructure));
123             gst_structure_set_name(outgoingStructure.get(), gst_structure_get_string(outgoingStructure.get(), "original-media-type"));
124
125             // Filter out the DRM related fields from the down-stream caps.
126             for (int j = 0; j < gst_structure_n_fields(incomingStructure); ++j) {
127                 const gchar* fieldName = gst_structure_nth_field_name(incomingStructure, j);
128
129                 if (g_str_has_prefix(fieldName, "protection-system")
130                     || g_str_has_prefix(fieldName, "original-media-type"))
131                     gst_structure_remove_field(outgoingStructure.get(), fieldName);
132             }
133         } else {
134             outgoingStructure = GUniquePtr<GstStructure>(gst_structure_copy(incomingStructure));
135             // Filter out the video related fields from the up-stream caps,
136             // because they are not relevant to the input caps of this element and
137             // can cause caps negotiation failures with adaptive bitrate streams.
138             for (int index = gst_structure_n_fields(outgoingStructure.get()) - 1; index >= 0; --index) {
139                 const gchar* fieldName = gst_structure_nth_field_name(outgoingStructure.get(), index);
140                 GST_TRACE("Check field \"%s\" for removal", fieldName);
141
142                 if (!g_strcmp0(fieldName, "base-profile")
143                     || !g_strcmp0(fieldName, "codec_data")
144                     || !g_strcmp0(fieldName, "height")
145                     || !g_strcmp0(fieldName, "framerate")
146                     || !g_strcmp0(fieldName, "level")
147                     || !g_strcmp0(fieldName, "pixel-aspect-ratio")
148                     || !g_strcmp0(fieldName, "profile")
149                     || !g_strcmp0(fieldName, "rate")
150                     || !g_strcmp0(fieldName, "width")) {
151                     gst_structure_remove_field(outgoingStructure.get(), fieldName);
152                     GST_TRACE("Removing field %s", fieldName);
153                 }
154             }
155
156             gst_structure_set(outgoingStructure.get(), "protection-system", G_TYPE_STRING, klass->protectionSystemId,
157                 "original-media-type", G_TYPE_STRING, gst_structure_get_name(incomingStructure), nullptr);
158
159             gst_structure_set_name(outgoingStructure.get(), "application/x-cenc");
160         }
161
162         bool duplicate = false;
163         unsigned size = gst_caps_get_size(transformedCaps);
164
165         for (unsigned index = 0; !duplicate && index < size; ++index) {
166             GstStructure* structure = gst_caps_get_structure(transformedCaps, index);
167             if (gst_structure_is_equal(structure, outgoingStructure.get()))
168                 duplicate = true;
169         }
170
171         if (!duplicate)
172             gst_caps_append_structure(transformedCaps, outgoingStructure.release());
173     }
174
175     if (filter) {
176         GstCaps* intersection;
177
178         GST_DEBUG_OBJECT(base, "Using filter caps %" GST_PTR_FORMAT, filter);
179         intersection = gst_caps_intersect_full(transformedCaps, filter, GST_CAPS_INTERSECT_FIRST);
180         gst_caps_unref(transformedCaps);
181         transformedCaps = intersection;
182     }
183
184     GST_DEBUG_OBJECT(base, "returning %" GST_PTR_FORMAT, transformedCaps);
185     return transformedCaps;
186 }
187
188 static GstFlowReturn webkitMediaCommonEncryptionDecryptTransformInPlace(GstBaseTransform* base, GstBuffer* buffer)
189 {
190     WebKitMediaCommonEncryptionDecrypt* self = WEBKIT_MEDIA_CENC_DECRYPT(base);
191     WebKitMediaCommonEncryptionDecryptPrivate* priv = WEBKIT_MEDIA_CENC_DECRYPT_GET_PRIVATE(self);
192     LockHolder locker(priv->mutex);
193
194     // The key might not have been received yet. Wait for it.
195     if (!priv->keyReceived) {
196         GST_DEBUG_OBJECT(self, "key not available yet, waiting for it");
197         if (GST_STATE(GST_ELEMENT(self)) < GST_STATE_PAUSED || (GST_STATE_TARGET(GST_ELEMENT(self)) != GST_STATE_VOID_PENDING && GST_STATE_TARGET(GST_ELEMENT(self)) < GST_STATE_PAUSED)) {
198             GST_ERROR_OBJECT(self, "can't process key requests in less than PAUSED state");
199             return GST_FLOW_NOT_SUPPORTED;
200         }
201         // Send "drm-cdm-instance-needed" message to the player to resend the CDMInstance if available and inform we are waiting for key.
202         gst_element_post_message(GST_ELEMENT(self), gst_message_new_element(GST_OBJECT(self), gst_structure_new_empty("drm-cdm-instance-needed")));
203         priv->waitingForKey = true;
204         gst_element_post_message(GST_ELEMENT(self), gst_message_new_element(GST_OBJECT(self), gst_structure_new_empty("drm-waiting-for-key")));
205
206         priv->condition.waitFor(priv->mutex, Seconds(5), [priv] {
207             return priv->keyReceived;
208         });
209         if (!priv->keyReceived) {
210             GST_ERROR_OBJECT(self, "key not available");
211             return GST_FLOW_NOT_SUPPORTED;
212         }
213         GST_DEBUG_OBJECT(self, "key received, continuing");
214     }
215
216     GstProtectionMeta* protectionMeta = reinterpret_cast<GstProtectionMeta*>(gst_buffer_get_protection_meta(buffer));
217     if (!protectionMeta) {
218         GST_ERROR_OBJECT(self, "Failed to get GstProtection metadata from buffer %p", buffer);
219         return GST_FLOW_NOT_SUPPORTED;
220     }
221
222     unsigned ivSize;
223     if (!gst_structure_get_uint(protectionMeta->info, "iv_size", &ivSize)) {
224         GST_ERROR_OBJECT(self, "Failed to get iv_size");
225         gst_buffer_remove_meta(buffer, reinterpret_cast<GstMeta*>(protectionMeta));
226         return GST_FLOW_NOT_SUPPORTED;
227     }
228
229     gboolean encrypted;
230     if (!gst_structure_get_boolean(protectionMeta->info, "encrypted", &encrypted)) {
231         GST_ERROR_OBJECT(self, "Failed to get encrypted flag");
232         gst_buffer_remove_meta(buffer, reinterpret_cast<GstMeta*>(protectionMeta));
233         return GST_FLOW_NOT_SUPPORTED;
234     }
235
236     if (!ivSize || !encrypted) {
237         gst_buffer_remove_meta(buffer, reinterpret_cast<GstMeta*>(protectionMeta));
238         return GST_FLOW_OK;
239     }
240
241     GST_DEBUG_OBJECT(base, "protection meta: %" GST_PTR_FORMAT, protectionMeta->info);
242
243     unsigned subSampleCount;
244     if (!gst_structure_get_uint(protectionMeta->info, "subsample_count", &subSampleCount)) {
245         GST_ERROR_OBJECT(self, "Failed to get subsample_count");
246         gst_buffer_remove_meta(buffer, reinterpret_cast<GstMeta*>(protectionMeta));
247         return GST_FLOW_NOT_SUPPORTED;
248     }
249
250     const GValue* value;
251     GstBuffer* subSamplesBuffer = nullptr;
252     if (subSampleCount) {
253         value = gst_structure_get_value(protectionMeta->info, "subsamples");
254         if (!value) {
255             GST_ERROR_OBJECT(self, "Failed to get subsamples");
256             gst_buffer_remove_meta(buffer, reinterpret_cast<GstMeta*>(protectionMeta));
257             return GST_FLOW_NOT_SUPPORTED;
258         }
259         subSamplesBuffer = gst_value_get_buffer(value);
260     }
261
262     value = gst_structure_get_value(protectionMeta->info, "kid");
263     GstBuffer* keyIDBuffer = nullptr;
264     if (value)
265         keyIDBuffer = gst_value_get_buffer(value);
266
267     WebKitMediaCommonEncryptionDecryptClass* klass = WEBKIT_MEDIA_CENC_DECRYPT_GET_CLASS(self);
268     if (!klass->setupCipher(self, keyIDBuffer)) {
269         GST_ERROR_OBJECT(self, "Failed to configure cipher");
270         gst_buffer_remove_meta(buffer, reinterpret_cast<GstMeta*>(protectionMeta));
271         return GST_FLOW_NOT_SUPPORTED;
272     }
273
274     value = gst_structure_get_value(protectionMeta->info, "iv");
275     if (!value) {
276         GST_ERROR_OBJECT(self, "Failed to get IV for sample");
277         klass->releaseCipher(self);
278         gst_buffer_remove_meta(buffer, reinterpret_cast<GstMeta*>(protectionMeta));
279         return GST_FLOW_NOT_SUPPORTED;
280     }
281
282     GstBuffer* ivBuffer = gst_value_get_buffer(value);
283     GST_TRACE_OBJECT(self, "decrypting");
284     if (!klass->decrypt(self, ivBuffer, buffer, subSampleCount, subSamplesBuffer)) {
285         GST_ERROR_OBJECT(self, "Decryption failed");
286         klass->releaseCipher(self);
287         gst_buffer_remove_meta(buffer, reinterpret_cast<GstMeta*>(protectionMeta));
288         return GST_FLOW_NOT_SUPPORTED;
289     }
290
291     klass->releaseCipher(self);
292     gst_buffer_remove_meta(buffer, reinterpret_cast<GstMeta*>(protectionMeta));
293     return GST_FLOW_OK;
294 }
295
296
297 static gboolean webkitMediaCommonEncryptionDecryptSinkEventHandler(GstBaseTransform* trans, GstEvent* event)
298 {
299     WebKitMediaCommonEncryptionDecrypt* self = WEBKIT_MEDIA_CENC_DECRYPT(trans);
300     WebKitMediaCommonEncryptionDecryptPrivate* priv = WEBKIT_MEDIA_CENC_DECRYPT_GET_PRIVATE(self);
301     WebKitMediaCommonEncryptionDecryptClass* klass = WEBKIT_MEDIA_CENC_DECRYPT_GET_CLASS(self);
302     gboolean result = FALSE;
303
304     switch (GST_EVENT_TYPE(event)) {
305     case GST_EVENT_CUSTOM_DOWNSTREAM_OOB: {
306         if (klass->handleKeyResponse(self, event)) {
307             GST_DEBUG_OBJECT(self, "key received");
308             priv->keyReceived = true;
309             priv->waitingForKey = false;
310             priv->condition.notifyOne();
311         } else if (priv->waitingForKey) {
312             GST_DEBUG_OBJECT(self, "still waiting for key, reposting");
313             gst_element_post_message(GST_ELEMENT(self), gst_message_new_element(GST_OBJECT(self), gst_structure_new_empty("drm-waiting-for-key")));
314         }
315
316         gst_event_unref(event);
317         result = TRUE;
318         break;
319     }
320     default:
321         result = GST_BASE_TRANSFORM_CLASS(parent_class)->sink_event(trans, event);
322         break;
323     }
324
325     return result;
326 }
327
328 static GstStateChangeReturn webKitMediaCommonEncryptionDecryptorChangeState(GstElement* element, GstStateChange transition)
329 {
330     WebKitMediaCommonEncryptionDecrypt* self = WEBKIT_MEDIA_CENC_DECRYPT(element);
331     WebKitMediaCommonEncryptionDecryptPrivate* priv = WEBKIT_MEDIA_CENC_DECRYPT_GET_PRIVATE(self);
332
333     switch (transition) {
334     case GST_STATE_CHANGE_PAUSED_TO_READY:
335         GST_DEBUG_OBJECT(self, "PAUSED->READY");
336         priv->condition.notifyOne();
337         break;
338     default:
339         break;
340     }
341
342     GstStateChangeReturn result = GST_ELEMENT_CLASS(parent_class)->change_state(element, transition);
343
344     // Add post-transition code here.
345
346     return result;
347 }
348
349
350 static gboolean webKitMediaCommonEncryptionDecryptDefaultSetupCipher(WebKitMediaCommonEncryptionDecrypt*, GstBuffer*)
351 {
352     return true;
353 }
354
355
356 static void webKitMediaCommonEncryptionDecryptDefaultReleaseCipher(WebKitMediaCommonEncryptionDecrypt*)
357 {
358 }
359
360 #endif // ENABLE(ENCRYPTED_MEDIA) && USE(GSTREAMER)