mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-27 12:11:13 +00:00
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:
parent
f8911deccf
commit
09749192d8
4 changed files with 888 additions and 1 deletions
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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 &&
|
||||
|
|
|
@ -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;
|
||||
|
||||
/**
|
||||
|
|
Loading…
Reference in a new issue