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;
+}
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 */