event: add new GST_EVENT_PROTECTION
authorAlex Ashley <bugzilla@ashley-family.net>
Mon, 16 Mar 2015 12:35:27 +0000 (12:35 +0000)
committerTim-Philipp Müller <tim@centricular.com>
Sat, 18 Apr 2015 11:04:29 +0000 (12:04 +0100)
In order for a decrypter element to decrypt media protected using a
specific protection system, it first needs all the protection system
specific  information necessary (E.g. information on how to acquire
the decryption keys) for that stream.

The GST_EVENT_PROTECTION defined in this commit enables this information
to be passed from elements that extract it (e.g. qtdemux, dashdemux) to
elements that use it (E.g. a decrypter element).

API: GST_EVENT_PROTECTION
API: gst_event_new_protection()
API: gst_event_parse_protection()

https://bugzilla.gnome.org/show_bug.cgi?id=705991

gst/gstevent.c
gst/gstevent.h
tests/check/gst/gstevent.c
win32/common/libgstreamer.def

index 4d48b9a..725679a 100644 (file)
@@ -109,6 +109,7 @@ static GstEventQuarks event_quarks[] = {
   {GST_EVENT_SEGMENT, "segment", 0},
   {GST_EVENT_TAG, "tag", 0},
   {GST_EVENT_TOC, "toc", 0},
+  {GST_EVENT_PROTECTION, "protection", 0},
   {GST_EVENT_BUFFERSIZE, "buffersize", 0},
   {GST_EVENT_SINK_MESSAGE, "sink-message", 0},
   {GST_EVENT_EOS, "eos", 0},
@@ -1691,6 +1692,127 @@ gst_event_parse_toc_select (GstEvent * event, gchar ** uid)
 }
 
 /**
+ * SECTION:gstprotectionevent
+ * @short_description: Functions to support the passing of
+ * protection system specific information via events.
+ *
+ * In order for a decryption element to decrypt media
+ * protected using a specific system, it first needs all the
+ * protection system specific information necessary to acquire the decryption
+ * key(s) for that stream. The functions defined here enable this information
+ * to be passed in events from elements that extract it
+ * (e.g., ISOBMFF demuxers, MPEG DASH demuxers) to protection decrypter
+ * elements that use it.
+ *
+ * Events containing protection system specific information are created using
+ * #gst_event_new_protection, and they can be parsed by downstream elements
+ * using #gst_event_parse_protection.
+ *
+ * In Common Encryption, protection system specific information may be located
+ * within ISOBMFF files, both in movie (moov) boxes and movie fragment (moof)
+ * boxes; it may also be contained in ContentProtection elements within MPEG
+ * DASH MPDs. The events created by #gst_event_new_protection contain data
+ * identifying from which of these locations the encapsulated protection system
+ * specific information originated. This origin information is required as
+ * some protection systems use different encodings depending upon where the
+ * information originates.
+ *
+ * The events returned by #gst_event_new_protection are implemented
+ * in such a way as to ensure that the most recently-pushed protection info
+ * event of a particular @origin and @system_id will
+ * be stuck to the output pad of the sending element.
+ *
+ * Since: 1.6
+ */
+
+/**
+ * gst_event_new_protection:
+ * @system_id: (transfer none): a string holding a UUID that uniquely
+ * identifies a protection system.
+ * @data: (transfer none): a #GstBuffer holding protection system specific
+ * information. The reference count of the buffer will be incremented by one.
+ * @origin: a string indicating where the protection
+ * information carried in the event was extracted from. The allowed values
+ * of this string will depend upon the protection scheme.
+ *
+ * Creates a new event containing information specific to a particular
+ * protection system (uniquely identified by @system_id), by which that
+ * protection system can acquire key(s) to decrypt a protected stream.
+ *
+ * Returns: a #GST_EVENT_PROTECTION event, if successful; %NULL
+ * if unsuccessful.
+ *
+ * Since: 1.6
+ */
+GstEvent *
+gst_event_new_protection (const gchar * system_id,
+    GstBuffer * data, const gchar * origin)
+{
+  gchar *event_name;
+  GstEvent *event;
+  GstStructure *s;
+
+  g_return_val_if_fail (system_id != NULL, NULL);
+  g_return_val_if_fail (data != NULL, NULL);
+
+  event_name =
+      g_strconcat ("GstProtectionEvent", origin ? "-" : "",
+      origin ? origin : "", "-", system_id, NULL);
+
+  GST_CAT_INFO (GST_CAT_EVENT, "creating protection event %s", event_name);
+
+  s = gst_structure_new (event_name, "data", GST_TYPE_BUFFER, data,
+      "system_id", G_TYPE_STRING, system_id, NULL);
+  if (origin)
+    gst_structure_set (s, "origin", G_TYPE_STRING, origin, NULL);
+  event = gst_event_new_custom (GST_EVENT_PROTECTION, s);
+
+  g_free (event_name);
+  return event;
+}
+
+/**
+ * gst_event_parse_protection:
+ * @event: a #GST_EVENT_PROTECTION event.
+ * @system_id: (out) (allow-none) (transfer none): pointer to store the UUID
+ * string uniquely identifying a content protection system.
+ * @data: (out) (allow-none) (transfer none): pointer to store a #GstBuffer
+ * holding protection system specific information.
+ * @origin: (allow-none) (transfer none): pointer to store a value that
+ * indicates where the protection information carried by @event was extracted
+ * from.
+ *
+ * Parses an event containing protection system specific information and stores
+ * the results in @system_id, @data and @origin. The data stored in @system_id,
+ * @origin and @data are valid until @event is released.
+ *
+ * Since: 1.6
+ */
+void
+gst_event_parse_protection (GstEvent * event, const gchar ** system_id,
+    GstBuffer ** data, const gchar ** origin)
+{
+  const GstStructure *s;
+
+  g_return_if_fail (event != NULL);
+  g_return_if_fail (GST_IS_EVENT (event));
+  g_return_if_fail (GST_EVENT_TYPE (event) == GST_EVENT_PROTECTION);
+
+  s = gst_event_get_structure (event);
+
+  if (origin)
+    *origin = gst_structure_get_string (s, "origin");
+
+  if (system_id)
+    *system_id = gst_structure_get_string (s, "system_id");
+
+  if (data) {
+    const GValue *value = gst_structure_get_value (s, "data");
+    *data = gst_value_get_buffer (value);
+  }
+}
+
+/**
  * gst_event_new_segment_done:
  * @format: The format of the position being done
  * @position: The position of the segment being done
index ee7e8e0..67d70d7 100644 (file)
@@ -99,6 +99,8 @@ typedef enum {
  * @GST_EVENT_GAP: Marks a gap in the datastream.
  * @GST_EVENT_TOC: An event which indicates that a new table of contents (TOC)
  *                 was found or updated.
+ * @GST_EVENT_PROTECTION: An event which indicates that new or updated
+ *                 encryption information has been found in the stream.
  * @GST_EVENT_QOS: A quality message. Used to indicate to upstream elements
  *                 that the downstream elements should adjust their processing
  *                 rate.
@@ -147,6 +149,7 @@ typedef enum {
   GST_EVENT_SINK_MESSAGE          = GST_EVENT_MAKE_TYPE (100, FLAG(DOWNSTREAM) | FLAG(SERIALIZED) | FLAG(STICKY) | FLAG(STICKY_MULTI)),
   GST_EVENT_EOS                   = GST_EVENT_MAKE_TYPE (110, FLAG(DOWNSTREAM) | FLAG(SERIALIZED) | FLAG(STICKY)),
   GST_EVENT_TOC                   = GST_EVENT_MAKE_TYPE (120, FLAG(DOWNSTREAM) | FLAG(SERIALIZED) | FLAG(STICKY) | FLAG(STICKY_MULTI)),
+  GST_EVENT_PROTECTION            = GST_EVENT_MAKE_TYPE (130, FLAG (DOWNSTREAM) | FLAG (SERIALIZED) | FLAG (STICKY) | FLAG (STICKY_MULTI)),
 
   /* non-sticky downstream serialized */
   GST_EVENT_SEGMENT_DONE          = GST_EVENT_MAKE_TYPE (150, FLAG(DOWNSTREAM) | FLAG(SERIALIZED)),
@@ -530,6 +533,12 @@ void            gst_event_parse_tag             (GstEvent *event, GstTagList **t
 GstEvent*      gst_event_new_toc                (GstToc *toc, gboolean updated);
 void           gst_event_parse_toc              (GstEvent *event, GstToc **toc, gboolean *updated);
 
+/* Protection event */
+     GstEvent *gst_event_new_protection (const gchar * system_id,
+    GstBuffer * data, const gchar * origin);
+
+     void gst_event_parse_protection (GstEvent * event,
+    const gchar ** system_id, GstBuffer ** data, const gchar ** origin);
 
 /* buffer */
 GstEvent *      gst_event_new_buffer_size       (GstFormat format, gint64 minsize, gint64 maxsize,
index 7aae693..0983a69 100644 (file)
@@ -235,6 +235,42 @@ GST_START_TEST (create_events)
     gst_event_unref (event);
   }
 
+  /* Protection */
+  {
+    GstBuffer *data;
+    GstMemory *mem;
+    const gchar *parsed_origin;
+    const gchar *parsed_id;
+    GstBuffer *parsed_data;
+    const gchar clearkey_sys_id[] = "78f32170-d883-11e0-9572-0800200c9a66";
+
+    data = gst_buffer_new ();
+    mem = gst_allocator_alloc (NULL, 40, NULL);
+    gst_buffer_insert_memory (data, -1, mem);
+    for (gsize offset = 0; offset < 40; offset += 4) {
+      gst_buffer_fill (data, offset, "pssi", 4);
+    }
+    ASSERT_MINI_OBJECT_REFCOUNT (data, "data", 1);
+    event = gst_event_new_protection (clearkey_sys_id, data, "test");
+    fail_if (event == NULL);
+    ASSERT_MINI_OBJECT_REFCOUNT (data, "data", 2);
+    fail_unless (GST_EVENT_TYPE (event) == GST_EVENT_PROTECTION);
+    fail_unless (GST_EVENT_IS_DOWNSTREAM (event));
+    fail_unless (GST_EVENT_IS_SERIALIZED (event));
+    gst_event_parse_protection (event, &parsed_id, &parsed_data,
+        &parsed_origin);
+    fail_if (parsed_id == NULL);
+    fail_unless (g_strcmp0 (clearkey_sys_id, parsed_id) == 0);
+    fail_if (parsed_data == NULL);
+    fail_if (parsed_data != data);
+    ASSERT_MINI_OBJECT_REFCOUNT (data, "data", 2);
+    fail_if (parsed_origin == NULL);
+    fail_unless (g_strcmp0 ("test", parsed_origin) == 0);
+    gst_event_unref (event);
+    ASSERT_MINI_OBJECT_REFCOUNT (data, "data", 1);
+    gst_buffer_unref (data);
+  }
+
   /* Custom event types */
   {
     structure = gst_structure_new_empty ("application/x-custom");
index ebb0063..f567fda 100644 (file)
@@ -559,6 +559,7 @@ EXPORTS
        gst_event_new_gap
        gst_event_new_latency
        gst_event_new_navigation
+       gst_event_new_protection
        gst_event_new_qos
        gst_event_new_reconfigure
        gst_event_new_seek
@@ -576,6 +577,7 @@ EXPORTS
        gst_event_parse_gap
        gst_event_parse_group_id
        gst_event_parse_latency
+       gst_event_parse_protection
        gst_event_parse_qos
        gst_event_parse_seek
        gst_event_parse_segment