mpegts: Unify section checks and add BAT parsing

* Avoid repeating code everywhere, and instead provide all parsing
  information in one go.
* Add BAT support
* Refine BAT/CAT identification (by adding PID checks)
This commit is contained in:
Edward Hervey 2013-07-08 08:42:18 +02:00
parent 2fb7b87140
commit ae4d6bb334
4 changed files with 256 additions and 206 deletions

View File

@ -133,7 +133,7 @@ G_DEFINE_BOXED_TYPE (GstMpegTsEIT, gst_mpegts_eit,
(GBoxedCopyFunc) _gst_mpegts_eit_copy, (GFreeFunc) _gst_mpegts_eit_free); (GBoxedCopyFunc) _gst_mpegts_eit_copy, (GFreeFunc) _gst_mpegts_eit_free);
static GstMpegTsEIT * static gpointer
_parse_eit (GstMpegTsSection * section) _parse_eit (GstMpegTsSection * section)
{ {
GstMpegTsEIT *eit = NULL; GstMpegTsEIT *eit = NULL;
@ -141,13 +141,6 @@ _parse_eit (GstMpegTsSection * section)
guint8 *data, *end, *duration_ptr; guint8 *data, *end, *duration_ptr;
guint16 descriptors_loop_length; guint16 descriptors_loop_length;
/* fixed header + CRC == 16 */
if (section->section_length < 18) {
GST_WARNING ("PID %d invalid EIT size %d",
section->pid, section->section_length);
goto error;
}
eit = g_slice_new0 (GstMpegTsEIT); eit = g_slice_new0 (GstMpegTsEIT);
data = section->data; data = section->data;
@ -218,11 +211,11 @@ _parse_eit (GstMpegTsSection * section)
goto error; goto error;
} }
return eit; return (gpointer) eit;
error: error:
if (eit) if (eit)
gst_mpegts_section_unref (eit); _gst_mpegts_eit_free (eit);
return NULL; return NULL;
@ -243,32 +236,32 @@ gst_mpegts_section_get_eit (GstMpegTsSection * section)
g_return_val_if_fail (section->section_type == GST_MPEGTS_SECTION_EIT, NULL); g_return_val_if_fail (section->section_type == GST_MPEGTS_SECTION_EIT, NULL);
g_return_val_if_fail (section->cached_parsed || section->data, NULL); g_return_val_if_fail (section->cached_parsed || section->data, NULL);
if (!section->cached_parsed) { if (!section->cached_parsed)
if (G_UNLIKELY (_calc_crc32 (section->data, section->section_length) != 0)) section->cached_parsed = __common_desc_checks (section, 18, _parse_eit,
goto bad_crc; (GDestroyNotify) _gst_mpegts_eit_free);
section->cached_parsed = (gpointer) _parse_eit (section);
section->destroy_parsed = (GDestroyNotify) _gst_mpegts_eit_free;
if (section->cached_parsed == NULL)
goto parse_failure;
}
return (const GstMpegTsEIT *) section->cached_parsed; return (const GstMpegTsEIT *) section->cached_parsed;
bad_crc:
{
GST_WARNING ("Bad CRC on section");
return NULL;
}
parse_failure:
{
GST_WARNING ("Failure to parse section");
return NULL;
}
} }
/* Bouquet Association Table */ /* Bouquet Association Table */
static GstMpegTsBATStream *
_gst_mpegts_bat_stream_copy (GstMpegTsBATStream * bat)
{
/* FIXME : IMPLEMENT */
return NULL;
}
static void
_gst_mpegts_bat_stream_free (GstMpegTsBATStream * bat)
{
g_array_unref (bat->descriptors);
g_slice_free (GstMpegTsBATStream, bat);
}
G_DEFINE_BOXED_TYPE (GstMpegTsBATStream, gst_mpegts_bat_stream,
(GBoxedCopyFunc) _gst_mpegts_bat_stream_copy,
(GFreeFunc) _gst_mpegts_bat_stream_free);
static GstMpegTsBAT * static GstMpegTsBAT *
_gst_mpegts_bat_copy (GstMpegTsBAT * bat) _gst_mpegts_bat_copy (GstMpegTsBAT * bat)
{ {
@ -279,12 +272,143 @@ _gst_mpegts_bat_copy (GstMpegTsBAT * bat)
static void static void
_gst_mpegts_bat_free (GstMpegTsBAT * bat) _gst_mpegts_bat_free (GstMpegTsBAT * bat)
{ {
/* FIXME: IMPLEMENT */ g_array_unref (bat->descriptors);
g_ptr_array_unref (bat->streams);
g_slice_free (GstMpegTsBAT, bat);
} }
G_DEFINE_BOXED_TYPE (GstMpegTsBAT, gst_mpegts_bat, G_DEFINE_BOXED_TYPE (GstMpegTsBAT, gst_mpegts_bat,
(GBoxedCopyFunc) _gst_mpegts_bat_copy, (GFreeFunc) _gst_mpegts_bat_free); (GBoxedCopyFunc) _gst_mpegts_bat_copy, (GFreeFunc) _gst_mpegts_bat_free);
static gpointer
_parse_bat (GstMpegTsSection * section)
{
GstMpegTsBAT *bat = NULL;
guint i = 0, allocated_streams = 12;
guint8 *data, *end, *entry_begin;
guint16 descriptors_loop_length, transport_stream_loop_length;
GST_DEBUG ("BAT");
bat = g_slice_new0 (GstMpegTsBAT);
data = section->data;
end = data + section->section_length;
/* Skip already parsed data */
data += 8;
descriptors_loop_length = GST_READ_UINT16_BE (data) & 0x0FFF;
data += 2;
/* see if the buffer is large enough */
if (descriptors_loop_length && (data + descriptors_loop_length > end - 4)) {
GST_WARNING ("PID %d invalid BAT descriptors loop length %d",
section->pid, descriptors_loop_length);
goto error;
}
bat->descriptors =
gst_mpegts_parse_descriptors (data, descriptors_loop_length);
if (bat->descriptors == NULL)
goto error;
data += descriptors_loop_length;
transport_stream_loop_length = GST_READ_UINT16_BE (data) & 0x0FFF;
data += 2;
if (G_UNLIKELY (transport_stream_loop_length > (end - 4 - data))) {
GST_WARNING
("PID 0x%04x invalid BAT (transport_stream_loop_length too big)",
section->pid);
goto error;
}
bat->streams =
g_ptr_array_new_full (allocated_streams,
(GDestroyNotify) _gst_mpegts_bat_stream_free);
/* read up to the CRC */
while (transport_stream_loop_length - 4 > 0) {
GstMpegTsBATStream *stream = g_slice_new0 (GstMpegTsBATStream);
g_ptr_array_add (bat->streams, stream);
if (transport_stream_loop_length < 6) {
/* each entry must be at least 6 bytes (+ 4bytes CRC) */
GST_WARNING ("PID %d invalid BAT entry size %d",
section->pid, transport_stream_loop_length);
goto error;
}
entry_begin = data;
stream->transport_stream_id = GST_READ_UINT16_BE (data);
data += 2;
stream->original_network_id = GST_READ_UINT16_BE (data);
data += 2;
descriptors_loop_length = GST_READ_UINT16_BE (data) & 0x0FFF;
data += 2;
GST_DEBUG ("descriptors_loop_length %d", descriptors_loop_length);
if (descriptors_loop_length && (data + descriptors_loop_length > end - 4)) {
GST_WARNING
("PID %d invalid BAT entry %d descriptors loop length %d (only have %"
G_GSIZE_FORMAT ")", section->pid, section->subtable_extension,
descriptors_loop_length, end - 4 - data);
goto error;
}
stream->descriptors =
gst_mpegts_parse_descriptors (data, descriptors_loop_length);
if (stream->descriptors == NULL)
goto error;
data += descriptors_loop_length;
i += 1;
transport_stream_loop_length -= data - entry_begin;
}
if (data != end - 4) {
GST_WARNING ("PID %d invalid BAT parsed %d length %d",
section->pid, (gint) (data - section->data), section->section_length);
goto error;
}
return (gpointer) bat;
error:
if (bat)
_gst_mpegts_bat_free (bat);
return NULL;
}
/**
* gst_mpegts_section_get_bat:
* @section: a #GstMpegTsSection of type %GST_MPEGTS_SECTION_BAT
*
* Returns the #GstMpegTsBAT contained in the @section.
*
* Returns: The #GstMpegTsBAT contained in the section, or %NULL if an error
* happened.
*/
const GstMpegTsBAT *
gst_mpegts_section_get_bat (GstMpegTsSection * section)
{
g_return_val_if_fail (section->section_type == GST_MPEGTS_SECTION_BAT, NULL);
g_return_val_if_fail (section->cached_parsed || section->data, NULL);
if (!section->cached_parsed)
section->cached_parsed =
__common_desc_checks (section, 16, _parse_bat,
(GDestroyNotify) _gst_mpegts_bat_free);
return (const GstMpegTsBAT *) section->cached_parsed;
}
/* Network Information Table */ /* Network Information Table */
static GstMpegTsNITStream * static GstMpegTsNITStream *
@ -324,7 +448,7 @@ G_DEFINE_BOXED_TYPE (GstMpegTsNIT, gst_mpegts_nit,
(GBoxedCopyFunc) _gst_mpegts_nit_copy, (GFreeFunc) _gst_mpegts_nit_free); (GBoxedCopyFunc) _gst_mpegts_nit_copy, (GFreeFunc) _gst_mpegts_nit_free);
static GstMpegTsNIT * static gpointer
_parse_nit (GstMpegTsSection * section) _parse_nit (GstMpegTsSection * section)
{ {
GstMpegTsNIT *nit = NULL; GstMpegTsNIT *nit = NULL;
@ -334,13 +458,6 @@ _parse_nit (GstMpegTsSection * section)
GST_DEBUG ("NIT"); GST_DEBUG ("NIT");
/* fixed header (no streams) + CRC == 16 */
if (section->section_length < 16) {
GST_WARNING ("PID %d invalid NIT size %d",
section->pid, section->section_length);
goto error;
}
nit = g_slice_new0 (GstMpegTsNIT); nit = g_slice_new0 (GstMpegTsNIT);
data = section->data; data = section->data;
@ -429,11 +546,11 @@ _parse_nit (GstMpegTsSection * section)
goto error; goto error;
} }
return nit; return (gpointer) nit;
error: error:
if (nit) if (nit)
gst_mpegts_section_unref (nit); _gst_mpegts_nit_free (nit);
return NULL; return NULL;
} }
@ -453,29 +570,12 @@ gst_mpegts_section_get_nit (GstMpegTsSection * section)
g_return_val_if_fail (section->section_type == GST_MPEGTS_SECTION_NIT, NULL); g_return_val_if_fail (section->section_type == GST_MPEGTS_SECTION_NIT, NULL);
g_return_val_if_fail (section->cached_parsed || section->data, NULL); g_return_val_if_fail (section->cached_parsed || section->data, NULL);
if (!section->cached_parsed) { if (!section->cached_parsed)
if (G_UNLIKELY (_calc_crc32 (section->data, section->section_length) != 0)) section->cached_parsed =
goto bad_crc; __common_desc_checks (section, 16, _parse_nit,
(GDestroyNotify) _gst_mpegts_nit_free);
section->cached_parsed = (gpointer) _parse_nit (section);
section->destroy_parsed = (GDestroyNotify) _gst_mpegts_nit_free;
if (section->cached_parsed == NULL)
goto parse_failure;
}
return (const GstMpegTsNIT *) section->cached_parsed; return (const GstMpegTsNIT *) section->cached_parsed;
bad_crc:
{
GST_WARNING ("Bad CRC on section");
return NULL;
}
parse_failure:
{
GST_WARNING ("Failure to parse section");
return NULL;
}
} }
@ -517,7 +617,7 @@ G_DEFINE_BOXED_TYPE (GstMpegTsSDT, gst_mpegts_sdt,
(GBoxedCopyFunc) _gst_mpegts_sdt_copy, (GFreeFunc) _gst_mpegts_sdt_free); (GBoxedCopyFunc) _gst_mpegts_sdt_copy, (GFreeFunc) _gst_mpegts_sdt_free);
static GstMpegTsSDT * static gpointer
_parse_sdt (GstMpegTsSection * section) _parse_sdt (GstMpegTsSection * section)
{ {
GstMpegTsSDT *sdt = NULL; GstMpegTsSDT *sdt = NULL;
@ -529,13 +629,6 @@ _parse_sdt (GstMpegTsSection * section)
GST_DEBUG ("SDT"); GST_DEBUG ("SDT");
/* fixed header + CRC == 16 */
if (section->section_length < 14) {
GST_WARNING ("PID %d invalid SDT size %d",
section->pid, section->section_length);
goto error;
}
sdt = g_slice_new0 (GstMpegTsSDT); sdt = g_slice_new0 (GstMpegTsSDT);
data = section->data; data = section->data;
@ -564,7 +657,7 @@ _parse_sdt (GstMpegTsSection * section)
entry_begin = data; entry_begin = data;
if (sdt_info_length < 9) { if (sdt_info_length + 5 < 4) {
/* each entry must be at least 5 bytes (+4 bytes for the CRC) */ /* each entry must be at least 5 bytes (+4 bytes for the CRC) */
GST_WARNING ("PID %d invalid SDT entry size %d", GST_WARNING ("PID %d invalid SDT entry size %d",
section->pid, sdt_info_length); section->pid, sdt_info_length);
@ -631,37 +724,19 @@ gst_mpegts_section_get_sdt (GstMpegTsSection * section)
g_return_val_if_fail (section->section_type == GST_MPEGTS_SECTION_SDT, NULL); g_return_val_if_fail (section->section_type == GST_MPEGTS_SECTION_SDT, NULL);
g_return_val_if_fail (section->cached_parsed || section->data, NULL); g_return_val_if_fail (section->cached_parsed || section->data, NULL);
if (!section->cached_parsed) { if (!section->cached_parsed)
if (G_UNLIKELY (_calc_crc32 (section->data, section->section_length) != 0)) section->cached_parsed =
goto bad_crc; __common_desc_checks (section, 15, _parse_sdt,
(GDestroyNotify) _gst_mpegts_sdt_free);
section->cached_parsed = (gpointer) _parse_sdt (section);
section->destroy_parsed = (GDestroyNotify) _gst_mpegts_sdt_free;
if (section->cached_parsed == NULL)
goto parse_failure;
}
return (const GstMpegTsSDT *) section->cached_parsed; return (const GstMpegTsSDT *) section->cached_parsed;
bad_crc:
{
GST_WARNING ("Bad CRC on section");
return NULL;
}
parse_failure:
{
GST_WARNING ("Failure to parse section");
return NULL;
}
} }
/* Time and Date Table (TDT) */ /* Time and Date Table (TDT) */
static GstDateTime * static gpointer
_parse_tdt (GstMpegTsSection * section) _parse_tdt (GstMpegTsSection * section)
{ {
/* FIXME : Add length check */ return (gpointer) _parse_utc_time (section->data + 3);
return _parse_utc_time (section->data + 3);
} }
/** /**
@ -679,20 +754,14 @@ gst_mpegts_section_get_tdt (GstMpegTsSection * section)
g_return_val_if_fail (section->section_type == GST_MPEGTS_SECTION_TDT, NULL); g_return_val_if_fail (section->section_type == GST_MPEGTS_SECTION_TDT, NULL);
g_return_val_if_fail (section->cached_parsed || section->data, NULL); g_return_val_if_fail (section->cached_parsed || section->data, NULL);
if (!section->cached_parsed) { if (!section->cached_parsed)
section->cached_parsed = (gpointer) _parse_tdt (section); section->cached_parsed =
section->destroy_parsed = (GDestroyNotify) gst_date_time_unref; __common_desc_checks (section, 8, _parse_tdt,
if (section->cached_parsed == NULL) (GDestroyNotify) gst_date_time_unref);
goto parse_failure;
}
return gst_date_time_ref ((GstDateTime *) section->cached_parsed); if (section->cached_parsed)
return gst_date_time_ref ((GstDateTime *) section->cached_parsed);
parse_failure: return NULL;
{
GST_WARNING ("Failure to parse section");
return NULL;
}
} }
@ -716,15 +785,13 @@ _gst_mpegts_tot_free (GstMpegTsTOT * tot)
G_DEFINE_BOXED_TYPE (GstMpegTsTOT, gst_mpegts_tot, G_DEFINE_BOXED_TYPE (GstMpegTsTOT, gst_mpegts_tot,
(GBoxedCopyFunc) _gst_mpegts_tot_copy, (GFreeFunc) _gst_mpegts_tot_free); (GBoxedCopyFunc) _gst_mpegts_tot_copy, (GFreeFunc) _gst_mpegts_tot_free);
static GstMpegTsTOT * static gpointer
_parse_tot (GstMpegTsSection * section) _parse_tot (GstMpegTsSection * section)
{ {
guint8 *data; guint8 *data;
GstMpegTsTOT *tot; GstMpegTsTOT *tot;
guint16 desc_len; guint16 desc_len;
/* FIXME : Check minimum length */
GST_DEBUG ("TOT"); GST_DEBUG ("TOT");
tot = g_slice_new0 (GstMpegTsTOT); tot = g_slice_new0 (GstMpegTsTOT);
@ -738,7 +805,7 @@ _parse_tot (GstMpegTsSection * section)
data += 2; data += 2;
tot->descriptors = gst_mpegts_parse_descriptors (data, desc_len); tot->descriptors = gst_mpegts_parse_descriptors (data, desc_len);
return tot; return (gpointer) tot;
} }
/** /**
@ -756,27 +823,10 @@ gst_mpegts_section_get_tot (GstMpegTsSection * section)
g_return_val_if_fail (section->section_type == GST_MPEGTS_SECTION_TOT, NULL); g_return_val_if_fail (section->section_type == GST_MPEGTS_SECTION_TOT, NULL);
g_return_val_if_fail (section->cached_parsed || section->data, NULL); g_return_val_if_fail (section->cached_parsed || section->data, NULL);
if (!section->cached_parsed) { if (!section->cached_parsed)
if (G_UNLIKELY (_calc_crc32 (section->data, section->section_length) != 0)) section->cached_parsed =
goto bad_crc; __common_desc_checks (section, 14, _parse_tot,
(GDestroyNotify) _gst_mpegts_tot_free);
section->cached_parsed = (gpointer) _parse_tot (section);
section->destroy_parsed = (GDestroyNotify) _gst_mpegts_tot_free;
if (section->cached_parsed == NULL)
goto parse_failure;
}
return (const GstMpegTsTOT *) section->cached_parsed; return (const GstMpegTsTOT *) section->cached_parsed;
bad_crc:
{
GST_WARNING ("Bad CRC on section");
return NULL;
}
parse_failure:
{
GST_WARNING ("Failure to parse section");
return NULL;
}
} }

View File

@ -171,6 +171,7 @@ typedef struct _GstMpegTsBATStream GstMpegTsBATStream;
typedef struct _GstMpegTsBAT GstMpegTsBAT; typedef struct _GstMpegTsBAT GstMpegTsBAT;
#define GST_TYPE_MPEGTS_BAT (gst_mpegts_bat_get_type()) #define GST_TYPE_MPEGTS_BAT (gst_mpegts_bat_get_type())
#define GST_TYPE_MPEGTS_BAT_STREAM (gst_mpegts_bat_get_type())
struct _GstMpegTsBATStream struct _GstMpegTsBATStream
{ {
@ -195,6 +196,9 @@ struct _GstMpegTsBAT
}; };
GType gst_mpegts_bat_get_type (void); GType gst_mpegts_bat_get_type (void);
GType gst_mpegts_bat_stream_get_type (void);
const GstMpegTsBAT *gst_mpegts_section_get_bat (GstMpegTsSection *section);
/* SDT */ /* SDT */
#define GST_TYPE_MPEGTS_SDT (gst_mpegts_sdt_get_type()) #define GST_TYPE_MPEGTS_SDT (gst_mpegts_sdt_get_type())

View File

@ -31,4 +31,10 @@ G_GNUC_INTERNAL void __initialize_descriptors (void);
G_GNUC_INTERNAL guint32 _calc_crc32 (const guint8 *data, guint datalen); G_GNUC_INTERNAL guint32 _calc_crc32 (const guint8 *data, guint datalen);
G_GNUC_INTERNAL gchar *get_encoding_and_convert (const gchar *text, guint length); G_GNUC_INTERNAL gchar *get_encoding_and_convert (const gchar *text, guint length);
typedef gpointer (*GstMpegTsParseFunc) (GstMpegTsSection *section);
G_GNUC_INTERNAL gpointer __common_desc_checks (GstMpegTsSection *section,
guint minsize,
GstMpegTsParseFunc parsefunc,
GDestroyNotify destroynotify);
#endif /* _GST_MPEGTS_PRIVATE_H_ */ #endif /* _GST_MPEGTS_PRIVATE_H_ */

View File

@ -149,6 +149,37 @@ _calc_crc32 (const guint8 * data, guint datalen)
return crc; return crc;
} }
gpointer
__common_desc_checks (GstMpegTsSection * section, guint min_size,
GstMpegTsParseFunc parsefunc, GDestroyNotify destroynotify)
{
gpointer res;
/* Check section is big enough */
if (section->section_length < min_size) {
GST_WARNING
("PID:0x%04x table_id:0x%02x, section too small (Got %d, need at least %d)",
section->pid, section->table_id, section->section_length, min_size);
return NULL;
}
/* If section has a CRC, check it */
if (!section->short_section
&& (_calc_crc32 (section->data, section->section_length) != 0)) {
GST_WARNING ("PID:0x%04x table_id:0x%02x, Bad CRC on section", section->pid,
section->table_id);
return NULL;
}
/* Finally parse and set the destroy notify */
res = parsefunc (section);
if (res == NULL)
GST_WARNING ("PID:0x%04x table_id:0x%02x, Failed to parse section",
section->pid, section->table_id);
else
section->destroy_parsed = destroynotify;
return res;
}
/* /*
@ -287,7 +318,7 @@ gst_message_new_mpegts_section (GstObject * parent, GstMpegTsSection * section)
/* Program Association Table */ /* Program Association Table */
static GArray * static gpointer
_parse_pat (GstMpegTsSection * section) _parse_pat (GstMpegTsSection * section)
{ {
GArray *pat; GArray *pat;
@ -326,7 +357,7 @@ _parse_pat (GstMpegTsSection * section)
return NULL; return NULL;
} }
return pat; return (gpointer) pat;
} }
/** /**
@ -350,29 +381,14 @@ gst_mpegts_section_get_pat (GstMpegTsSection * section)
g_return_val_if_fail (section->section_type == GST_MPEGTS_SECTION_PAT, NULL); g_return_val_if_fail (section->section_type == GST_MPEGTS_SECTION_PAT, NULL);
g_return_val_if_fail (section->cached_parsed || section->data, NULL); g_return_val_if_fail (section->cached_parsed || section->data, NULL);
if (!section->cached_parsed) { if (!section->cached_parsed)
if (G_UNLIKELY (_calc_crc32 (section->data, section->section_length) != 0)) section->cached_parsed =
goto bad_crc; __common_desc_checks (section, 12, _parse_pat,
(GDestroyNotify) g_array_unref);
section->cached_parsed = (gpointer) _parse_pat (section); if (section->cached_parsed)
section->destroy_parsed = (GDestroyNotify) g_array_unref; return g_array_ref ((GArray *) section->cached_parsed);
if (section->cached_parsed == NULL) return NULL;
goto parse_failure;
}
return g_array_ref ((GArray *) section->cached_parsed);
bad_crc:
{
GST_WARNING ("Bad CRC on section");
return NULL;
}
parse_failure:
{
GST_WARNING ("Failure to parse section");
return NULL;
}
} }
@ -415,7 +431,7 @@ G_DEFINE_BOXED_TYPE (GstMpegTsPMT, gst_mpegts_pmt,
(GBoxedCopyFunc) _gst_mpegts_pmt_copy, (GFreeFunc) _gst_mpegts_pmt_free); (GBoxedCopyFunc) _gst_mpegts_pmt_copy, (GFreeFunc) _gst_mpegts_pmt_free);
static GstMpegTsPMT * static gpointer
_parse_pmt (GstMpegTsSection * section) _parse_pmt (GstMpegTsSection * section)
{ {
GstMpegTsPMT *pmt = NULL; GstMpegTsPMT *pmt = NULL;
@ -424,13 +440,6 @@ _parse_pmt (GstMpegTsSection * section)
guint program_info_length; guint program_info_length;
guint stream_info_length; guint stream_info_length;
/* fixed header + CRC == 16 */
if (section->section_length < 16) {
GST_WARNING ("PID %d invalid PMT size %d",
section->pid, section->section_length);
goto error;
}
pmt = g_slice_new0 (GstMpegTsPMT); pmt = g_slice_new0 (GstMpegTsPMT);
data = section->data; data = section->data;
@ -496,11 +505,11 @@ _parse_pmt (GstMpegTsSection * section)
g_assert (data == end - 4); g_assert (data == end - 4);
return pmt; return (gpointer) pmt;
error: error:
if (pmt) if (pmt)
gst_mpegts_section_unref (pmt); _gst_mpegts_pmt_free (pmt);
return NULL; return NULL;
} }
@ -520,34 +529,17 @@ gst_mpegts_section_get_pmt (GstMpegTsSection * section)
g_return_val_if_fail (section->section_type == GST_MPEGTS_SECTION_PMT, NULL); g_return_val_if_fail (section->section_type == GST_MPEGTS_SECTION_PMT, NULL);
g_return_val_if_fail (section->cached_parsed || section->data, NULL); g_return_val_if_fail (section->cached_parsed || section->data, NULL);
if (!section->cached_parsed) { if (!section->cached_parsed)
if (G_UNLIKELY (_calc_crc32 (section->data, section->section_length) != 0)) section->cached_parsed =
goto bad_crc; __common_desc_checks (section, 16, _parse_pmt,
(GDestroyNotify) _gst_mpegts_pmt_free);
section->cached_parsed = (gpointer) _parse_pmt (section);
section->destroy_parsed = (GDestroyNotify) _gst_mpegts_pmt_free;
if (section->cached_parsed == NULL)
goto parse_failure;
}
return (const GstMpegTsPMT *) section->cached_parsed; return (const GstMpegTsPMT *) section->cached_parsed;
bad_crc:
{
GST_WARNING ("Bad CRC on section");
return NULL;
}
parse_failure:
{
GST_WARNING ("Failure to parse section");
return NULL;
}
} }
/* Conditional Access Table */ /* Conditional Access Table */
static GArray * static gpointer
_parse_cat (GstMpegTsSection * section) _parse_cat (GstMpegTsSection * section)
{ {
guint8 *data; guint8 *data;
@ -558,7 +550,7 @@ _parse_cat (GstMpegTsSection * section)
/* descriptors */ /* descriptors */
desc_len = section->section_length - 4 - 8; desc_len = section->section_length - 4 - 8;
return gst_mpegts_parse_descriptors (data, desc_len); return (gpointer) gst_mpegts_parse_descriptors (data, desc_len);
} }
/** /**
@ -578,20 +570,14 @@ gst_mpegts_section_get_cat (GstMpegTsSection * section)
g_return_val_if_fail (section->section_type == GST_MPEGTS_SECTION_CAT, NULL); g_return_val_if_fail (section->section_type == GST_MPEGTS_SECTION_CAT, NULL);
g_return_val_if_fail (section->cached_parsed || section->data, NULL); g_return_val_if_fail (section->cached_parsed || section->data, NULL);
if (!section->cached_parsed) { if (!section->cached_parsed)
section->cached_parsed = (gpointer) _parse_cat (section); section->cached_parsed =
section->destroy_parsed = (GDestroyNotify) g_array_unref; __common_desc_checks (section, 12, _parse_cat,
if (section->cached_parsed == NULL) (GDestroyNotify) g_array_unref);
goto parse_failure;
}
return g_array_ref ((GArray *) section->cached_parsed); if (section->cached_parsed)
return g_array_ref ((GArray *) section->cached_parsed);
parse_failure: return NULL;
{
GST_WARNING ("Failure to parse section");
return NULL;
}
} }
/* Transport Stream Description Table (TSDT) */ /* Transport Stream Description Table (TSDT) */
@ -662,11 +648,15 @@ _identify_section (guint16 pid, guint8 table_id)
return GST_MPEGTS_SECTION_PAT; return GST_MPEGTS_SECTION_PAT;
break; break;
case GST_MTS_TABLE_ID_CONDITIONAL_ACCESS: case GST_MTS_TABLE_ID_CONDITIONAL_ACCESS:
return GST_MPEGTS_SECTION_CAT; if (pid == 0x01)
return GST_MPEGTS_SECTION_CAT;
break;
case GST_MTS_TABLE_ID_TS_PROGRAM_MAP: case GST_MTS_TABLE_ID_TS_PROGRAM_MAP:
return GST_MPEGTS_SECTION_PMT; return GST_MPEGTS_SECTION_PMT;
case GST_MTS_TABLE_ID_BOUQUET_ASSOCIATION: case GST_MTS_TABLE_ID_BOUQUET_ASSOCIATION:
return GST_MPEGTS_SECTION_BAT; if (pid == 0x0011)
return GST_MPEGTS_SECTION_BAT;
break;
case GST_MTS_TABLE_ID_NETWORK_INFORMATION_ACTUAL_NETWORK: case GST_MTS_TABLE_ID_NETWORK_INFORMATION_ACTUAL_NETWORK:
case GST_MTS_TABLE_ID_NETWORK_INFORMATION_OTHER_NETWORK: case GST_MTS_TABLE_ID_NETWORK_INFORMATION_OTHER_NETWORK:
if (pid == 0x0010) if (pid == 0x0010)