mpegts: atsc: add ETT structures and parsing
authorThiago Santos <ts.santos@sisa.samsung.com>
Mon, 19 May 2014 16:46:03 +0000 (13:46 -0300)
committerEdward Hervey <bilboed@bilboed.com>
Thu, 29 May 2014 08:37:59 +0000 (10:37 +0200)
ETT (extended text table) contains ATSC text information with descriptions
of virtual channels and events. The text can be internationalized and also
compressed.

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

gst-libs/gst/mpegts/gst-atsc-section.c
gst-libs/gst/mpegts/gst-atsc-section.h
gst-libs/gst/mpegts/gstmpegtssection.c
gst-libs/gst/mpegts/gstmpegtssection.h

index c77d0f8a11b11f25f591182f548dc95e2250c75a..a7118c15abf474de7dd29c92b752617ae2047b83 100644 (file)
@@ -396,3 +396,222 @@ gst_mpegts_section_get_atsc_mgt (GstMpegTsSection * section)
 
   return (const GstMpegTsAtscMGT *) section->cached_parsed;
 }
+
+static GstMpegTsAtscStringSegment *
+_gst_mpegts_atsc_string_segment_copy (GstMpegTsAtscStringSegment * seg)
+{
+  GstMpegTsAtscStringSegment *copy;
+
+  copy = g_slice_dup (GstMpegTsAtscStringSegment, seg);
+
+  return copy;
+}
+
+static void
+_gst_mpegts_atsc_string_segment_free (GstMpegTsAtscStringSegment * seg)
+{
+  if (seg->cached_string)
+    g_free (seg->cached_string);
+  g_slice_free (GstMpegTsAtscStringSegment, seg);
+}
+
+static void
+_gst_mpegts_atsc_string_segment_decode_string (GstMpegTsAtscStringSegment * seg)
+{
+  g_return_if_fail (seg->cached_string == NULL);
+
+  if (seg->compression_type != 0) {
+    GST_FIXME ("Compressed strings not yet supported");
+    return;
+  }
+  /* FIXME check encoding */
+
+  seg->cached_string =
+      g_strndup ((gchar *) seg->compressed_data, seg->compressed_data_size);
+}
+
+const gchar *
+gst_mpegts_atsc_string_segment_get_string (GstMpegTsAtscStringSegment * seg)
+{
+  if (!seg->cached_string)
+    _gst_mpegts_atsc_string_segment_decode_string (seg);
+
+  return seg->cached_string;
+}
+
+G_DEFINE_BOXED_TYPE (GstMpegTsAtscStringSegment, gst_mpegts_atsc_string_segment,
+    (GBoxedCopyFunc) _gst_mpegts_atsc_string_segment_copy,
+    (GFreeFunc) _gst_mpegts_atsc_string_segment_free);
+
+static GstMpegTsAtscMultString *
+_gst_mpegts_atsc_mult_string_copy (GstMpegTsAtscMultString * mstring)
+{
+  GstMpegTsAtscMultString *copy;
+
+  copy = g_slice_dup (GstMpegTsAtscMultString, mstring);
+  copy->segments = g_ptr_array_ref (mstring->segments);
+
+  return copy;
+}
+
+static void
+_gst_mpegts_atsc_mult_string_free (GstMpegTsAtscMultString * mstring)
+{
+  g_ptr_array_unref (mstring->segments);
+  g_slice_free (GstMpegTsAtscMultString, mstring);
+}
+
+G_DEFINE_BOXED_TYPE (GstMpegTsAtscMultString, gst_mpegts_atsc_mult_string,
+    (GBoxedCopyFunc) _gst_mpegts_atsc_mult_string_copy,
+    (GFreeFunc) _gst_mpegts_atsc_mult_string_free);
+
+static GstMpegTsAtscETT *
+_gst_mpegts_atsc_ett_copy (GstMpegTsAtscETT * ett)
+{
+  GstMpegTsAtscETT *copy;
+
+  copy = g_slice_dup (GstMpegTsAtscETT, ett);
+  copy->messages = g_ptr_array_ref (ett->messages);
+
+  return copy;
+}
+
+static void
+_gst_mpegts_atsc_ett_free (GstMpegTsAtscETT * ett)
+{
+  g_ptr_array_unref (ett->messages);
+  g_slice_free (GstMpegTsAtscETT, ett);
+}
+
+G_DEFINE_BOXED_TYPE (GstMpegTsAtscETT, gst_mpegts_atsc_ett,
+    (GBoxedCopyFunc) _gst_mpegts_atsc_ett_copy,
+    (GFreeFunc) _gst_mpegts_atsc_ett_free);
+
+static gpointer
+_parse_ett (GstMpegTsSection * section)
+{
+  GstMpegTsAtscETT *ett = NULL;
+  guint i = 0;
+  guint8 *data, *end;
+  guint8 num_strings;
+
+  ett = g_slice_new0 (GstMpegTsAtscETT);
+
+  data = section->data;
+  end = data + section->section_length;
+
+  /* Skip already parsed data */
+  data += 8;
+
+  ett->protocol_version = GST_READ_UINT8 (data);
+  data += 1;
+  ett->etm_id = GST_READ_UINT32_BE (data);
+  data += 4;
+
+  ett->messages = g_ptr_array_new_with_free_func ((GDestroyNotify)
+      _gst_mpegts_atsc_mult_string_free);
+
+  if (end - data > 4) {
+    /* 1 is the minimum entry size, so no need to check here */
+    num_strings = GST_READ_UINT8 (data);
+    data += 1;
+
+    for (i = 0; i < num_strings; i++) {
+      GstMpegTsAtscMultString *mstring;
+      guint8 num_segments;
+      gint j;
+
+      mstring = g_slice_new0 (GstMpegTsAtscMultString);
+      g_ptr_array_add (ett->messages, mstring);
+      mstring->segments =
+          g_ptr_array_new_full (num_strings,
+          (GDestroyNotify) _gst_mpegts_atsc_string_segment_free);
+
+      /* each entry needs at least 4 bytes (lang code and segments number */
+      if (end - data < 4 + 4) {
+        GST_WARNING ("PID %d invalid ETT entry length %d",
+            section->pid, (gint) (end - 4 - data));
+        goto error;
+      }
+
+      mstring->iso_639_langcode[0] = GST_READ_UINT8 (data);
+      data += 1;
+      mstring->iso_639_langcode[1] = GST_READ_UINT8 (data);
+      data += 1;
+      mstring->iso_639_langcode[2] = GST_READ_UINT8 (data);
+      data += 1;
+      num_segments = GST_READ_UINT8 (data);
+      data += 1;
+
+      for (j = 0; j < num_segments; j++) {
+        GstMpegTsAtscStringSegment *seg;
+
+        seg = g_slice_new0 (GstMpegTsAtscStringSegment);
+        g_ptr_array_add (mstring->segments, seg);
+
+        /* each entry needs at least 4 bytes (lang code and segments number */
+        if (end - data < 3 + 4) {
+          GST_WARNING ("PID %d invalid ETT entry length %d",
+              section->pid, (gint) (end - 4 - data));
+          goto error;
+        }
+
+        seg->compression_type = GST_READ_UINT8 (data);
+        data += 1;
+        seg->mode = GST_READ_UINT8 (data);
+        data += 1;
+        seg->compressed_data_size = GST_READ_UINT8 (data);
+        data += 1;
+
+        if (end - data < seg->compressed_data_size + 4) {
+          GST_WARNING ("PID %d invalid ETT entry length %d",
+              section->pid, (gint) (end - 4 - data));
+          goto error;
+        }
+
+        if (seg->compressed_data_size)
+          seg->compressed_data = data;
+        data += seg->compressed_data_size;
+      }
+
+    }
+  }
+
+  if (data != end - 4) {
+    GST_WARNING ("PID %d invalid ETT parsed %d length %d",
+        section->pid, (gint) (data - section->data), section->section_length);
+    goto error;
+  }
+
+  return (gpointer) ett;
+
+error:
+  if (ett)
+    _gst_mpegts_atsc_ett_free (ett);
+
+  return NULL;
+
+}
+
+/**
+ * gst_mpegts_section_get_atsc_ett:
+ * @section: a #GstMpegTsSection of type %GST_MPEGTS_SECTION_ATSC_ETT
+ *
+ * Returns the #GstMpegTsAtscETT contained in the @section.
+ *
+ * Returns: The #GstMpegTsAtscETT contained in the section, or %NULL if an error
+ * happened.
+ */
+const GstMpegTsAtscETT *
+gst_mpegts_section_get_atsc_ett (GstMpegTsSection * section)
+{
+  g_return_val_if_fail (section->section_type == GST_MPEGTS_SECTION_ATSC_ETT,
+      NULL);
+  g_return_val_if_fail (section->cached_parsed || section->data, NULL);
+
+  if (!section->cached_parsed)
+    section->cached_parsed = __common_section_checks (section, 17, _parse_ett,
+        (GDestroyNotify) _gst_mpegts_atsc_ett_free);
+
+  return (const GstMpegTsAtscETT *) section->cached_parsed;
+}
index caa612ef3ea27803eadf046160d5c535523d570c..91fb265862cf878766b9c5cd76a9d8c8a7c3ed29 100644 (file)
@@ -169,6 +169,53 @@ GType gst_mpegts_atsc_mgt_table_get_type (void);
 
 const GstMpegTsAtscMGT * gst_mpegts_section_get_atsc_mgt (GstMpegTsSection * section);
 
+/* ETT */
+
+#define GST_TYPE_MPEGTS_ATSC_STRING_SEGMENT (gst_mpegts_atsc_string_segment_get_type())
+#define GST_TYPE_MPEGTS_ATSC_MULT_STRING (gst_mpegts_atsc_mult_string_get_type())
+#define GST_TYPE_MPEGTS_ATSC_ETT (gst_mpegts_atsc_ett_get_type())
+
+typedef struct _GstMpegTsAtscStringSegment GstMpegTsAtscStringSegment;
+typedef struct _GstMpegTsAtscMultString GstMpegTsAtscMultString;
+typedef struct _GstMpegTsAtscETT GstMpegTsAtscETT;
+
+struct _GstMpegTsAtscStringSegment {
+  guint8 compression_type;
+  guint8 mode;
+  guint8 compressed_data_size;
+  guint8 *compressed_data;
+
+  gchar *cached_string;
+};
+
+const gchar * gst_mpegts_atsc_string_segment_get_string (GstMpegTsAtscStringSegment * seg);
+
+struct _GstMpegTsAtscMultString {
+  gchar      iso_639_langcode[4];
+  GPtrArray *segments;
+};
+
+/**
+ * GstMpegTsAtscETT:
+ * @events: (element-type FIXME): List of texts
+ *
+ * Extended Text Table (ATSC)
+ *
+ */
+struct _GstMpegTsAtscETT
+{
+  guint16        protocol_version;
+  guint32        etm_id;
+
+  GPtrArray     *messages;
+};
+
+GType gst_mpegts_atsc_string_segment_get_type (void);
+GType gst_mpegts_atsc_mult_string_get_type (void);
+GType gst_mpegts_atsc_ett_get_type (void);
+
+const GstMpegTsAtscETT *gst_mpegts_section_get_atsc_ett (GstMpegTsSection *section);
+
 G_END_DECLS
 
 #endif                         /* GST_MPEGTS_SECTION_H */
index d294d16d6bbfc6d151113ac7e76b2e77bc2c1e3d..97118f0e5d8cb06ac1df6aa3b4290b9c180c112b 100644 (file)
@@ -1063,6 +1063,9 @@ _identify_section (guint16 pid, guint8 table_id)
     case GST_MTS_TABLE_ID_ATSC_EVENT_INFORMATION:
       /* FIXME check pids reported on the MGT to confirm expectations */
       return GST_MPEGTS_SECTION_EIT;
+    case GST_MTS_TABLE_ID_ATSC_CHANNEL_OR_EVENT_EXTENDED_TEXT:
+      /* FIXME check pids reported on the MGT to confirm expectations */
+      return GST_MPEGTS_SECTION_ATSC_ETT;
       /* FIXME : FILL */
     default:
       /* Handle ranges */
index 536dce386524bc7489ae3d8a8b3206779973247a..2ee8f39273d09fd6931779714ce3727de0af2fb2 100644 (file)
@@ -54,6 +54,7 @@ GType gst_mpegts_section_get_type (void);
  * @GST_MPEGTS_SECTION_ATSC_TVCT: ATSC Terrestrial Virtual Channel Table (A65)
  * @GST_MPEGTS_SECTION_ATSC_CVCT: ATSC Cable Virtual Channel Table (A65)
  * @GST_MPEGTS_SECTION_ATSC_MGT: ATSC Master Guide Table (A65)
+ * @GST_MPEGTS_SECTION_ATSC_ETT: ATSC Extended Text Table (A65)
  *
  * Types of #GstMpegTsSection that the library handles.
  */
@@ -71,7 +72,8 @@ typedef enum {
   GST_MPEGTS_SECTION_TOT,
   GST_MPEGTS_SECTION_ATSC_TVCT,
   GST_MPEGTS_SECTION_ATSC_CVCT,
-  GST_MPEGTS_SECTION_ATSC_MGT
+  GST_MPEGTS_SECTION_ATSC_MGT,
+  GST_MPEGTS_SECTION_ATSC_ETT
 } GstMpegTsSectionType;
 
 /**