1 /*
2 * Copyright (c) 2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #ifdef HAVE_CONFIG_H
17 #include "config.h"
18 #endif
19
20 #include <string.h>
21
22 #include <glib.h>
23 #include <gst/gst.h>
24 #include <gst/gstprotection.h>
25 #include <gst/gstelement.h>
26 #include <gst/base/gstbasetransform.h>
27 #include <gst/base/gstbytereader.h>
28
29 #include "gstdrmdec.h"
30
31 GST_DEBUG_CATEGORY_STATIC (gst_drm_decrypt_category);
32 #define GST_CAT_DEFAULT gst_drm_decrypt_category
33
34 #define KID_LENGTH 16
35 #define KEY_LENGTH 16
36 #define DRM_IV_SIZE 16
37 #define DRM_MAX_SUB_SAMPLE_NUM 64
38 #define DRM_TS_SUB_SAMPLE_NUM (2)
39 #define DRM_TS_FLAG_CRYPT_BYTE_BLOCK (2)
40 #define DRM_CRYPT_BYTE_BLOCK (1 + 2) // 2: DRM_TS_FLAG_CRYPT_BYTE_BLOCK
41 #define DRM_SKIP_BYTE_BLOCK (9)
42
43 typedef struct _DRM_SubSample DRM_SubSample;
44
45 enum
46 {
47 SIGNAL_ON_MEDIA_DECRYPT,
48 NUM_SIGNALS
49 };
50
51 typedef enum {
52 DRM_ALG_CENC_UNENCRYPTED = 0x0,
53 DRM_ALG_CENC_AES_CTR = 0x1,
54 DRM_ALG_CENC_AES_CBC,
55 DRM_ALG_CENC_SM4_CBC = 0x4,
56 DRM_ALG_CENC_SM4_CTR,
57 } DRM_CencAlgorithm;
58
59 typedef enum
60 {
61 GST_DRM_CLEARPLAY,
62 GST_DRM_CDRM,
63 GST_DRM_UNKNOWN = -1
64 } GstDrmType;
65
66 struct _GstDrmDecrypt
67 {
68 GstBaseTransform parent;
69 GstDrmType drm_type;
70 gboolean is_audio;
71 };
72
73 struct _GstDrmDecryptClass
74 {
75 GstBaseTransformClass parent_class;
76 };
77
78 struct _DRM_SubSample
79 {
80 guint clear_header_len;
81 guint pay_load_len;
82 };
83
84 static guint signals[NUM_SIGNALS];
85
86 /* prototypes */
87 static void gst_drm_decrypt_dispose (GObject *object);
88 static void gst_drm_decrypt_finalize (GObject *object);
89
90 static gboolean gst_drm_decrypt_start (GstBaseTransform *trans);
91 static gboolean gst_drm_decrypt_stop (GstBaseTransform *trans);
92 static gboolean gst_drm_decrypt_append_if_not_duplicate (GstCaps *dest, GstStructure *new_struct);
93 static GstCaps *gst_drm_decrypt_transform_caps (GstBaseTransform *base,
94 GstPadDirection direction, GstCaps *caps, GstCaps *filter);
95
96 static GstFlowReturn gst_drm_decrypt_transform_ip (GstBaseTransform *trans,
97 GstBuffer *buf);
98
99 static gboolean gst_drm_decrypt_sink_event_handler (GstBaseTransform *trans,
100 GstEvent *event);
101
102 #define CLEARPLAY_PROTECTION_ID "e2719d58-a985-b3c9-781a-b030af78d30e"
103 #define CDRM_PROTECTION_ID "3d5e6d35-9b9a-41e8-b843-dd3c6e72c42c"
104
105 /* pad templates */
106 static GstStaticPadTemplate gst_drm_decrypt_sink_template =
107 GST_STATIC_PAD_TEMPLATE ("sink",
108 GST_PAD_SINK,
109 GST_PAD_ALWAYS,
110 GST_STATIC_CAPS
111 (
112 "application/x-cenc, protection-system=(string)" CLEARPLAY_PROTECTION_ID "; "
113 "application/x-cenc, protection-system=(string)" CDRM_PROTECTION_ID)
114 );
115
116 static GstStaticPadTemplate gst_drm_decrypt_src_template =
117 GST_STATIC_PAD_TEMPLATE ("src",
118 GST_PAD_SRC,
119 GST_PAD_ALWAYS,
120 GST_STATIC_CAPS_ANY
121 );
122
123
124 static const gchar* gst_drm_decrypt_protection_ids[] = {
125 CLEARPLAY_PROTECTION_ID,
126 CDRM_PROTECTION_ID,
127 NULL
128 };
129
130 /* class initialization */
131 #define gst_drm_decrypt_parent_class parent_class
132 G_DEFINE_TYPE (GstDrmDecrypt, gst_drm_decrypt, GST_TYPE_BASE_TRANSFORM);
133
134 static void
gst_drm_decrypt_class_init(GstDrmDecryptClass * klass)135 gst_drm_decrypt_class_init (GstDrmDecryptClass *klass)
136 {
137 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
138 GstBaseTransformClass *base_transform_class =
139 GST_BASE_TRANSFORM_CLASS (klass);
140 GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
141 gst_element_class_add_pad_template (element_class,
142 gst_static_pad_template_get (&gst_drm_decrypt_sink_template));
143 gst_element_class_add_pad_template (element_class,
144 gst_static_pad_template_get (&gst_drm_decrypt_src_template));
145
146 gst_element_class_set_static_metadata (element_class,
147 "Decrypt content encrypted using ISOBMFF Common Encryption",
148 GST_ELEMENT_FACTORY_KLASS_DECRYPTOR,
149 "Decrypts media that has been encrypted using ISOBMFF Common Encryption.",
150 "drm");
151
152 GST_DEBUG_CATEGORY_INIT (gst_drm_decrypt_category,
153 "drmdec", 0, "DRM decryptor");
154
155 gobject_class->dispose = gst_drm_decrypt_dispose;
156 gobject_class->finalize = gst_drm_decrypt_finalize;
157 base_transform_class->start = GST_DEBUG_FUNCPTR (gst_drm_decrypt_start);
158 base_transform_class->stop = GST_DEBUG_FUNCPTR (gst_drm_decrypt_stop);
159 base_transform_class->transform_ip =
160 GST_DEBUG_FUNCPTR (gst_drm_decrypt_transform_ip);
161 base_transform_class->transform_caps =
162 GST_DEBUG_FUNCPTR (gst_drm_decrypt_transform_caps);
163 base_transform_class->sink_event =
164 GST_DEBUG_FUNCPTR (gst_drm_decrypt_sink_event_handler);
165 base_transform_class->transform_ip_on_passthrough = FALSE;
166
167 signals[SIGNAL_ON_MEDIA_DECRYPT] =
168 g_signal_new ("media-decrypt", G_TYPE_FROM_CLASS(klass),
169 G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
170 0, NULL, NULL, NULL,
171 G_TYPE_INT, 13, G_TYPE_INT64, G_TYPE_INT64, G_TYPE_UINT, G_TYPE_POINTER, G_TYPE_UINT, // 13:parameter nums
172 G_TYPE_POINTER, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_POINTER, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_UINT);
173 }
174
175 static void
gst_drm_decrypt_init(GstDrmDecrypt * self)176 gst_drm_decrypt_init (GstDrmDecrypt *self)
177 {
178 GstBaseTransform *base = GST_BASE_TRANSFORM (self);
179
180 GST_PAD_SET_ACCEPT_TEMPLATE (GST_BASE_TRANSFORM_SINK_PAD (self));
181
182 gst_base_transform_set_in_place (base, TRUE);
183 gst_base_transform_set_passthrough (base, FALSE);
184 gst_base_transform_set_gap_aware (GST_BASE_TRANSFORM (self), FALSE);
185 self->drm_type = GST_DRM_UNKNOWN;
186 self->is_audio = FALSE;
187 }
188
189 void
gst_drm_decrypt_dispose(GObject * object)190 gst_drm_decrypt_dispose (GObject *object)
191 {
192 GstDrmDecrypt *self = GST_DRM_DECRYPT (object);
193
194 self->is_audio = FALSE;
195 G_OBJECT_CLASS (parent_class)->dispose (object);
196 }
197
198 void
gst_drm_decrypt_finalize(GObject * object)199 gst_drm_decrypt_finalize (GObject *object)
200 {
201 /* clean up object here */
202 G_OBJECT_CLASS (parent_class)->finalize (object);
203 }
204
205 static gboolean
gst_drm_decrypt_start(GstBaseTransform * trans)206 gst_drm_decrypt_start (GstBaseTransform *trans)
207 {
208 GstDrmDecrypt *self = GST_DRM_DECRYPT (trans);
209 GST_DEBUG_OBJECT (self, "start");
210
211 return TRUE;
212 }
213
214 static gboolean
gst_drm_decrypt_stop(GstBaseTransform * trans)215 gst_drm_decrypt_stop (GstBaseTransform *trans)
216 {
217 GstDrmDecrypt *self = GST_DRM_DECRYPT (trans);
218 GST_DEBUG_OBJECT (self, "stop");
219
220 return TRUE;
221 }
222
223 /*
224 * Append new_structure to dest, but only if it does not already exist in res.
225 * This function takes ownership of new_structure.
226 */
227 static gboolean
gst_drm_decrypt_append_if_not_duplicate(GstCaps * dest,GstStructure * new_struct)228 gst_drm_decrypt_append_if_not_duplicate (GstCaps *dest, GstStructure *new_struct)
229 {
230 gboolean duplicate = FALSE;
231 gint i;
232
233 for (i = 0; (!duplicate) && (i < gst_caps_get_size (dest)); ++i) {
234 GstStructure *s = gst_caps_get_structure (dest, i);
235 if (gst_structure_is_equal (s, new_struct)) {
236 duplicate=TRUE;
237 }
238 }
239 if (!duplicate) {
240 gst_caps_append_structure (dest, new_struct);
241 } else {
242 gst_structure_free (new_struct);
243 }
244 return duplicate;
245 }
246
247 /* filter out the audio and video related fields from the up-stream caps,
248 * because they are not relevant to the input caps of this element and
249 * can cause caps negotiation failures with adaptive bitrate streams
250 */
251 static void
gst_drm_remove_codec_fields(GstStructure * gs)252 gst_drm_remove_codec_fields (GstStructure *gs)
253 {
254 gint i;
255 gint n_fields = gst_structure_n_fields (gs);
256 for (i = n_fields - 1; i >= 0; --i) {
257 const gchar *name;
258
259 name = gst_structure_nth_field_name (gs, i);
260 GST_TRACE ("Check field \"%s\"", name);
261
262 if (g_strcmp0 (name, "height") == 0 ||
263 g_strcmp0 (name, "width") == 0 ||
264 g_strcmp0 (name, "rate") == 0 ||
265 g_strcmp0 (name, "framerate") == 0 ||
266 g_strcmp0 (name, "pixel-aspect-ratio") == 0 ||
267 g_strcmp0 (name, "level") == 0 ||
268 g_strcmp0 (name, "codec_data") == 0 ||
269 g_strcmp0 (name, "base-profile") == 0 ||
270 g_strcmp0 (name, "profile") == 0) {
271 gst_structure_remove_field (gs, name);
272 }
273 }
274 }
275
276 static gboolean
gst_drm_decrypt_transform_sink_caps(GstBaseTransform * base,GstCaps * res,GstStructure * in,GstStructure * out)277 gst_drm_decrypt_transform_sink_caps (GstBaseTransform *base, GstCaps *res, GstStructure *in, GstStructure *out)
278 {
279 gint n_fields;
280 gint i;
281 GstDrmDecrypt *self = GST_DRM_DECRYPT (base);
282
283 if (!gst_structure_has_field (in, "original-media-type")) {
284 return FALSE;
285 }
286
287 out = gst_structure_copy (in);
288 n_fields = gst_structure_n_fields (in);
289
290 gst_structure_set_name (out,
291 gst_structure_get_string (out, "original-media-type"));
292
293 const gchar *media_type;
294 if ((media_type = gst_structure_get_string (in, "original-media-type"))) {
295 if (g_str_has_prefix (media_type, "audio")) {
296 self->is_audio = TRUE;
297 }
298 if (g_str_has_prefix (media_type, "video")) {
299 self->is_audio = FALSE;
300 }
301 }
302
303 /* filter out the DRM related fields from the down-stream caps */
304 for (i = n_fields - 1; i >= 0; --i) {
305 const gchar *field_name;
306
307 field_name = gst_structure_nth_field_name (in, i);
308 if (g_str_has_prefix(field_name, "protection-system") ||
309 g_str_has_prefix(field_name, "original-media-type")) {
310 gst_structure_remove_field (out, field_name);
311 }
312 }
313 gst_drm_decrypt_append_if_not_duplicate (res, out);
314 return TRUE;
315 }
316
317 static gboolean
gst_drm_decrypt_transform_src_caps(GstBaseTransform * base,GstCaps * res,GstStructure * in,GstStructure * out)318 gst_drm_decrypt_transform_src_caps (GstBaseTransform *base, GstCaps *res, GstStructure *in, GstStructure *out)
319 {
320 GstStructure *tmp = NULL;
321 guint i;
322 (void)base;
323 tmp = gst_structure_copy (in);
324 gst_drm_remove_codec_fields (tmp);
325 for (i = 0; gst_drm_decrypt_protection_ids[i]; ++i) {
326 /* filter out the audio/video related fields from the down-stream
327 * caps, because they are not relevant to the input caps of this
328 * element and they can cause caps negotiation failures with
329 * adaptive bitrate streams
330 */
331 out = gst_structure_copy (tmp);
332 gst_structure_set (out,
333 "protection-system", G_TYPE_STRING, gst_drm_decrypt_protection_ids[i],
334 "original-media-type", G_TYPE_STRING, gst_structure_get_name (in), NULL);
335 gst_structure_set_name (out, "application/x-cenc");
336 gst_drm_decrypt_append_if_not_duplicate (res, out);
337 }
338 gst_structure_free (tmp);
339 return TRUE;
340 }
341
342 static GstCaps *
gst_drm_decrypt_transform_caps(GstBaseTransform * base,GstPadDirection direction,GstCaps * caps,GstCaps * filter)343 gst_drm_decrypt_transform_caps (GstBaseTransform *base,
344 GstPadDirection direction, GstCaps *caps, GstCaps *filter)
345 {
346 GstCaps *res = NULL;
347 gint i;
348
349 g_return_val_if_fail (direction != GST_PAD_UNKNOWN, NULL);
350 GST_DEBUG_OBJECT (base, "direction:%s caps:%" GST_PTR_FORMAT " filter:"
351 " %" GST_PTR_FORMAT, (direction == GST_PAD_SRC) ? "Src" : "Sink", caps, filter);
352
353 if ((direction == GST_PAD_SRC) && (gst_caps_is_any (caps))) {
354 res = gst_pad_get_pad_template_caps (GST_BASE_TRANSFORM_SINK_PAD (base));
355 goto beach;
356 }
357
358 res = gst_caps_new_empty ();
359
360 for (i = 0; i < gst_caps_get_size (caps); ++i) {
361 GstStructure *in = gst_caps_get_structure (caps, i);
362 GstStructure *out = NULL;
363 if (direction == GST_PAD_SINK) {
364 if (gst_drm_decrypt_transform_sink_caps (base, res, in, out) == FALSE) {
365 continue;
366 }
367 } else { /* GST_PAD_SRC */
368 (void)gst_drm_decrypt_transform_src_caps (base, res, in, out);
369 }
370 }
371 if ((direction == GST_PAD_SINK) && (gst_caps_get_size (res) == 0)) {
372 gst_caps_unref (res);
373 res = gst_caps_new_any ();
374 }
375 beach:
376 if (filter) {
377 GstCaps *intersection;
378 GST_DEBUG_OBJECT (base, "using caps %" GST_PTR_FORMAT, filter);
379 intersection =
380 gst_caps_intersect_full (res, filter, GST_CAPS_INTERSECT_FIRST);
381 gst_caps_unref (res);
382 res = intersection;
383 }
384 GST_DEBUG_OBJECT (base, "return %" GST_PTR_FORMAT, res);
385 return res;
386 }
387
388 static void
gst_drm_get_algo(const gchar * mode,guint * algo)389 gst_drm_get_algo (const gchar *mode, guint *algo)
390 {
391 if ((strcmp (mode, "sm4c") == 0) || (strcmp (mode, "sm4s") == 0)) {
392 *algo = (guint)DRM_ALG_CENC_SM4_CBC;
393 } else if ((strcmp (mode, "cbc1") == 0) || (strcmp (mode, "cbcs") == 0)) {
394 *algo = (guint)DRM_ALG_CENC_AES_CBC;
395 } else if ((strcmp (mode, "cenc") == 0) || (strcmp (mode, "cens") == 0)) {
396 *algo = (guint)DRM_ALG_CENC_AES_CTR;
397 } else if ((strcmp (mode, "sm4t") == 0) || (strcmp (mode, "sm4r") == 0)) {
398 *algo = (guint)DRM_ALG_CENC_SM4_CTR;
399 }
400 return;
401 }
402
403 static void
gst_drm_decrypt_get_block(const GstProtectionMeta * prot_meta,guint * crypt_byte_block,guint * skip_byte_block)404 gst_drm_decrypt_get_block (const GstProtectionMeta *prot_meta, guint *crypt_byte_block,
405 guint *skip_byte_block)
406 {
407 if (!gst_structure_get_uint (prot_meta->info, "crypt_byte_block", crypt_byte_block)) {
408 GST_ERROR_OBJECT (prot_meta, "failed to get crypt_byte_block");
409 return;
410 }
411 if (!gst_structure_get_uint (prot_meta->info, "skip_byte_block", skip_byte_block)) {
412 GST_ERROR_OBJECT (prot_meta, "failed to get skip_byte_block");
413 return;
414 }
415 return;
416 }
417
418 static void
gst_drm_decrypt_get_algo(const GstProtectionMeta * prot_meta,guint * algo)419 gst_drm_decrypt_get_algo (const GstProtectionMeta *prot_meta, guint *algo)
420 {
421 const gchar *mode = NULL;
422 gboolean encrypted;
423 mode = gst_structure_get_string (prot_meta->info, "cipher-mode");
424 if (mode == NULL) {
425 *algo = DRM_ALG_CENC_UNENCRYPTED;
426 } else {
427 gst_drm_get_algo (mode, algo);
428 }
429 if (!gst_structure_get_boolean (prot_meta->info, "encrypted", &encrypted)) {
430 if (encrypted == FALSE) {
431 *algo = DRM_ALG_CENC_UNENCRYPTED;
432 }
433 }
434 return;
435 }
436
437 static GstFlowReturn
gst_drm_decrypt_get_iv(const GstProtectionMeta * prot_meta,guint8 * iv_data,guint * iv_data_size)438 gst_drm_decrypt_get_iv (const GstProtectionMeta *prot_meta, guint8 *iv_data, guint *iv_data_size)
439 {
440 GstFlowReturn ret = GST_FLOW_OK;
441 const GValue *value = NULL;
442 GstBuffer *iv_buf = NULL;
443 GstMapInfo iv_map;
444 guint iv_size;
445
446 if (!gst_structure_get_uint (prot_meta->info, "iv_size", &iv_size)) {
447 GST_ERROR_OBJECT (prot_meta, "failed to get iv_size");
448 return GST_FLOW_NOT_SUPPORTED;
449 }
450 if (iv_size > *iv_data_size) {
451 return GST_FLOW_NOT_SUPPORTED;
452 }
453 value = gst_structure_get_value (prot_meta->info, "iv");
454 if (value == NULL) {
455 GST_ERROR_OBJECT (prot_meta, "Failed to get iv for sample");
456 ret = GST_FLOW_NOT_SUPPORTED;
457 goto beach;
458 }
459 iv_buf = gst_value_get_buffer (value);
460 if (!gst_buffer_map (iv_buf, &iv_map, GST_MAP_READ)) {
461 GST_ERROR_OBJECT (prot_meta, "Failed to map iv");
462 ret = GST_FLOW_NOT_SUPPORTED;
463 goto beach;
464 }
465
466 if (iv_map.size > *iv_data_size) {
467 GST_ERROR_OBJECT (prot_meta, "iv size err\n");
468 ret = GST_FLOW_NOT_SUPPORTED;
469 goto beach;
470 }
471 *iv_data_size = iv_map.size;
472 memset (iv_data, 0, *iv_data_size);
473 memcpy (iv_data, iv_map.data, iv_map.size);
474 beach:
475 if (iv_buf) {
476 gst_buffer_unmap (iv_buf, &iv_map);
477 }
478 return ret;
479 }
480
481 static GstFlowReturn
gst_drm_decrypt_get_keyid(const GstProtectionMeta * prot_meta,guint8 * keyid_data,guint * keyid_data_size)482 gst_drm_decrypt_get_keyid (const GstProtectionMeta *prot_meta, guint8 *keyid_data, guint *keyid_data_size)
483 {
484 GstFlowReturn ret = GST_FLOW_OK;
485 const GValue *value = NULL;
486 GstBuffer *keyid_buf = NULL;
487 GstMapInfo keyid_map;
488
489 value = gst_structure_get_value (prot_meta->info, "kid");
490 if (value == NULL) {
491 GST_ERROR_OBJECT (prot_meta, "Failed to get kid for sample");
492 ret = GST_FLOW_NOT_SUPPORTED;
493 goto beach;
494 }
495 keyid_buf = gst_value_get_buffer (value);
496 if (!gst_buffer_map (keyid_buf, &keyid_map, GST_MAP_READ)) {
497 GST_ERROR_OBJECT (prot_meta, "Failed to map key id");
498 ret = GST_FLOW_NOT_SUPPORTED;
499 goto beach;
500 }
501
502 if (keyid_map.size > *keyid_data_size) {
503 GST_ERROR_OBJECT (prot_meta, "iv size err\n");
504 ret = GST_FLOW_NOT_SUPPORTED;
505 goto beach;
506 }
507 *keyid_data_size = keyid_map.size;
508 memset (keyid_data, 0, *keyid_data_size);
509 memcpy (keyid_data, keyid_map.data, keyid_map.size);
510 beach:
511 if (keyid_buf) {
512 gst_buffer_unmap (keyid_buf, &keyid_map);
513 }
514 return ret;
515 }
516
517 static GstFlowReturn
gst_drm_decrypt_get_subsample_count(const GstProtectionMeta * prot_meta,guint * subsample_count)518 gst_drm_decrypt_get_subsample_count (const GstProtectionMeta *prot_meta, guint *subsample_count)
519 {
520 if (!gst_structure_get_uint (prot_meta->info, "subsample_count", subsample_count)) {
521 GST_ERROR_OBJECT (prot_meta, "failed to get subsample_count");
522 return GST_FLOW_NOT_SUPPORTED;
523 }
524 if (*subsample_count > DRM_MAX_SUB_SAMPLE_NUM) {
525 GST_ERROR_OBJECT (prot_meta, "subsample_count err");
526 return GST_FLOW_NOT_SUPPORTED;
527 }
528 return GST_FLOW_OK;
529 }
530
531 static GstFlowReturn
gst_drm_decrypt_get_subsample(const GstProtectionMeta * prot_meta,DRM_SubSample * subsample_info,guint subsample_count)532 gst_drm_decrypt_get_subsample (const GstProtectionMeta *prot_meta, DRM_SubSample *subsample_info,
533 guint subsample_count)
534 {
535 GstFlowReturn ret = GST_FLOW_OK;
536 const GValue *value = NULL;
537 GstBuffer *subsamples_buf = NULL;
538 GstMapInfo subsamples_map;
539 GstByteReader *reader = NULL;
540
541 if (subsample_count) {
542 value = gst_structure_get_value (prot_meta->info, "subsamples");
543 if (value == NULL) {
544 GST_ERROR_OBJECT (prot_meta, "Failed to get subsamples");
545 return GST_FLOW_NOT_SUPPORTED;
546 }
547 subsamples_buf = gst_value_get_buffer (value);
548 if (!gst_buffer_map (subsamples_buf, &subsamples_map, GST_MAP_READ)) {
549 GST_ERROR_OBJECT (prot_meta, "Failed to map subsample buffer");
550 ret = GST_FLOW_NOT_SUPPORTED;
551 goto beach;
552 }
553 reader = gst_byte_reader_new (subsamples_map.data, subsamples_map.size);
554 if (reader == NULL) {
555 GST_ERROR_OBJECT (prot_meta, "Failed to new subsample reader");
556 ret = GST_FLOW_NOT_SUPPORTED;
557 goto beach;
558 }
559 }
560 for (guint i = 0; i < subsample_count; i++) {
561 guint16 clear_header_len = 0;
562 guint32 pay_load_len = 0;
563 if (!gst_byte_reader_get_uint16_be (reader, &clear_header_len)
564 || !gst_byte_reader_get_uint32_be (reader, &pay_load_len)) {
565 ret = GST_FLOW_NOT_SUPPORTED;
566 goto beach;
567 }
568 subsample_info[i].clear_header_len = (guint)clear_header_len;
569 subsample_info[i].pay_load_len = (guint)pay_load_len;
570 }
571 beach:
572 if (reader) {
573 gst_byte_reader_free (reader);
574 }
575 if (subsamples_buf) {
576 gst_buffer_unmap (subsamples_buf, &subsamples_map);
577 }
578 return ret;
579 }
580
581 static GstFlowReturn
gst_drm_decrypt_set_ts_subsample(GstMapInfo * map,DRM_SubSample * subsample_info,guint * subsample_count,guint skip_byte_block,guint * crypt_byte_block)582 gst_drm_decrypt_set_ts_subsample (GstMapInfo *map, DRM_SubSample *subsample_info,
583 guint *subsample_count, guint skip_byte_block, guint *crypt_byte_block)
584 {
585 if ((*subsample_count == 0) && (*crypt_byte_block + skip_byte_block == DRM_TS_FLAG_CRYPT_BYTE_BLOCK ||
586 *crypt_byte_block + skip_byte_block == (DRM_CRYPT_BYTE_BLOCK + DRM_SKIP_BYTE_BLOCK))) {
587 *subsample_count = (guint)DRM_TS_SUB_SAMPLE_NUM;
588 subsample_info[0].clear_header_len = map->size;
589 subsample_info[0].pay_load_len = 0;
590 subsample_info[1].clear_header_len = 0;
591 subsample_info[1].pay_load_len = 0;
592 if (*crypt_byte_block >= DRM_TS_FLAG_CRYPT_BYTE_BLOCK) {
593 *crypt_byte_block -= DRM_TS_FLAG_CRYPT_BYTE_BLOCK;
594 }
595 }
596 return GST_FLOW_OK;
597 }
598
599 static GstFlowReturn
gst_drm_decrypt_transform_ip(GstBaseTransform * base,GstBuffer * buf)600 gst_drm_decrypt_transform_ip (GstBaseTransform *base, GstBuffer *buf)
601 {
602 GstDrmDecrypt *self = GST_DRM_DECRYPT (base);
603 GstFlowReturn ret = GST_FLOW_OK;
604 GstMapInfo map;
605 guint algo = 0;
606 guint crypt_byte_block = 0;
607 guint skip_byte_block = 0;
608 guint subsample_count = 0;
609 DRM_SubSample subsample_info[DRM_MAX_SUB_SAMPLE_NUM];
610 guint iv_size = DRM_IV_SIZE;
611 guint8 iv_data[DRM_IV_SIZE];
612 guint keyid_size = KID_LENGTH;
613 guint8 keyid_data[KID_LENGTH];
614 gint res;
615 const GstProtectionMeta *prot_meta = (const GstProtectionMeta*) gst_buffer_get_protection_meta (buf);
616 if (prot_meta == NULL) {
617 goto out;
618 }
619 if (buf == NULL) {
620 GST_ERROR_OBJECT (self, "Failed to get writable buffer\n");
621 return GST_FLOW_NOT_SUPPORTED;
622 }
623 if (!gst_buffer_map (buf, &map, GST_MAP_READWRITE)) {
624 GST_ERROR_OBJECT (self, "Failed to map buffer");
625 ret = GST_FLOW_NOT_SUPPORTED;
626 goto out;
627 }
628 gst_drm_decrypt_get_block (prot_meta, &crypt_byte_block, &skip_byte_block);
629 gst_drm_decrypt_get_algo (prot_meta, &algo);
630 gst_drm_decrypt_get_iv (prot_meta, iv_data, &iv_size);
631 gst_drm_decrypt_get_keyid (prot_meta, keyid_data, &keyid_size);
632 gst_drm_decrypt_get_subsample_count (prot_meta, &subsample_count);
633 gst_drm_decrypt_get_subsample (prot_meta, subsample_info, subsample_count);
634 if (iv_size == 0 || algo == 0) {
635 /* sample is not encrypted */
636 goto beach;
637 }
638 gst_drm_decrypt_set_ts_subsample (&map, subsample_info, &subsample_count,
639 skip_byte_block, &crypt_byte_block);
640 if (self->is_audio) {
641 g_signal_emit_by_name ((GstElement *) base, "media-decrypt", map.data, map.data, map.size,
642 keyid_data, keyid_size, iv_data, iv_size, subsample_count, subsample_info, algo, 0,
643 crypt_byte_block, skip_byte_block, &res);
644 }
645 beach:
646 gst_buffer_unmap (buf, &map);
647 out:
648 return ret;
649 }
650
651 static gboolean
gst_drm_decrypt_sink_event_handler(GstBaseTransform * trans,GstEvent * event)652 gst_drm_decrypt_sink_event_handler (GstBaseTransform *trans, GstEvent *event)
653 {
654 gboolean res = TRUE;
655 const gchar *system_id;
656 GstBuffer *pssi = NULL;
657 const gchar *loc;
658 GstDrmDecrypt *self = GST_DRM_DECRYPT (trans);
659
660 switch (GST_EVENT_TYPE (event)) {
661 case GST_EVENT_PROTECTION:
662 GST_DEBUG_OBJECT (self, "received protection event");
663 gst_event_parse_protection (event, &system_id, &pssi, &loc);
664 GST_DEBUG_OBJECT (self, "system_id: %s loc: %s", system_id, loc);
665 if (g_str_has_prefix (loc, "isobmff/") && g_ascii_strcasecmp(system_id, CDRM_PROTECTION_ID) == 0) {
666 GST_DEBUG_OBJECT (self, "event carries pssh data from tsdemux or qtdemux");
667 self->drm_type = GST_DRM_CDRM;
668 }
669 gst_event_unref (event);
670 break;
671 default:
672 res = GST_BASE_TRANSFORM_CLASS (parent_class)->sink_event (trans, event);
673 break;
674 }
675 return res;
676 }
677