mpegts: atsc: add ETT structures and parsing

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
This commit is contained in:
Thiago Santos 2014-05-19 13:46:03 -03:00 committed by Edward Hervey
parent 32d8022820
commit 7ced36eccd
4 changed files with 272 additions and 1 deletions

View file

@ -396,3 +396,222 @@ gst_mpegts_section_get_atsc_mgt (GstMpegTsSection * section)
return (const GstMpegTsAtscMGT *) section->cached_parsed; 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;
}

View file

@ -169,6 +169,53 @@ GType gst_mpegts_atsc_mgt_table_get_type (void);
const GstMpegTsAtscMGT * gst_mpegts_section_get_atsc_mgt (GstMpegTsSection * section); 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 G_END_DECLS
#endif /* GST_MPEGTS_SECTION_H */ #endif /* GST_MPEGTS_SECTION_H */

View file

@ -1063,6 +1063,9 @@ _identify_section (guint16 pid, guint8 table_id)
case GST_MTS_TABLE_ID_ATSC_EVENT_INFORMATION: case GST_MTS_TABLE_ID_ATSC_EVENT_INFORMATION:
/* FIXME check pids reported on the MGT to confirm expectations */ /* FIXME check pids reported on the MGT to confirm expectations */
return GST_MPEGTS_SECTION_EIT; 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 */ /* FIXME : FILL */
default: default:
/* Handle ranges */ /* Handle ranges */

View 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_TVCT: ATSC Terrestrial Virtual Channel Table (A65)
* @GST_MPEGTS_SECTION_ATSC_CVCT: ATSC Cable 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_MGT: ATSC Master Guide Table (A65)
* @GST_MPEGTS_SECTION_ATSC_ETT: ATSC Extended Text Table (A65)
* *
* Types of #GstMpegTsSection that the library handles. * Types of #GstMpegTsSection that the library handles.
*/ */
@ -71,7 +72,8 @@ typedef enum {
GST_MPEGTS_SECTION_TOT, GST_MPEGTS_SECTION_TOT,
GST_MPEGTS_SECTION_ATSC_TVCT, GST_MPEGTS_SECTION_ATSC_TVCT,
GST_MPEGTS_SECTION_ATSC_CVCT, GST_MPEGTS_SECTION_ATSC_CVCT,
GST_MPEGTS_SECTION_ATSC_MGT GST_MPEGTS_SECTION_ATSC_MGT,
GST_MPEGTS_SECTION_ATSC_ETT
} GstMpegTsSectionType; } GstMpegTsSectionType;
/** /**