summaryrefslogtreecommitdiff
path: root/gst-libs/gst/mpegts
diff options
context:
space:
mode:
authorMathieu Duponchelle <mathieu@centricular.com>2019-05-21 02:53:20 +0200
committerMathieu Duponchelle <mduponchelle1@gmail.com>2019-05-30 13:53:05 +0000
commit09749192d83609c903499656fcb683ac494741ae (patch)
tree085a699edff3b265e5524ec5378e40801d5ddbb0 /gst-libs/gst/mpegts
parentf8911deccf05ce3087b1d4939d3c91ab424fc8de (diff)
downloadgstreamer-plugins-bad-09749192d83609c903499656fcb683ac494741ae.tar.gz
mpegts: extend support for ATSC tables
Adds constructors for the following sections: STT: System Time Table MGT: Master Guide Table RRT: Rating Region Table Also adds parsing code for RRT
Diffstat (limited to 'gst-libs/gst/mpegts')
-rw-r--r--gst-libs/gst/mpegts/gst-atsc-section.c779
-rw-r--r--gst-libs/gst/mpegts/gst-atsc-section.h103
-rw-r--r--gst-libs/gst/mpegts/gstmpegtssection.c4
-rw-r--r--gst-libs/gst/mpegts/gstmpegtssection.h3
4 files changed, 888 insertions, 1 deletions
diff --git a/gst-libs/gst/mpegts/gst-atsc-section.c b/gst-libs/gst/mpegts/gst-atsc-section.c
index a67863f8b..97743f7ae 100644
--- a/gst-libs/gst/mpegts/gst-atsc-section.c
+++ b/gst-libs/gst/mpegts/gst-atsc-section.c
@@ -372,6 +372,131 @@ error:
return NULL;
}
+static gboolean
+_packetize_mgt (GstMpegtsSection * section)
+{
+ const GstMpegtsAtscMGT *mgt;
+ guint8 *pos, *data;
+ gsize length;
+ guint i, j;
+
+ mgt = gst_mpegts_section_get_atsc_mgt (section);
+
+ if (mgt == NULL)
+ return FALSE;
+
+ if (mgt->tables_defined != mgt->tables->len)
+ return FALSE;
+
+ /* 8 byte common section fields
+ * 1 byte protocol version
+ * 2 byte tables_defined
+ * 2 byte reserved / descriptors_length
+ * 4 byte CRC
+ */
+ length = 17;
+
+ for (i = 0; i < mgt->tables->len; i++) {
+ GstMpegtsAtscMGTTable *mgt_table = g_ptr_array_index (mgt->tables, 1);
+ /* 2 byte table_type
+ * 2 byte reserved / table_type_PID
+ * 1 byte reserved / table_type_version_number
+ * 4 byte number bytes
+ * 2 byte reserved / table_type_descriptors_length
+ */
+ length += 11;
+
+ if (mgt_table->descriptors) {
+ for (j = 0; j < mgt_table->descriptors->len; j++) {
+ GstMpegtsDescriptor *descriptor =
+ g_ptr_array_index (mgt_table->descriptors, j);
+ length += descriptor->length + 2;
+ }
+ }
+ }
+
+ if (mgt->descriptors) {
+ for (i = 0; i < mgt->descriptors->len; i++) {
+ GstMpegtsDescriptor *descriptor = g_ptr_array_index (mgt->descriptors, i);
+ length += descriptor->length + 2;
+ }
+ }
+
+ _packetize_common_section (section, length);
+
+ data = section->data + 8;
+
+ /* protocol_version - 8 bit */
+ GST_WRITE_UINT8 (data, mgt->protocol_version);
+ data += 1;
+
+ /* tables_defined - 16 bit uimsbf */
+ GST_WRITE_UINT16_BE (data, mgt->tables_defined);
+ data += 2;
+
+ for (i = 0; i < mgt->tables_defined; i++) {
+ GstMpegtsAtscMGTTable *mgt_table = g_ptr_array_index (mgt->tables, 1);
+
+ /* table_type - 16 bit uimsbf */
+ GST_WRITE_UINT16_BE (data, mgt_table->table_type);
+ data += 2;
+
+ /* 3 bit reserved, 13 bit table_type_PID uimsbf */
+ GST_WRITE_UINT16_BE (data, mgt_table->pid | 0xe000);
+ data += 2;
+
+ /* 3 bit reserved, 5 bit table_type_version_number uimsbf */
+ GST_WRITE_UINT8 (data, mgt_table->version_number | 0xe0);
+ data += 1;
+
+ /* 4 bit reserved, 12 bit table_type_descriptor_length uimsbf */
+ pos = data;
+ *data++ = 0xF0;
+ *data++ = 0x00;
+
+ _packetize_descriptor_array (mgt_table->descriptors, &data);
+
+ /* Go back and update the descriptor length */
+ GST_WRITE_UINT16_BE (pos, (data - pos - 2) | 0xF000);
+ }
+
+ /* 4 bit reserved, 12 bit descriptor_length uimsbf */
+ pos = data;
+ *data++ = 0xF0;
+ *data++ = 0x00;
+
+ _packetize_descriptor_array (mgt->descriptors, &data);
+
+ /* Go back and update the descriptor length */
+ GST_WRITE_UINT16_BE (pos, (data - pos - 2) | 0xF000);
+
+ return TRUE;
+}
+
+/**
+ * gst_mpegts_section_from_atsc_mgt:
+ * @mgt: (transfer full): a #GstMpegtsAtscMGT to create the #GstMpegtsSection from
+ *
+ * Returns: (transfer full): the #GstMpegtsSection
+ * Since: 1.18
+ */
+GstMpegtsSection *
+gst_mpegts_section_from_atsc_mgt (GstMpegtsAtscMGT * mgt)
+{
+ GstMpegtsSection *section;
+
+ g_return_val_if_fail (mgt != NULL, NULL);
+
+ section = _gst_mpegts_section_init (0x1ffb,
+ GST_MTS_TABLE_ID_ATSC_MASTER_GUIDE);
+
+ section->subtable_extension = 0x0000;
+ section->cached_parsed = (gpointer) mgt;
+ section->packetizer = _packetize_mgt;
+ section->destroy_parsed = (GDestroyNotify) _gst_mpegts_atsc_mgt_free;
+
+ return section;
+}
/**
* gst_mpegts_section_get_atsc_mgt:
@@ -397,6 +522,28 @@ gst_mpegts_section_get_atsc_mgt (GstMpegtsSection * section)
return (const GstMpegtsAtscMGT *) section->cached_parsed;
}
+/**
+ * gst_mpegts_section_atsc_mgt_new:
+ *
+ * Returns: (transfer full): #GstMpegtsAtscMGT
+ * Since: 1.18
+ */
+GstMpegtsAtscMGT *
+gst_mpegts_atsc_mgt_new (void)
+{
+ GstMpegtsAtscMGT *mgt;
+
+ mgt = g_slice_new0 (GstMpegtsAtscMGT);
+
+ mgt->tables = g_ptr_array_new_with_free_func ((GDestroyNotify)
+ _gst_mpegts_atsc_mgt_table_free);
+
+ mgt->descriptors = g_ptr_array_new_with_free_func ((GDestroyNotify)
+ gst_mpegts_descriptor_free);
+
+ return mgt;
+}
+
/* Multi string structure */
static GstMpegtsAtscStringSegment *
@@ -466,6 +613,66 @@ gst_mpegts_atsc_string_segment_get_string (GstMpegtsAtscStringSegment * seg)
return seg->cached_string;
}
+gboolean
+gst_mpegts_atsc_string_segment_set_string (GstMpegtsAtscStringSegment * seg,
+ gchar * string, guint8 compression_type, guint8 mode)
+{
+ const gchar *to_encoding = NULL;
+ gboolean ret = FALSE;
+ gsize written;
+ GError *err = NULL;
+ unsigned long len;
+
+ if (compression_type) {
+ GST_FIXME ("Compressed strings not yet supported");
+ goto done;
+ }
+
+ switch (mode) {
+ case 0x3f:
+ to_encoding = "UTF-16BE";
+ break;
+ default:
+ break;
+ }
+
+ if (seg->cached_string)
+ g_free (seg->cached_string);
+
+ if (seg->compressed_data)
+ g_free (seg->compressed_data);
+
+ seg->cached_string = g_strdup (string);
+ seg->compression_type = compression_type;
+ seg->mode = mode;
+
+ len = strlen (string);
+
+ if (to_encoding && len) {
+ gchar *converted = g_convert (string, len, to_encoding, "UTF-8",
+ NULL, &written, &err);
+
+ if (err) {
+ GST_WARNING ("Failed to convert input string to codeset %s (%s)",
+ to_encoding, err->message);
+ g_error_free (err);
+ goto done;
+ }
+
+ seg->compressed_data = (guint8 *) g_strndup (converted, written);
+ seg->compressed_data_size = written;
+ g_free (converted);
+ } else {
+ seg->compressed_data = (guint8 *) g_strndup (string, len);
+ seg->compressed_data_size = len;
+ }
+
+ ret = TRUE;
+
+done:
+ return ret;
+}
+
G_DEFINE_BOXED_TYPE (GstMpegtsAtscStringSegment, gst_mpegts_atsc_string_segment,
(GBoxedCopyFunc) _gst_mpegts_atsc_string_segment_copy,
(GFreeFunc) _gst_mpegts_atsc_string_segment_free);
@@ -575,6 +782,82 @@ error:
return NULL;
}
+static void
+_packetize_atsc_mult_string (GPtrArray * strings, guint8 ** data)
+{
+ guint i;
+
+ if (strings == NULL)
+ return;
+
+ /* 8 bit number_strings */
+ GST_WRITE_UINT8 (*data, strings->len);
+ *data += 1;
+
+ for (i = 0; i < strings->len; i++) {
+ GstMpegtsAtscMultString *string;
+ guint j;
+
+ string = g_ptr_array_index (strings, i);
+
+ /* 24 bit ISO_639_langcode */
+ GST_WRITE_UINT8 (*data, string->iso_639_langcode[0]);
+ *data += 1;
+ GST_WRITE_UINT8 (*data, string->iso_639_langcode[1]);
+ *data += 1;
+ GST_WRITE_UINT8 (*data, string->iso_639_langcode[2]);
+ *data += 1;
+ /* 8 bit number_segments */
+ GST_WRITE_UINT8 (*data, string->segments->len);
+ *data += 1;
+
+ for (j = 0; j < string->segments->len; j++) {
+ GstMpegtsAtscStringSegment *seg;
+
+ seg = g_ptr_array_index (string->segments, j);
+
+ /* 8 bit compression_type */
+ GST_WRITE_UINT8 (*data, seg->compression_type);
+ *data += 1;
+ /* 8 bit mode */
+ GST_WRITE_UINT8 (*data, seg->mode);
+ *data += 1;
+ /* 8 bit number_bytes */
+ GST_WRITE_UINT8 (*data, seg->compressed_data_size);
+ *data += 1;
+ /* number_bytes compressed string */
+ memcpy (*data, seg->compressed_data, seg->compressed_data_size);
+ *data += seg->compressed_data_size;
+ }
+ }
+}
+
+static gsize
+_get_atsc_mult_string_packetized_length (GPtrArray * strings)
+{
+ gsize length = 1;
+ guint i;
+
+ for (i = 0; i < strings->len; i++) {
+ GstMpegtsAtscMultString *string;
+ guint j;
+
+ string = g_ptr_array_index (strings, i);
+
+ length += 4;
+
+ for (j = 0; j < string->segments->len; j++) {
+ GstMpegtsAtscStringSegment *seg;
+
+ seg = g_ptr_array_index (string->segments, j);
+
+ length += 3 + seg->compressed_data_size;
+ }
+ }
+
+ return length;
+}
+
/* EIT */
static GstMpegtsAtscEITEvent *
@@ -893,6 +1176,84 @@ error:
return NULL;
}
+static gboolean
+_packetize_stt (GstMpegtsSection * section)
+{
+ const GstMpegtsAtscSTT *stt;
+ guint8 *data;
+ gsize length;
+ guint i;
+
+ stt = gst_mpegts_section_get_atsc_stt (section);
+
+ if (stt == NULL)
+ return FALSE;
+
+ /* 8 byte common section fields
+ * 1 byte protocol version
+ * 4 byte system time
+ * 1 byte GPS_UTC_offset
+ * 2 byte daylight saving
+ * 4 byte CRC
+ */
+ length = 20;
+
+ if (stt->descriptors) {
+ for (i = 0; i < stt->descriptors->len; i++) {
+ GstMpegtsDescriptor *descriptor = g_ptr_array_index (stt->descriptors, i);
+ length += descriptor->length + 2;
+ }
+ }
+
+ _packetize_common_section (section, length);
+
+ data = section->data + 8;
+
+ /* protocol_version - 8 bit */
+ GST_WRITE_UINT8 (data, stt->protocol_version);
+ data += 1;
+ /* system time - 32 bit uimsbf */
+ GST_WRITE_UINT32_BE (data, stt->system_time);
+ data += 4;
+ /* GPS_UTC_offset - 8 bit */
+ GST_WRITE_UINT8 (data, stt->gps_utc_offset);
+ data += 1;
+ /* daylight_saving - 16 bit uimsbf */
+ GST_WRITE_UINT8 (data,
+ (stt->ds_status << 7) | 0x60 | (stt->ds_dayofmonth & 0x1f));
+ data += 1;
+ GST_WRITE_UINT8 (data, stt->ds_hour);
+ data += 1;
+
+ _packetize_descriptor_array (stt->descriptors, &data);
+
+ return TRUE;
+}
+
+/**
+ * gst_mpegts_section_section_from_atsc_stt:
+ * @stt: (transfer full): a #GstMpegtsAtscSTT to create the #GstMpegtsSection from
+ *
+ * Returns: (transfer full): the #GstMpegtsSection
+ * Since: 1.18
+ */
+GstMpegtsSection *
+gst_mpegts_section_from_atsc_stt (GstMpegtsAtscSTT * stt)
+{
+ GstMpegtsSection *section;
+
+ g_return_val_if_fail (stt != NULL, NULL);
+
+ section = _gst_mpegts_section_init (0x1ffb,
+ GST_MTS_TABLE_ID_ATSC_SYSTEM_TIME);
+
+ section->subtable_extension = 0x0000;
+ section->cached_parsed = (gpointer) stt;
+ section->packetizer = _packetize_stt;
+ section->destroy_parsed = (GDestroyNotify) _gst_mpegts_atsc_stt_free;
+
+ return section;
+}
/**
* gst_mpegts_section_get_atsc_stt:
@@ -918,6 +1279,24 @@ gst_mpegts_section_get_atsc_stt (GstMpegtsSection * section)
return (const GstMpegtsAtscSTT *) section->cached_parsed;
}
+/**
+ * gst_mpegts_section_atsc_stt_new:
+ *
+ * Returns: (transfer full): #GstMpegtsAtscSTT
+ * Since: 1.18
+ */
+GstMpegtsAtscSTT *
+gst_mpegts_atsc_stt_new (void)
+{
+ GstMpegtsAtscSTT *stt;
+
+ stt = g_slice_new0 (GstMpegtsAtscSTT);
+ stt->descriptors = g_ptr_array_new_with_free_func ((GDestroyNotify)
+ gst_mpegts_descriptor_free);
+
+ return stt;
+}
+
#define GPS_TO_UTC_TICKS G_GINT64_CONSTANT(315964800)
static GstDateTime *
_gst_mpegts_atsc_gps_time_to_datetime (guint32 systemtime, guint8 gps_offset)
@@ -937,3 +1316,403 @@ gst_mpegts_atsc_stt_get_datetime_utc (GstMpegtsAtscSTT * stt)
return gst_date_time_ref (stt->utc_datetime);
return NULL;
}
+
+/* RRT */
+
+static GstMpegtsAtscRRTDimensionValue *
+_gst_mpegts_atsc_rrt_dimension_value_copy (GstMpegtsAtscRRTDimensionValue *
+ value)
+{
+ GstMpegtsAtscRRTDimensionValue *copy;
+
+ copy = g_slice_dup (GstMpegtsAtscRRTDimensionValue, value);
+ copy->abbrev_ratings = g_ptr_array_ref (value->abbrev_ratings);
+ copy->ratings = g_ptr_array_ref (value->ratings);
+
+ return copy;
+}
+
+static void
+_gst_mpegts_atsc_rrt_dimension_value_free (GstMpegtsAtscRRTDimensionValue *
+ value)
+{
+ if (value->abbrev_ratings)
+ g_ptr_array_unref (value->abbrev_ratings);
+ if (value->ratings)
+ g_ptr_array_unref (value->ratings);
+
+ g_slice_free (GstMpegtsAtscRRTDimensionValue, value);
+}
+
+G_DEFINE_BOXED_TYPE (GstMpegtsAtscRRTDimensionValue,
+ gst_mpegts_atsc_rrt_dimension_value,
+ (GBoxedCopyFunc) _gst_mpegts_atsc_rrt_dimension_value_copy,
+ (GFreeFunc) _gst_mpegts_atsc_rrt_dimension_value_free);
+
+static GstMpegtsAtscRRTDimension *
+_gst_mpegts_atsc_rrt_dimension_copy (GstMpegtsAtscRRTDimension * dim)
+{
+ GstMpegtsAtscRRTDimension *copy;
+
+ copy = g_slice_dup (GstMpegtsAtscRRTDimension, dim);
+ copy->names = g_ptr_array_ref (dim->names);
+ copy->values = g_ptr_array_ref (dim->values);
+
+ return copy;
+}
+
+static void
+_gst_mpegts_atsc_rrt_dimension_free (GstMpegtsAtscRRTDimension * dim)
+{
+ if (dim->names)
+ g_ptr_array_unref (dim->names);
+ if (dim->values)
+ g_ptr_array_unref (dim->values);
+
+ g_slice_free (GstMpegtsAtscRRTDimension, dim);
+}
+
+G_DEFINE_BOXED_TYPE (GstMpegtsAtscRRTDimension, gst_mpegts_atsc_rrt_dimension,
+ (GBoxedCopyFunc) _gst_mpegts_atsc_rrt_dimension_copy,
+ (GFreeFunc) _gst_mpegts_atsc_rrt_dimension_free);
+
+static GstMpegtsAtscRRT *
+_gst_mpegts_atsc_rrt_copy (GstMpegtsAtscRRT * rrt)
+{
+ GstMpegtsAtscRRT *copy;
+
+ copy = g_slice_dup (GstMpegtsAtscRRT, rrt);
+ copy->names = g_ptr_array_ref (rrt->names);
+ copy->dimensions = g_ptr_array_ref (rrt->dimensions);
+ copy->descriptors = g_ptr_array_ref (rrt->descriptors);
+
+ return copy;
+}
+
+static void
+_gst_mpegts_atsc_rrt_free (GstMpegtsAtscRRT * rrt)
+{
+ if (rrt->names)
+ g_ptr_array_unref (rrt->names);
+ if (rrt->dimensions)
+ g_ptr_array_unref (rrt->dimensions);
+ if (rrt->descriptors)
+ g_ptr_array_unref (rrt->descriptors);
+
+ g_slice_free (GstMpegtsAtscRRT, rrt);
+}
+
+G_DEFINE_BOXED_TYPE (GstMpegtsAtscRRT, gst_mpegts_atsc_rrt,
+ (GBoxedCopyFunc) _gst_mpegts_atsc_rrt_copy,
+ (GFreeFunc) _gst_mpegts_atsc_rrt_free);
+
+static gpointer
+_parse_rrt (GstMpegtsSection * section)
+{
+ GstMpegtsAtscRRT *rrt = NULL;
+ guint i = 0;
+ guint8 *data;
+ guint16 descriptors_loop_length;
+ guint8 text_length;
+
+ rrt = g_slice_new0 (GstMpegtsAtscRRT);
+
+ data = section->data;
+
+ /* Skip already parsed data */
+ data += 8;
+
+ rrt->protocol_version = GST_READ_UINT8 (data);
+ data += 1;
+
+ text_length = GST_READ_UINT8 (data);
+ data += 1;
+ rrt->names = _parse_atsc_mult_string (data, text_length);
+ data += text_length;
+
+ rrt->dimensions_defined = GST_READ_UINT8 (data);
+ data += 1;
+
+ rrt->dimensions = g_ptr_array_new_full (rrt->dimensions_defined,
+ (GDestroyNotify) _gst_mpegts_atsc_rrt_dimension_free);
+
+ for (i = 0; i < rrt->dimensions_defined; i++) {
+ GstMpegtsAtscRRTDimension *dim;
+ guint8 tmp;
+ guint j = 0;
+
+ dim = g_slice_new0 (GstMpegtsAtscRRTDimension);
+ g_ptr_array_add (rrt->dimensions, dim);
+
+ text_length = GST_READ_UINT8 (data);
+ data += 1;
+ dim->names = _parse_atsc_mult_string (data, text_length);
+ data += text_length;
+
+ tmp = GST_READ_UINT8 (data);
+ data += 1;
+
+ dim->graduated_scale = tmp & 0x10;
+ dim->values_defined = tmp & 0x0f;
+
+ dim->values = g_ptr_array_new_full (dim->values_defined,
+ (GDestroyNotify) _gst_mpegts_atsc_rrt_dimension_value_free);
+
+ for (j = 0; j < dim->values_defined; j++) {
+ GstMpegtsAtscRRTDimensionValue *val;
+
+ val = g_slice_new0 (GstMpegtsAtscRRTDimensionValue);
+ g_ptr_array_add (dim->values, val);
+
+ text_length = GST_READ_UINT8 (data);
+ data += 1;
+ val->abbrev_ratings = _parse_atsc_mult_string (data, text_length);
+ data += text_length;
+
+ text_length = GST_READ_UINT8 (data);
+ data += 1;
+ val->ratings = _parse_atsc_mult_string (data, text_length);
+ data += text_length;
+ }
+ }
+
+ descriptors_loop_length = GST_READ_UINT16_BE (data) & 0x3FF;
+ data += 2;
+ rrt->descriptors =
+ gst_mpegts_parse_descriptors (data, descriptors_loop_length);
+
+ return (gpointer) rrt;
+}
+
+static gboolean
+_packetize_rrt (GstMpegtsSection * section)
+{
+ const GstMpegtsAtscRRT *rrt;
+ guint8 *data, *pos;
+ gsize length;
+ gsize names_length;
+ guint i, j;
+
+ rrt = gst_mpegts_section_get_atsc_rrt (section);
+
+ if (rrt == NULL)
+ return FALSE;
+
+ names_length = _get_atsc_mult_string_packetized_length (rrt->names);
+
+ /* 8 byte common section fields
+ * 1 byte protocol version
+ * 1 byte rating_region_name_length
+ * name_length bytes
+ * 1 byte dimensions_defined
+ * 2 byte reserved / descriptors_length
+ * 4 byte CRC
+ */
+ length = names_length + 17;
+
+ for (i = 0; i < rrt->dimensions->len; i++) {
+ GstMpegtsAtscRRTDimension *dim = g_ptr_array_index (rrt->dimensions, i);
+
+ /* 1 byte dimension_name_length
+ * 1 byte reserved / graduated_scale / values_defined
+ */
+ length += 2;
+ length += _get_atsc_mult_string_packetized_length (dim->names);
+ for (j = 0; j < dim->values->len; j++) {
+ GstMpegtsAtscRRTDimensionValue *val = g_ptr_array_index (dim->values, j);
+
+ /* 1 byte abbrev_rating_value_length
+ * 1 byte rating_value_length
+ */
+ length += 2;
+ length += _get_atsc_mult_string_packetized_length (val->abbrev_ratings);
+ length += _get_atsc_mult_string_packetized_length (val->ratings);
+ }
+ }
+
+ if (rrt->descriptors) {
+ for (i = 0; i < rrt->descriptors->len; i++) {
+ GstMpegtsDescriptor *descriptor = g_ptr_array_index (rrt->descriptors, i);
+ length += descriptor->length + 2;
+ }
+ }
+
+ if (length > 1024) {
+ GST_WARNING ("RRT size can not exceed 1024");
+ return FALSE;
+ }
+
+ _packetize_common_section (section, length);
+
+ data = section->data + 8;
+
+ /* protocol_version - 8 bit */
+ GST_WRITE_UINT8 (data, rrt->protocol_version);
+ data += 1;
+
+ /* rating_region_name_length - 8 bit */
+ GST_WRITE_UINT8 (data, names_length);
+ data += 1;
+
+ _packetize_atsc_mult_string (rrt->names, &data);
+
+ for (i = 0; i < rrt->dimensions->len; i++) {
+ GstMpegtsAtscRRTDimension *dim = g_ptr_array_index (rrt->dimensions, i);
+
+ /* dimension_name_length - 8 bit */
+ GST_WRITE_UINT8 (data,
+ _get_atsc_mult_string_packetized_length (dim->names));
+ data += 1;
+
+ _packetize_atsc_mult_string (rrt->names, &data);
+
+ /* 3 bit reserved / 1 bit graduated_scale / 4 bit values_defined */
+ GST_WRITE_UINT8 (data,
+ 0xe0 | ((dim->graduated_scale ? 1 : 0) << 4) | (dim->
+ values_defined & 0x0f));
+ data += 1;
+
+ for (j = 0; j < dim->values->len; j++) {
+ GstMpegtsAtscRRTDimensionValue *val = g_ptr_array_index (dim->values, j);
+
+ /* abbrev_rating_value_length - 8 bit */
+ GST_WRITE_UINT8 (data,
+ _get_atsc_mult_string_packetized_length (val->abbrev_ratings));
+ data += 1;
+
+ _packetize_atsc_mult_string (val->abbrev_ratings, &data);
+
+ /* rating_value_length - 8 bit */
+ GST_WRITE_UINT8 (data,
+ _get_atsc_mult_string_packetized_length (val->ratings));
+ data += 1;
+
+ _packetize_atsc_mult_string (val->ratings, &data);
+ }
+ }
+
+ /* 6 bit reserved, 10 bit descriptor_length uimsbf */
+ pos = data;
+ *data++ = 0xFC;
+ *data++ = 0x00;
+
+ _packetize_descriptor_array (rrt->descriptors, &data);
+
+ /* Go back and update the descriptor length */
+ GST_WRITE_UINT16_BE (pos, (data - pos - 2) | 0xFC00);
+
+ return TRUE;
+}
+
+/**
+ * gst_mpegts_section_section_from_atsc_rrt:
+ * @rrt: (transfer full): a #GstMpegtsAtscRRT to create the #GstMpegtsSection from
+ *
+ * Returns: (transfer full): the #GstMpegtsSection
+ * Since: 1.18
+ */
+GstMpegtsSection *
+gst_mpegts_section_from_atsc_rrt (GstMpegtsAtscRRT * rrt)
+{
+ GstMpegtsSection *section;
+
+ g_return_val_if_fail (rrt != NULL, NULL);
+
+ section = _gst_mpegts_section_init (0x1ffb,
+ GST_MTS_TABLE_ID_ATSC_RATING_REGION);
+
+ /* FIXME random rating_region, what should be the default? */
+ section->subtable_extension = 0xff01;
+ section->cached_parsed = (gpointer) rrt;
+ section->packetizer = _packetize_rrt;
+ section->destroy_parsed = (GDestroyNotify) _gst_mpegts_atsc_rrt_free;
+
+ return section;
+}
+
+/**
+ * gst_mpegts_section_get_atsc_rrt:
+ * @section: a #GstMpegtsSection of type %GST_MPEGTS_SECTION_ATSC_RRT
+ *
+ * Returns the #GstMpegtsAtscRRT contained in the @section.
+ *
+ * Returns: The #GstMpegtsAtscRRT contained in the section, or %NULL if an error
+ * happened.
+ * Since: 1.18
+ */
+const GstMpegtsAtscRRT *
+gst_mpegts_section_get_atsc_rrt (GstMpegtsSection * section)
+{
+ g_return_val_if_fail (section->section_type == GST_MPEGTS_SECTION_ATSC_RRT,
+ 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_rrt,
+ (GDestroyNotify) _gst_mpegts_atsc_rrt_free);
+
+ return (const GstMpegtsAtscRRT *) section->cached_parsed;
+}
+
+/**
+ * gst_mpegts_section_atsc_rrt_dimension_value_new:
+ *
+ * Returns: (transfer full): #GstMpegtsAtscRRTDimensionValue
+ * Since: 1.18
+ */
+GstMpegtsAtscRRTDimensionValue *
+gst_mpegts_atsc_rrt_dimension_value_new (void)
+{
+ GstMpegtsAtscRRTDimensionValue *val;
+
+ val = g_slice_new0 (GstMpegtsAtscRRTDimensionValue);
+ val->abbrev_ratings = g_ptr_array_new_with_free_func ((GDestroyNotify)
+ _gst_mpegts_atsc_mult_string_free);
+ val->ratings = g_ptr_array_new_with_free_func ((GDestroyNotify)
+ _gst_mpegts_atsc_mult_string_free);
+
+ return val;
+}
+
+/**
+ * gst_mpegts_section_atsc_rrt_dimension_new:
+ *
+ * Returns: (transfer full): #GstMpegtsAtscRRTDimension
+ * Since: 1.18
+ */
+GstMpegtsAtscRRTDimension *
+gst_mpegts_atsc_rrt_dimension_new (void)
+{
+ GstMpegtsAtscRRTDimension *dim;
+
+ dim = g_slice_new0 (GstMpegtsAtscRRTDimension);
+ dim->names = g_ptr_array_new_with_free_func ((GDestroyNotify)
+ _gst_mpegts_atsc_mult_string_free);
+ dim->values = g_ptr_array_new_with_free_func ((GDestroyNotify)
+ _gst_mpegts_atsc_rrt_dimension_value_free);
+
+ return dim;
+}
+
+/**
+ * gst_mpegts_section_atsc_rrt_new:
+ *
+ * Returns: (transfer full): #GstMpegtsAtscRRT
+ * Since: 1.18
+ */
+GstMpegtsAtscRRT *
+gst_mpegts_atsc_rrt_new (void)
+{
+ GstMpegtsAtscRRT *rrt;
+
+ rrt = g_slice_new0 (GstMpegtsAtscRRT);
+ rrt->names = g_ptr_array_new_with_free_func ((GDestroyNotify)
+ _gst_mpegts_atsc_mult_string_free);
+ rrt->dimensions = g_ptr_array_new_with_free_func ((GDestroyNotify)
+ _gst_mpegts_atsc_rrt_dimension_free);
+ rrt->descriptors = g_ptr_array_new_with_free_func ((GDestroyNotify)
+ gst_mpegts_descriptor_free);
+
+ return rrt;
+}
diff --git a/gst-libs/gst/mpegts/gst-atsc-section.h b/gst-libs/gst/mpegts/gst-atsc-section.h
index ca353211d..b31bd1486 100644
--- a/gst-libs/gst/mpegts/gst-atsc-section.h
+++ b/gst-libs/gst/mpegts/gst-atsc-section.h
@@ -208,6 +208,12 @@ GType gst_mpegts_atsc_mgt_table_get_type (void);
GST_MPEGTS_API
const GstMpegtsAtscMGT * gst_mpegts_section_get_atsc_mgt (GstMpegtsSection * section);
+GST_MPEGTS_API
+GstMpegtsSection * gst_mpegts_section_from_atsc_mgt (GstMpegtsAtscMGT * mgt);
+
+GST_MPEGTS_API
+GstMpegtsAtscMGT * gst_mpegts_atsc_mgt_new (void);
+
/* Multiple string structure (used in ETT and EIT */
#define GST_TYPE_MPEGTS_ATSC_STRING_SEGMENT (gst_mpegts_atsc_string_segment_get_type())
@@ -238,6 +244,13 @@ struct _GstMpegtsAtscStringSegment {
GST_MPEGTS_API
const gchar * gst_mpegts_atsc_string_segment_get_string (GstMpegtsAtscStringSegment * seg);
+GST_MPEGTS_API
+gboolean
+gst_mpegts_atsc_string_segment_set_string (GstMpegtsAtscStringSegment * seg,
+ gchar *string,
+ guint8 compression_type,
+ guint8 mode);
+
/**
* GstMpegtsAtscMultString:
* @iso_639_langcode: The ISO639 language code
@@ -383,6 +396,96 @@ const GstMpegtsAtscSTT * gst_mpegts_section_get_atsc_stt (GstMpegtsSection * sec
GST_MPEGTS_API
GstDateTime * gst_mpegts_atsc_stt_get_datetime_utc (GstMpegtsAtscSTT * stt);
+GST_MPEGTS_API
+GstMpegtsSection * gst_mpegts_section_from_atsc_stt (GstMpegtsAtscSTT * stt);
+
+GST_MPEGTS_API
+GstMpegtsAtscSTT * gst_mpegts_atsc_stt_new (void);
+
+/* RRT */
+#define GST_TYPE_MPEGTS_ATSC_RRT (gst_mpegts_atsc_rrt_get_type ())
+#define GST_TYPE_MPEGTS_ATSC_RRT_DIMENSION (gst_mpegts_atsc_rrt_dimension_get_type ())
+#define GST_TYPE_MPEGTS_ATSC_RRT_DIMENSION_VALUE (gst_mpegts_atsc_rrt_dimension_value_get_type ())
+
+typedef struct _GstMpegtsAtscRRT GstMpegtsAtscRRT;
+typedef struct _GstMpegtsAtscRRTDimension GstMpegtsAtscRRTDimension;
+typedef struct _GstMpegtsAtscRRTDimensionValue GstMpegtsAtscRRTDimensionValue;
+
+/**
+ * GstMpegtsAtscRRTDimensionValue:
+ * @abbrev_ratings: (element-type GstMpegtsAtscMultString): the abbreviated ratings
+ * @ratings: (element-type GstMpegtsAtscMultString): the ratings
+ *
+ * Since: 1.18
+ */
+struct _GstMpegtsAtscRRTDimensionValue
+{
+ GPtrArray *abbrev_ratings;
+ GPtrArray *ratings;
+};
+
+/**
+ * _GstMpegtsAtscRRTDimension:
+ * @names: (element-type GstMpegtsAtscMultString): the names
+ * @graduated_scale: whether the ratings represent a graduated scale
+ * @values_defined: the number of values defined for this dimension
+ * @values: (element-type GstMpegtsAtscRRTDimensionValue): set of values
+ *
+ * Since: 1.18
+ */
+struct _GstMpegtsAtscRRTDimension
+{
+ GPtrArray * names;
+ gboolean graduated_scale;
+ guint8 values_defined;
+ GPtrArray * values;
+};
+
+/**
+ * GstMpegtsAtscRRT:
+ * @protocol_version: The protocol version
+ * @names: (element-type GstMpegtsAtscMultString): the names
+ * @dimensions_defined: the number of dimensions defined for this rating table
+ * @dimensions: (element-type GstMpegtsAtscRRTDimension): A set of dimensions
+ * @descriptors: descriptors
+ *
+ * Region Rating Table (A65)
+ *
+ * Since: 1.18
+ */
+struct _GstMpegtsAtscRRT
+{
+ guint8 protocol_version;
+ GPtrArray * names;
+ guint8 dimensions_defined;
+ GPtrArray * dimensions;
+ GPtrArray * descriptors;
+};
+
+GST_MPEGTS_API
+GType gst_mpegts_atsc_rrt_get_type (void);
+
+GST_MPEGTS_API
+GType gst_mpegts_atsc_rrt_dimension_get_type (void);
+
+GST_MPEGTS_API
+GType gst_mpegts_atsc_rrt_dimension_value_get_type (void);
+
+GST_MPEGTS_API
+const GstMpegtsAtscRRT * gst_mpegts_section_get_atsc_rrt (GstMpegtsSection * section);
+
+GST_MPEGTS_API
+GstMpegtsSection * gst_mpegts_section_from_atsc_rrt (GstMpegtsAtscRRT * rrt);
+
+GST_MPEGTS_API
+GstMpegtsAtscRRT * gst_mpegts_atsc_rrt_new (void);
+
+GST_MPEGTS_API
+GstMpegtsAtscRRTDimension * gst_mpegts_atsc_rrt_dimension_new (void);
+
+GST_MPEGTS_API
+GstMpegtsAtscRRTDimensionValue * gst_mpegts_atsc_rrt_dimension_value_new (void);
+
G_END_DECLS
#endif /* GST_MPEGTS_SECTION_H */
diff --git a/gst-libs/gst/mpegts/gstmpegtssection.c b/gst-libs/gst/mpegts/gstmpegtssection.c
index 595c288d9..c92752bb5 100644
--- a/gst-libs/gst/mpegts/gstmpegtssection.c
+++ b/gst-libs/gst/mpegts/gstmpegtssection.c
@@ -1119,6 +1119,10 @@ _identify_section (guint16 pid, guint8 table_id)
if (pid == 0x1ffb)
return GST_MPEGTS_SECTION_ATSC_STT;
break;
+ case GST_MTS_TABLE_ID_ATSC_RATING_REGION:
+ if (pid == 0x1ffb)
+ return GST_MPEGTS_SECTION_ATSC_RRT;
+ break;
default:
/* Handle ranges */
if (table_id >= GST_MTS_TABLE_ID_EVENT_INFORMATION_ACTUAL_TS_PRESENT &&
diff --git a/gst-libs/gst/mpegts/gstmpegtssection.h b/gst-libs/gst/mpegts/gstmpegtssection.h
index 6054edfe1..aeb6121d1 100644
--- a/gst-libs/gst/mpegts/gstmpegtssection.h
+++ b/gst-libs/gst/mpegts/gstmpegtssection.h
@@ -78,7 +78,8 @@ typedef enum {
GST_MPEGTS_SECTION_ATSC_MGT,
GST_MPEGTS_SECTION_ATSC_ETT,
GST_MPEGTS_SECTION_ATSC_EIT,
- GST_MPEGTS_SECTION_ATSC_STT
+ GST_MPEGTS_SECTION_ATSC_STT,
+ GST_MPEGTS_SECTION_ATSC_RRT
} GstMpegtsSectionType;
/**