mpegts: add atsc MGT section parsing

Add a parsing function for MGT and also detect the EIT tables
for ATSC, the EIT pids are reported inside the MGT and we are still
only relying only on the table id for detecting it. In the future we
would want to also check the pid and compare with whatever the MGT
previously reported to confirm that it is indeed the EIT.

https://bugzilla.gnome.org/show_bug.cgi?id=730435
This commit is contained in:
Thiago Santos 2014-05-15 12:31:05 -03:00 committed by Edward Hervey
parent 8f6a3c0a99
commit 9eed28d353
5 changed files with 226 additions and 1 deletions

View file

@ -250,3 +250,149 @@ gst_mpegts_section_get_atsc_cvct (GstMpegTsSection * section)
return (const GstMpegTsAtscVCT *) section->cached_parsed;
}
/* MGT */
static GstMpegTsAtscMGTTable *
_gst_mpegts_atsc_mgt_table_copy (GstMpegTsAtscMGTTable * mgt_table)
{
GstMpegTsAtscMGTTable *copy;
copy = g_slice_dup (GstMpegTsAtscMGTTable, mgt_table);
copy->descriptors = g_ptr_array_ref (mgt_table->descriptors);
return copy;
}
static void
_gst_mpegts_atsc_mgt_table_free (GstMpegTsAtscMGTTable * mgt_table)
{
g_ptr_array_unref (mgt_table->descriptors);
g_slice_free (GstMpegTsAtscMGTTable, mgt_table);
}
G_DEFINE_BOXED_TYPE (GstMpegTsAtscMGTTable, gst_mpegts_atsc_mgt_table,
(GBoxedCopyFunc) _gst_mpegts_atsc_mgt_table_copy,
(GFreeFunc) _gst_mpegts_atsc_mgt_table_free);
static GstMpegTsAtscMGT *
_gst_mpegts_atsc_mgt_copy (GstMpegTsAtscMGT * mgt)
{
GstMpegTsAtscMGT *copy;
copy = g_slice_dup (GstMpegTsAtscMGT, mgt);
copy->tables = g_ptr_array_ref (mgt->tables);
copy->descriptors = g_ptr_array_ref (mgt->descriptors);
return copy;
}
static void
_gst_mpegts_atsc_mgt_free (GstMpegTsAtscMGT * mgt)
{
g_ptr_array_unref (mgt->tables);
g_ptr_array_unref (mgt->descriptors);
g_slice_free (GstMpegTsAtscMGT, mgt);
}
G_DEFINE_BOXED_TYPE (GstMpegTsAtscMGT, gst_mpegts_atsc_mgt,
(GBoxedCopyFunc) _gst_mpegts_atsc_mgt_copy,
(GFreeFunc) _gst_mpegts_atsc_mgt_free);
static gpointer
_parse_atsc_mgt (GstMpegTsSection * section)
{
GstMpegTsAtscMGT *mgt = NULL;
guint i = 0;
guint8 *data, *end;
guint16 descriptors_loop_length;
mgt = g_slice_new0 (GstMpegTsAtscMGT);
data = section->data;
end = data + section->section_length;
/* Skip already parsed data */
data += 8;
mgt->protocol_version = GST_READ_UINT8 (data);
data += 1;
mgt->tables_defined = GST_READ_UINT16_BE (data);
data += 2;
mgt->tables = g_ptr_array_new_full (mgt->tables_defined,
(GDestroyNotify) _gst_mpegts_atsc_mgt_table_free);
for (i = 0; i < mgt->tables_defined && data + 11 < end; i++) {
GstMpegTsAtscMGTTable *mgt_table;
if (data + 11 >= end) {
GST_WARNING ("MGT data too short to parse inner table num %d", i);
goto error;
}
mgt_table = g_slice_new0 (GstMpegTsAtscMGTTable);
g_ptr_array_add (mgt->tables, mgt_table);
mgt_table->table_type = GST_READ_UINT16_BE (data);
data += 2;
mgt_table->pid = GST_READ_UINT16_BE (data) & 0x1FFF;
data += 2;
mgt_table->version_number = GST_READ_UINT8 (data) & 0x1F;
data += 1;
mgt_table->number_bytes = GST_READ_UINT32_BE (data);
data += 4;
descriptors_loop_length = GST_READ_UINT16_BE (data) & 0x0FFF;
data += 2;
if (data + descriptors_loop_length >= end) {
GST_WARNING ("MGT data too short to parse inner table descriptors (table "
"num %d", i);
goto error;
}
mgt_table->descriptors =
gst_mpegts_parse_descriptors (data, descriptors_loop_length);
data += descriptors_loop_length;
}
descriptors_loop_length = GST_READ_UINT16_BE (data) & 0xFFF;
data += 2;
if (data + descriptors_loop_length >= end) {
GST_WARNING ("MGT data too short to parse descriptors");
goto error;
}
mgt->descriptors =
gst_mpegts_parse_descriptors (data, descriptors_loop_length);
data += descriptors_loop_length;
return (gpointer) mgt;
error:
if (mgt)
_gst_mpegts_atsc_mgt_free (mgt);
return NULL;
}
/**
* gst_mpegts_section_get_atsc_mgt:
* @section: a #GstMpegTsSection of type %GST_MPEGTS_SECTION_ATSC_MGT
*
* Returns the #GstMpegTsAtscMGT contained in the @section.
*
* Returns: The #GstMpegTsAtscMGT contained in the section, or %NULL if an error
* happened.
*/
const GstMpegTsAtscMGT *
gst_mpegts_section_get_atsc_mgt (GstMpegTsSection * section)
{
g_return_val_if_fail (section->section_type == GST_MPEGTS_SECTION_ATSC_MGT,
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_atsc_mgt,
(GDestroyNotify) _gst_mpegts_atsc_mgt_free);
return (const GstMpegTsAtscMGT *) section->cached_parsed;
}

View file

@ -122,6 +122,53 @@ GType gst_mpegts_atsc_vct_source_get_type (void);
const GstMpegTsAtscVCT * gst_mpegts_section_get_atsc_tvct (GstMpegTsSection * section);
const GstMpegTsAtscVCT * gst_mpegts_section_get_atsc_cvct (GstMpegTsSection * section);
/* MGT */
#define GST_TYPE_MPEGTS_ATSC_MGT (gst_mpegts_atsc_mgt_get_type ())
#define GST_TYPE_MPEGTS_ATSC_MGT_TABLE (gst_mpegts_atsc_mgt_table_get_type ())
typedef struct _GstMpegTsAtscMGTTable GstMpegTsAtscMGTTable;
typedef struct _GstMpegTsAtscMGT GstMpegTsAtscMGT;
typedef enum {
GST_MPEG_TS_ATSC_MGT_TABLE_TYPE_EIT0 = 0x0100,
GST_MPEG_TS_ATSC_MGT_TABLE_TYPE_EIT127 = 0x017F,
GST_MPEG_TS_ATSC_MGT_TABLE_TYPE_ETT0 = 0x0200,
GST_MPEG_TS_ATSC_MGT_TABLE_TYPE_ETT127 = 0x027F
} GstMpegTsAtscMGTTableType;
/**
* GstMpegTsAtscMGTTable:
*
* Source from a @GstMpegTsAtscMGT
*/
struct _GstMpegTsAtscMGTTable
{
guint16 table_type;
guint16 pid;
guint8 version_number;
guint32 number_bytes;
GPtrArray *descriptors;
};
/**
* GstMpegTsAtscMGT:
*
* Terrestrial Virtual Channel Table (A65)
*
*/
struct _GstMpegTsAtscMGT
{
guint8 protocol_version;
guint16 tables_defined;
GPtrArray *tables;
GPtrArray *descriptors;
};
GType gst_mpegts_atsc_mgt_get_type (void);
GType gst_mpegts_atsc_mgt_table_get_type (void);
const GstMpegTsAtscMGT * gst_mpegts_section_get_atsc_mgt (GstMpegTsSection * section);
G_END_DECLS
#endif /* GST_MPEGTS_SECTION_H */

View file

@ -1056,6 +1056,13 @@ _identify_section (guint16 pid, guint8 table_id)
if (pid == 0x1ffb)
return GST_MPEGTS_SECTION_ATSC_CVCT;
break;
case GST_MTS_TABLE_ID_ATSC_MASTER_GUIDE:
if (pid == 0x1ffb)
return GST_MPEGTS_SECTION_ATSC_MGT;
break;
case GST_MTS_TABLE_ID_ATSC_EVENT_INFORMATION:
/* FIXME check pids reported on the MGT to confirm expectations */
return GST_MPEGTS_SECTION_EIT;
/* FIXME : FILL */
default:
/* Handle ranges */

View file

@ -53,6 +53,7 @@ GType gst_mpegts_section_get_type (void);
* @GST_MPEGTS_SECTION_TOT: Time Offset Table (EN 300 468)
* @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_MGT: ATSC Master Guide Table (A65)
*
* Types of #GstMpegTsSection that the library handles.
*/
@ -69,7 +70,8 @@ typedef enum {
GST_MPEGTS_SECTION_TDT,
GST_MPEGTS_SECTION_TOT,
GST_MPEGTS_SECTION_ATSC_TVCT,
GST_MPEGTS_SECTION_ATSC_CVCT
GST_MPEGTS_SECTION_ATSC_CVCT,
GST_MPEGTS_SECTION_ATSC_MGT
} GstMpegTsSectionType;
/**

View file

@ -702,6 +702,26 @@ dump_tot (GstMpegTsSection * section)
g_free (str);
}
static void
dump_mgt (GstMpegTsSection * section)
{
const GstMpegTsAtscMGT *mgt = gst_mpegts_section_get_atsc_mgt (section);
gint i;
g_printf (" protocol_version : %u\n", mgt->protocol_version);
g_printf (" tables number : %d\n", mgt->tables->len);
for (i = 0; i < mgt->tables->len; i++) {
GstMpegTsAtscMGTTable *table = g_ptr_array_index (mgt->tables, i);
g_printf (" table %d)\n", i);
g_printf (" table_type : %u\n", table->table_type);
g_printf (" pid : 0x%x\n", table->pid);
g_printf (" version_number: %u\n", table->version_number);
g_printf (" number_bytes : %u\n", table->number_bytes);
dump_descriptors (table->descriptors, 9);
}
dump_descriptors (mgt->descriptors, 7);
}
static void
dump_vct (GstMpegTsSection * section)
{
@ -773,6 +793,9 @@ dump_section (GstMpegTsSection * section)
case GST_MPEGTS_SECTION_EIT:
dump_eit (section);
break;
case GST_MPEGTS_SECTION_ATSC_MGT:
dump_mgt (section);
break;
case GST_MPEGTS_SECTION_ATSC_CVCT:
case GST_MPEGTS_SECTION_ATSC_TVCT:
dump_vct (section);