mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-26 19:51:11 +00:00
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:
parent
8f6a3c0a99
commit
9eed28d353
5 changed files with 226 additions and 1 deletions
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
|
||||
/**
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue