amlqtdemux: CB1 Widevine H264 CBCS Playback Exception [1/1]

PD#SWPL-198185

Problem:
Widevine H264 CBCS Playback Exception

Solution:
Reslove amlqtdemux send uncrypt video data to drm as encrypt
data

Verify:
SC2

Change-Id: I634a6dd18b3fbb0427c88acaa3774aab87778c78
Signed-off-by: shipeng sun <shipeng.sun@amlogic.com>
diff --git a/aml-qtdemux/aml-qtdemux.c b/aml-qtdemux/aml-qtdemux.c
index 9ba6fb9..e05caa1 100644
--- a/aml-qtdemux/aml-qtdemux.c
+++ b/aml-qtdemux/aml-qtdemux.c
@@ -2747,7 +2747,8 @@
       "encrypted", G_TYPE_BOOLEAN, (is_encrypted == 1),
       "kid", GST_TYPE_BUFFER, kid_buf, NULL);
   GST_DEBUG_OBJECT (qtdemux, "default sample properties: "
-      "is_encrypted=%u, iv_size=%u constant_iv_size=%u", is_encrypted, iv_size, constant_iv_size);
+      "is_encrypted=%u, iv_size=%u constant_iv_size=%u crypt_block %u:%u",
+      is_encrypted, iv_size, constant_iv_size, crypt_byte_block, skip_byte_block);
   gst_buffer_unref (kid_buf);
   if (protection_scheme_type == AML_FOURCC_cbcs || protection_scheme_type == AML_FOURCC_cens) {
     if (crypt_byte_block != 0 || skip_byte_block != 0) {
@@ -2925,6 +2926,7 @@
       qtdemux->cenc_aux_sample_count = i;
       return;
     }
+
     buf = gst_buffer_new_wrapped (data, iv_size);
     gst_structure_set (properties, "iv", GST_TYPE_BUFFER, buf, NULL);
     gst_buffer_unref (buf);
@@ -4054,6 +4056,147 @@
   return TRUE;
 }
 
+static void
+aml_qtdemux_parse_senc (GstAmlQTDemux * qtdemux, AmlQtDemuxStream * stream, GstByteReader * br)
+{
+  guint8 version = 0;
+  guint32 flags = 0;
+  gboolean use_subsample_encryption = FALSE;
+  guint16 subsample_count = 0;
+  guint32 byte_of_clear_data = 0;
+  guint32 byte_of_protected_data = 0;
+  guint32 sample_count = 0;
+  gint i, j;
+  guint iv_size = 8;
+  AmlQtDemuxCencSampleSetInfo *ss_info = NULL;
+
+  if (!stream->protection_scheme_info)
+    stream->protection_scheme_info = g_new0 (AmlQtDemuxCencSampleSetInfo, 1);
+
+  ss_info = (AmlQtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
+  if (!ss_info->default_properties) {
+    ss_info->default_properties =
+        gst_structure_new ("application/x-cenc",
+        "encrypted", G_TYPE_BOOLEAN, TRUE,
+        NULL);
+  }
+
+  if (ss_info->crypto_info) {
+    GST_LOG_OBJECT (qtdemux, "unreffing existing crypto_info");
+    g_ptr_array_free (ss_info->crypto_info, TRUE);
+    ss_info->crypto_info = NULL;
+  }
+
+  if (!gst_byte_reader_get_uint8 (br, &version)) {
+    GST_ERROR_OBJECT (qtdemux, "Error getting box's version field");
+    return;
+  }
+
+  GST_DEBUG_OBJECT (qtdemux, "version %d", version);
+
+  if (version > 0) {
+    return;
+  }
+
+  if (!gst_byte_reader_get_uint24_be (br, &flags)) {
+    GST_ERROR_OBJECT (qtdemux, "Error getting box's flags field");
+    return;
+  }
+
+  if (flags & 0x000002) {
+    use_subsample_encryption = TRUE;
+  }
+
+  if (!gst_structure_get_uint (ss_info->default_properties, "iv_size", &iv_size)) {
+    GST_ERROR_OBJECT (qtdemux, "Error getting encryption IV size field");
+    return;
+  }
+  GST_DEBUG_OBJECT (qtdemux, "iv_size %d", iv_size);
+
+  if (!gst_byte_reader_get_uint32_be (br, &sample_count)) {
+    GST_ERROR_OBJECT (qtdemux, "Error getting box's sample count field");
+    return;
+  }
+
+  ss_info->crypto_info =
+      g_ptr_array_new_full (sample_count,
+      (GDestroyNotify) aml_qtdemux_gst_structure_free);
+
+  for (i = 0; i < sample_count; i++) {
+    GstStructure *properties;
+    guint8 *data;
+    GstBuffer *buf;
+    GstBuffer *subsamples = NULL;
+
+    properties = aml_qtdemux_get_cenc_sample_properties (qtdemux, stream, i);
+    if (properties == NULL) {
+      GST_ERROR_OBJECT (qtdemux, "failed to get properties for sample %u", i);
+      qtdemux->cenc_aux_sample_count = i;
+      return;
+    }
+
+    if (iv_size > 0) {
+      if (!gst_byte_reader_dup_data (br, iv_size, &data)) {
+        GST_ERROR_OBJECT (qtdemux, "IV data not present for sample %u", i);
+        gst_structure_free (properties);
+        qtdemux->cenc_aux_sample_count = i;
+        return;
+      }
+      buf = gst_buffer_new_wrapped (data, iv_size);
+      gst_structure_set (properties, "iv", GST_TYPE_BUFFER, buf, NULL);
+      gst_buffer_unref (buf);
+    } else {
+      const GValue *constant_iv_size_value =
+          gst_structure_get_value (properties, "constant_iv_size");
+      const GValue *constant_iv_value =
+          gst_structure_get_value (properties, "iv");
+      if (constant_iv_size_value == NULL || constant_iv_value == NULL) {
+        GST_ERROR_OBJECT (qtdemux, "failed to get constant_iv");
+        gst_structure_free (properties);
+        return;
+      }
+      gst_structure_set_value (properties, "iv_size", constant_iv_size_value);
+    }
+
+    if (use_subsample_encryption) {
+      const GValue *kid_buf_value;
+      if (!gst_byte_reader_get_uint16_be (br, &subsample_count)
+        || subsample_count == 0) {
+        GST_ERROR_OBJECT (qtdemux,
+            "failed to get subsample count for sample %u", i);
+        gst_structure_free (properties);
+        qtdemux->cenc_aux_sample_count = i;
+        return;
+      }
+      GST_DEBUG_OBJECT (qtdemux, "subsample_count %d", subsample_count);
+
+      if (!gst_byte_reader_dup_data (br, subsample_count * 6, &data)) {
+        GST_ERROR_OBJECT (qtdemux, "failed to get subsample data for sample %u",
+            i);
+        gst_structure_free (properties);
+        qtdemux->cenc_aux_sample_count = i;
+        return;
+      }
+      buf = gst_buffer_new_wrapped (data, subsample_count * 6);// guint16 clr + guint32 enc
+      kid_buf_value = gst_structure_get_value (ss_info->default_properties, "kid");
+
+      gst_structure_set (properties,
+          "subsample_count", G_TYPE_UINT, subsample_count,
+          "subsamples", GST_TYPE_BUFFER, buf, NULL);
+      gst_structure_set_value (properties, "kid", kid_buf_value);
+      gst_buffer_unref (buf);
+    } else {
+      gst_structure_set (properties,
+          "subsample_count", G_TYPE_UINT, 0,
+          "subsamples", GST_TYPE_BUFFER, NULL, NULL);
+    }
+
+    g_ptr_array_add (ss_info->crypto_info, properties);
+  }
+
+  qtdemux->cenc_aux_sample_count = sample_count;
+}
+
 static gboolean
 aml_qtdemux_parse_moof (GstAmlQTDemux * qtdemux, const guint8 * buffer, guint length,
     guint64 moof_offset, AmlQtDemuxStream * stream)
@@ -4067,7 +4210,8 @@
   gint64 base_offset, running_offset;
   guint32 frag_num;
   GstClockTime min_dts = GST_CLOCK_TIME_NONE;
-
+  GNode *senc_node;
+  GstByteReader senc_data;
   /* NOTE @stream ignored */
 
   moof_node = g_node_new ((guint8 *) buffer);
@@ -4159,7 +4303,16 @@
         }
       }
     } else {
-      GST_WARNING_OBJECT (qtdemux, "no saiz_node, may cbc1 audio");
+      GST_WARNING_OBJECT (qtdemux, "no saiz_node, may cbc1 audio, try parse senc");
+      senc_node =
+          aml_qtdemux_tree_get_child_by_type_full (traf_node, AML_FOURCC_senc,
+          &senc_data);
+      if (senc_node) {
+        GST_DEBUG_OBJECT (qtdemux, "parsing senc box");
+        aml_qtdemux_parse_senc (qtdemux, stream, &senc_data);
+      } else {
+        GST_WARNING_OBJECT (qtdemux, "no senc_node");
+      }
     }
 
     tfdt_node =
@@ -6055,7 +6208,7 @@
       || stream->protection_scheme_type == AML_FOURCC_cbc1
       || stream->protection_scheme_type == AML_FOURCC_cbcs
       || stream->protection_scheme_type == AML_FOURCC_cens)) {
-    GstStructure *crypto_info;
+    GstStructure *crypto_info = NULL;
     AmlQtDemuxCencSampleSetInfo *info =
         (AmlQtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
     gint index;
@@ -6069,49 +6222,8 @@
     }
 
     if (info->crypto_info == NULL) {
-      /* cbc1 audio may has no saiz node, need update crypto info from default properties */
-      if (stream->protection_scheme_type == AML_FOURCC_cbcs || stream->protection_scheme_type == AML_FOURCC_cens) {
-        guint crypt_byte_block = 0;
-        guint skip_byte_block = 0;
-        guint iv_size = 0;
-        guint constant_iv_size = 0;
-
-        crypto_info = aml_qtdemux_get_cenc_sample_properties (qtdemux, stream, 0);
-        gst_structure_get (crypto_info,
-            "crypt_byte_block", G_TYPE_UINT, &crypt_byte_block,
-            "skip_byte_block", G_TYPE_UINT, &skip_byte_block,
-            "iv_size", G_TYPE_UINT, &iv_size,
-            NULL);
-        if (iv_size == 0) {
-          if (!gst_structure_get_uint (crypto_info, "constant_iv_size", &constant_iv_size)) {
-            GST_ERROR_OBJECT (qtdemux, "failed to get iv_size");
-          } else {
-            gst_structure_set (crypto_info, "iv_size", G_TYPE_UINT, constant_iv_size, NULL);
-          }
-        }
-
-        meta = gst_buffer_get_protection_meta(buf);
-        if (meta) {
-          GST_DEBUG_OBJECT (qtdemux, "protection metadata name %s", gst_structure_get_name(meta->info));
-          gst_structure_set (meta->info,
-              "crypt_byte_block", G_TYPE_UINT, crypt_byte_block,
-              "skip_byte_block", G_TYPE_UINT, skip_byte_block,
-              NULL);
-        } else {
-          GST_INFO_OBJECT (qtdemux, "no cbcs protection metadata");
-        }
-
-        if (!meta && (!crypto_info || !gst_buffer_add_protection_meta (buf, crypto_info))) {
-          GST_ERROR_OBJECT (qtdemux,
-              "failed to attach cbcs metadata to buffer");
-          aml_qtdemux_gst_structure_free (crypto_info);
-        } else {
-          GST_TRACE_OBJECT (qtdemux, "added cbcs protection metadata");
-        }
-      } else {
-        GST_DEBUG_OBJECT (qtdemux,
-            "cenc metadata hasn't been parsed yet, pushing buffer as if it wasn't encrypted");
-      }
+      GST_DEBUG_OBJECT (qtdemux,
+          "cenc metadata hasn't been parsed yet, pushing buffer as if it wasn't encrypted");
     } else {
       /* The end of the crypto_info array matches our n_samples position,
        * so count backward from there */
@@ -6135,6 +6247,13 @@
               "crypt_byte_block", G_TYPE_UINT, &crypt_byte_block,
               "skip_byte_block", G_TYPE_UINT, &skip_byte_block,
               NULL);
+          if (crypt_byte_block == 0 && skip_byte_block == 0
+              && (0 == strncmp(GST_PAD_NAME (stream->pad), "audio", 5))) {
+            crypt_byte_block = 1;
+            gst_structure_set (crypto_info,
+                "crypt_byte_block", G_TYPE_UINT, crypt_byte_block,
+                NULL);
+          }
           meta = gst_buffer_get_protection_meta(buf);
           if (meta) {
             GST_DEBUG_OBJECT (qtdemux, "protection metadata name %s", gst_structure_get_name(meta->info));