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
This commit is contained in:
Mathieu Duponchelle 2019-05-21 02:53:20 +02:00 committed by Mathieu Duponchelle
parent f8911deccf
commit 09749192d8
4 changed files with 888 additions and 1 deletions

View file

@ -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;
}

View file

@ -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 */

View file

@ -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 &&

View file

@ -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;
/**