• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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