diff options
author | Alessandro Decina <alessandro@nnva.org> | 2007-11-23 17:53:37 +0000 |
---|---|---|
committer | Zaheer Abbas Merali <zaheerabbas@merali.org> | 2007-11-23 17:53:37 +0000 |
commit | 50841996be64a7b4697d3e30a45ca68db459762e (patch) | |
tree | 6a3b09a46b1cbe30ac009743bb50799077502871 /gst/mpegtsparse | |
parent | 1cb35c75741314f40f098250108b1b0e7db643cc (diff) | |
download | gst-plugins-bad-50841996be64a7b4697d3e30a45ca68db459762e.tar.gz gst-plugins-bad-50841996be64a7b4697d3e30a45ca68db459762e.tar.bz2 gst-plugins-bad-50841996be64a7b4697d3e30a45ca68db459762e.zip |
gst/mpegtsparse/: pat-info is now a signal not a GObject property that gets notified.
Original commit message from CVS:
patch by: Alessandro Decina
* gst/mpegtsparse/mpegtspacketizer.c:
* gst/mpegtsparse/mpegtspacketizer.h:
* gst/mpegtsparse/mpegtsparse.c:
* gst/mpegtsparse/mpegtsparse.h:
pat-info is now a signal not a GObject property that
gets notified.
pat-info, pmt-info now instead of passing a GObject as
a parameter, pass a GstStructure.
New signals: nit-info, sdt-info, eit-info for DVB SI information
* sys/dvb/camconditionalaccess.c:
* sys/dvb/camconditionalaccess.h:
* sys/dvb/camdevice.c:
* sys/dvb/camdevice.h:
* sys/dvb/camswclient.c:
* sys/dvb/camswclient.h:
* sys/dvb/camutils.c:
* sys/dvb/camutils.h:
Cam code now uses the pmt GstStructure passed from mpegtsparse
signals rather than the GObject.
* sys/dvb/dvbbasebin.c:
Use new signals in mpegtsparse and use GstStructures as per
mpegtsparse's modified API.
Diffstat (limited to 'gst/mpegtsparse')
-rw-r--r-- | gst/mpegtsparse/mpegtspacketizer.c | 659 | ||||
-rw-r--r-- | gst/mpegtsparse/mpegtspacketizer.h | 10 | ||||
-rw-r--r-- | gst/mpegtsparse/mpegtsparse.c | 256 | ||||
-rw-r--r-- | gst/mpegtsparse/mpegtsparse.h | 8 |
4 files changed, 786 insertions, 147 deletions
diff --git a/gst/mpegtsparse/mpegtspacketizer.c b/gst/mpegtsparse/mpegtspacketizer.c index 1aac7991..af759eeb 100644 --- a/gst/mpegtsparse/mpegtspacketizer.c +++ b/gst/mpegtsparse/mpegtspacketizer.c @@ -22,8 +22,6 @@ */ #include "mpegtspacketizer.h" -#include "flutspatinfo.h" -#include "flutspmtinfo.h" GST_DEBUG_CATEGORY_STATIC (mpegts_packetizer_debug); #define GST_CAT_DEFAULT mpegts_packetizer_debug @@ -139,7 +137,8 @@ mpegts_packetizer_parse_adaptation_field_control (MpegTSPacketizer * packetizer, { guint8 length; - length = *packet->data++; + length = *packet->data; + packet->data += 1; if (packet->adaptation_field_control == 0x02) { /* no payload, adaptation field of 183 bytes */ @@ -154,8 +153,9 @@ mpegts_packetizer_parse_adaptation_field_control (MpegTSPacketizer * packetizer, /* skip the adaptation field body for now */ if (packet->data + length > packet->data_end) { - GST_DEBUG ("PID %d afc length overflows the buffer %d", - packet->pid, length); + GST_DEBUG ("PID %d afc length %d overflows the buffer current %d max %d", + packet->pid, length, packet->data - packet->data_start, + packet->data_end - packet->data_start); return FALSE; } @@ -178,7 +178,7 @@ mpegts_packetizer_parse_packet (MpegTSPacketizer * packetizer, packet->pid = GST_READ_UINT16_BE (data) & 0x1FFF; data += 2; - packet->adaptation_field_control = *data >> 4 & 0x03; + packet->adaptation_field_control = (*data >> 4) & 0x03; packet->continuity_counter = *data & 0x0F; data += 1; @@ -236,21 +236,66 @@ not_applicable: return TRUE; } -GValueArray * +static gboolean +mpegts_packetizer_parse_descriptors (MpegTSPacketizer * packetizer, + guint8 ** buffer, guint8 * buffer_end, GValueArray * descriptors) +{ + guint8 tag, length; + guint8 *data; + GValue value = { 0 }; + GString *desc; + + data = *buffer; + + while (data < buffer_end) { + tag = *data++; + length = *data++; + + if (data + length > buffer_end) { + GST_WARNING ("invalid descriptor length %d now at %d max %d", + length, data - *buffer, buffer_end - *buffer); + goto error; + } + + /* include tag and length */ + desc = g_string_new_len ((gchar *) data - 2, length + 2); + data += length; + + g_value_init (&value, G_TYPE_GSTRING); + g_value_take_boxed (&value, desc); + g_value_array_append (descriptors, &value); + g_value_unset (&value); + } + + if (data != buffer_end) { + GST_WARNING ("descriptors size %d expected %d", + data - *buffer, buffer_end - *buffer); + goto error; + } + + *buffer = data; + + return TRUE; +error: + return FALSE; +} + +GstStructure * mpegts_packetizer_parse_pat (MpegTSPacketizer * packetizer, MpegTSPacketizerSection * section) { + GstStructure *pat_info = NULL; guint8 *data, *end; - guint16 transport_stream_id; + guint transport_stream_id; guint8 tmp; guint program_number; - guint16 pmt_pid; - MpegTSPatInfo *info; - GValueArray *pat; + guint pmt_pid; + GValue entries = { 0 }; GValue value = { 0 }; + GstStructure *entry = NULL; + gchar *struct_name; data = GST_BUFFER_DATA (section->buffer); - pat = g_value_array_new (0); section->table_id = *data++; section->section_length = GST_READ_UINT16_BE (data) & 0x0FFF; @@ -266,6 +311,9 @@ mpegts_packetizer_parse_pat (MpegTSPacketizer * packetizer, /* skip section_number and last_section_number */ data += 2; + pat_info = gst_structure_new ("pat", + "transport-stream-id", G_TYPE_UINT, transport_stream_id, NULL); + g_value_init (&entries, GST_TYPE_LIST); /* stop at the CRC */ end = GST_BUFFER_DATA (section->buffer) + GST_BUFFER_SIZE (section->buffer); while (data < end - 4) { @@ -275,40 +323,50 @@ mpegts_packetizer_parse_pat (MpegTSPacketizer * packetizer, pmt_pid = GST_READ_UINT16_BE (data) & 0x1FFF; data += 2; - info = mpegts_pat_info_new (program_number, pmt_pid); + struct_name = g_strdup_printf ("program-%d", program_number); + entry = gst_structure_new (struct_name, + "program-number", G_TYPE_UINT, program_number, + "pid", G_TYPE_UINT, pmt_pid, NULL); + g_free (struct_name); - g_value_init (&value, G_TYPE_OBJECT); - g_value_take_object (&value, info); - g_value_array_append (pat, &value); + g_value_init (&value, GST_TYPE_STRUCTURE); + g_value_take_boxed (&value, entry); + gst_value_list_append_value (&entries, &value); g_value_unset (&value); } + gst_structure_set_value (pat_info, "programs", &entries); + g_value_unset (&entries); + if (data != end - 4) { /* FIXME: check the CRC before parsing the packet */ GST_ERROR ("at the end of PAT data != end - 4"); - g_value_array_free (pat); + gst_structure_free (pat_info); return NULL; } - return pat; + return pat_info; } -GObject * +GstStructure * mpegts_packetizer_parse_pmt (MpegTSPacketizer * packetizer, MpegTSPacketizerSection * section) { - MpegTSPmtInfo *pmt = NULL; - MpegTSPmtStreamInfo *stream_info; + GstStructure *pmt = NULL; guint8 *data, *end; guint16 program_number; guint8 tmp; - guint16 pcr_pid; + guint pcr_pid; guint program_info_length; - guint8 tag, length; guint8 stream_type; guint16 pid; guint stream_info_length; + GValueArray *descriptors; + GValue stream_value = { 0 }; + GValue programs = { 0 }; + GstStructure *stream_info = NULL; + gchar *struct_name; /* fixed header + CRC == 16 */ if (GST_BUFFER_SIZE (section->buffer) < 16) { @@ -340,35 +398,35 @@ mpegts_packetizer_parse_pmt (MpegTSPacketizer * packetizer, program_info_length = GST_READ_UINT16_BE (data) & 0x0FFF; data += 2; - /* check that the buffer is large enough to contain at least - * program_info_length bytes + CRC */ - if (data + program_info_length + 4 > end) { - GST_WARNING ("PID %d invalid program info length %d " - "left %d", section->pid, program_info_length, end - data); - goto error; - } - - pmt = mpegts_pmt_info_new (program_number, pcr_pid, section->version_number); - - /* parse program level descriptors */ - while (program_info_length > 0) { - tag = *data++; - length = *data++; - program_info_length -= 2; + struct_name = g_strdup_printf ("program-%d", program_number); + pmt = gst_structure_new (struct_name, + "program-number", G_TYPE_UINT, program_number, + "pcr-pid", G_TYPE_UINT, pcr_pid, + "version-number", G_TYPE_UINT, section->version_number, NULL); + g_free (struct_name); + + if (program_info_length) { + /* check that the buffer is large enough to contain at least + * program_info_length bytes + CRC */ + if (data + program_info_length + 4 > end) { + GST_WARNING ("PID %d invalid program info length %d " + "left %d", section->pid, program_info_length, end - data); + goto error; + } - if (length > program_info_length) { - GST_WARNING ("PID %d invalid descriptor length %d left %d", - section->pid, length, program_info_length); + descriptors = g_value_array_new (0); + if (!mpegts_packetizer_parse_descriptors (packetizer, + &data, data + program_info_length, descriptors)) { + g_value_array_free (descriptors); goto error; } - mpegts_pmt_info_add_descriptor (pmt, (const gchar *) data - 2, 2 + length); - data += length; - program_info_length -= length; + gst_structure_set (pmt, "descriptors", G_TYPE_VALUE_ARRAY, descriptors, + NULL); + g_value_array_free (descriptors); } - g_assert (program_info_length == 0); - + g_value_init (&programs, GST_TYPE_LIST); /* parse entries, cycle until there's space for another entry (at least 5 * bytes) plus the CRC */ while (data <= end - 4 - 5) { @@ -383,45 +441,507 @@ mpegts_packetizer_parse_pmt (MpegTSPacketizer * packetizer, if (data + stream_info_length + 4 > end) { GST_WARNING ("PID %d invalid stream info length %d " "left %d", section->pid, stream_info_length, end - data); + g_value_unset (&programs); + goto error; + } + + struct_name = g_strdup_printf ("pid-%d", pid); + stream_info = gst_structure_new (struct_name, + "pid", G_TYPE_UINT, pid, "stream-type", G_TYPE_UINT, stream_type, NULL); + g_free (struct_name); + + if (stream_info_length) { + descriptors = g_value_array_new (0); + if (!mpegts_packetizer_parse_descriptors (packetizer, + &data, data + stream_info_length, descriptors)) { + g_value_unset (&programs); + gst_structure_free (stream_info); + g_value_array_free (descriptors); + goto error; + } + + gst_structure_set (stream_info, + "descriptors", G_TYPE_VALUE_ARRAY, descriptors, NULL); + g_value_array_free (descriptors); + } + + g_value_init (&stream_value, GST_TYPE_STRUCTURE); + g_value_take_boxed (&stream_value, stream_info); + gst_value_list_append_value (&programs, &stream_value); + g_value_unset (&stream_value); + } + + gst_structure_set_value (pmt, "streams", &programs); + g_value_unset (&programs); + + g_assert (data == end - 4); + + return pmt; + +error: + if (pmt) + gst_structure_free (pmt); + + return NULL; +} + +GstStructure * +mpegts_packetizer_parse_nit (MpegTSPacketizer * packetizer, + MpegTSPacketizerSection * section) +{ + GstStructure *nit = NULL, *transport = NULL; + guint8 *data, *end, *entry_begin; + guint16 network_id, transport_stream_id, original_network_id; + guint tmp; + guint16 descriptors_loop_length, transport_stream_loop_length; + GValue transports = { 0 }; + GValue transport_value = { 0 }; + GValueArray *descriptors = NULL; + gchar *dbg_str; + + /* fixed header + CRC == 16 */ + if (GST_BUFFER_SIZE (section->buffer) < 23) { + GST_WARNING ("PID %d invalid NIT size %d", + section->pid, section->section_length); + goto error; + } + + data = GST_BUFFER_DATA (section->buffer); + end = data + GST_BUFFER_SIZE (section->buffer); + + section->table_id = *data++; + section->section_length = GST_READ_UINT16_BE (data) & 0x0FFF; + data += 2; + + if (data + section->section_length != end) { + GST_WARNING ("PID %d invalid NIT section length %d expected %d", + section->pid, section->section_length, end - data); + goto error; + } + + network_id = GST_READ_UINT16_BE (data); + data += 2; + + tmp = *data++; + section->version_number = (tmp >> 1) & 0x1F; + section->current_next_indicator = tmp & 0x01; + + /* skip section_number and last_section_number */ + data += 2; + + descriptors_loop_length = GST_READ_UINT16_BE (data) & 0x0FFF; + data += 2; + + nit = gst_structure_new ("nit", + "network-id", G_TYPE_UINT, network_id, + "version-number", G_TYPE_UINT, section->version_number, + "current-next-indicator", G_TYPE_UINT, section->current_next_indicator, + NULL); + + /* see if the buffer is large enough */ + if (descriptors_loop_length) { + if (data + descriptors_loop_length > end - 4) { + GST_WARNING ("PID %d invalid NIT descriptors loop length %d", + section->pid, descriptors_loop_length); + gst_structure_free (nit); + goto error; + } + + descriptors = g_value_array_new (0); + if (!mpegts_packetizer_parse_descriptors (packetizer, + &data, data + descriptors_loop_length, descriptors)) { + gst_structure_free (nit); + g_value_array_free (descriptors); + goto error; + } + + gst_structure_set (nit, "descriptors", G_TYPE_VALUE_ARRAY, descriptors, + NULL); + g_value_array_free (descriptors); + } + + transport_stream_loop_length = GST_READ_UINT16_BE (data) & 0x0FFF; + data += 2; + + g_value_init (&transports, GST_TYPE_LIST); + /* read up to the CRC */ + while (transport_stream_loop_length - 4 > 0) { + gchar *transport_name; + + entry_begin = data; + + if (transport_stream_loop_length < 10) { + /* each entry must be at least 6 bytes (+ 4bytes CRC) */ + GST_WARNING ("PID %d invalid NIT entry size %d", + section->pid, transport_stream_loop_length); goto error; } - GST_INFO ("PMT PID %d program_number %d pid %d", - section->pid, program_number, pid); + transport_stream_id = GST_READ_UINT16_BE (data); + data += 2; + + original_network_id = GST_READ_UINT16_BE (data); + data += 2; - stream_info = mpegts_pmt_stream_info_new (pid, stream_type); + descriptors_loop_length = GST_READ_UINT16_BE (data) & 0x0FFF; + data += 2; - /* parse stream level descriptors */ - while (stream_info_length > 0) { - tag = *data++; - length = *data++; - stream_info_length -= 2; + transport_name = g_strdup_printf ("transport-%d", transport_stream_id); + transport = gst_structure_new (transport_name, + "transport-stream-id", G_TYPE_UINT, transport_stream_id, + "original-network-id", G_TYPE_UINT, original_network_id, NULL); + g_free (transport_name); + + if (descriptors_loop_length) { + if (data + descriptors_loop_length > end - 4) { + GST_WARNING ("PID %d invalid NIT entry %d descriptors loop length %d", + section->pid, transport_stream_id, descriptors_loop_length); + gst_structure_free (transport); + goto error; + } - if (length > stream_info_length) { - GST_WARNING ("PID %d invalid descriptor length %d left %d", - section->pid, length, stream_info_length); - g_object_unref (stream_info); + descriptors = g_value_array_new (0); + if (!mpegts_packetizer_parse_descriptors (packetizer, + &data, data + descriptors_loop_length, descriptors)) { + gst_structure_free (transport); + g_value_array_free (descriptors); goto error; } - mpegts_pmt_stream_info_add_descriptor (stream_info, - (const gchar *) data - 2, 2 + length); - data += length; - stream_info_length -= length; + gst_structure_set (transport, "descriptors", G_TYPE_VALUE_ARRAY, + descriptors, NULL); + g_value_array_free (descriptors); } - /* adds a ref to stream_info */ - mpegts_pmt_info_add_stream (pmt, stream_info); - g_object_unref (stream_info); + g_value_init (&transport_value, GST_TYPE_STRUCTURE); + g_value_take_boxed (&transport_value, transport); + gst_value_list_append_value (&transports, &transport_value); + g_value_unset (&transport_value); + + transport_stream_loop_length -= data - entry_begin; } - g_assert (data == end - 4); + if (data != end - 4) { + GST_WARNING ("PID %d invalid NIT parsed %d length %d", + section->pid, data - GST_BUFFER_DATA (section->buffer), + GST_BUFFER_SIZE (section->buffer)); + goto error; + } + + gst_structure_set_value (nit, "transports", &transports); + g_value_unset (&transports); - return G_OBJECT (pmt); + dbg_str = gst_structure_to_string (nit); + GST_DEBUG ("NIT %s", dbg_str); + g_free (dbg_str); + + return nit; error: - if (pmt) - g_object_unref (pmt); + if (nit) + gst_structure_free (nit); + + if (GST_VALUE_HOLDS_LIST (&transports)) + g_value_unset (&transports); + + return NULL; +} + +GstStructure * +mpegts_packetizer_parse_sdt (MpegTSPacketizer * packetizer, + MpegTSPacketizerSection * section) +{ + GstStructure *sdt = NULL, *service = NULL; + guint8 *data, *end, *entry_begin; + guint16 transport_stream_id, original_network_id, service_id; + guint tmp; + guint sdt_info_length; + gboolean EIT_schedule, EIT_present_following; + guint8 running_status; + gboolean scrambled; + guint descriptors_loop_length; + GValue services = { 0 }; + GValueArray *descriptors = NULL; + GValue service_value = { 0 }; + gchar *dbg_str; + + /* fixed header + CRC == 16 */ + if (GST_BUFFER_SIZE (section->buffer) < 14) { + GST_WARNING ("PID %d invalid SDT size %d", + section->pid, section->section_length); + goto error; + } + + data = GST_BUFFER_DATA (section->buffer); + end = data + GST_BUFFER_SIZE (section->buffer); + + section->table_id = *data++; + section->section_length = GST_READ_UINT16_BE (data) & 0x0FFF; + data += 2; + + if (data + section->section_length != end) { + GST_WARNING ("PID %d invalid SDT section length %d expected %d", + section->pid, section->section_length, end - data); + goto error; + } + + transport_stream_id = GST_READ_UINT16_BE (data); + data += 2; + + tmp = *data++; + section->version_number = (tmp >> 1) & 0x1F; + section->current_next_indicator = tmp & 0x01; + + /* skip section_number and last_section_number */ + data += 2; + + original_network_id = GST_READ_UINT16_BE (data); + data += 2; + + /* skip reserved byte */ + data += 1; + + sdt = gst_structure_new ("sdt", + "transport-stream-id", G_TYPE_UINT, transport_stream_id, + "version-number", G_TYPE_UINT, section->version_number, + "current-next-indicator", G_TYPE_UINT, section->current_next_indicator, + "original-network-id", G_TYPE_UINT, original_network_id, NULL); + + sdt_info_length = section->section_length - 8; + g_value_init (&services, GST_TYPE_LIST); + /* read up to the CRC */ + while (sdt_info_length - 4 > 0) { + gchar *service_name; + + entry_begin = data; + + if (sdt_info_length < 9) { + /* each entry must be at least 5 bytes (+4 bytes for the CRC) */ + GST_WARNING ("PID %d invalid SDT entry size %d", + section->pid, sdt_info_length); + goto error; + } + + service_id = GST_READ_UINT16_BE (data); + data += 2; + + /* reserved */ + data += 1; + + tmp = GST_READ_UINT16_BE (data); + data += 2; + + EIT_schedule = (tmp >> 15); + EIT_present_following = (tmp >> 14) & 0x01; + running_status = (tmp >> 5) & 0x03; + scrambled = (tmp >> 4) & 0x01; + descriptors_loop_length = tmp & 0x0FFF; + + service_name = g_strdup_printf ("service-%d", service_id); + service = gst_structure_new (service_name, NULL); + g_free (service_name); + + if (descriptors_loop_length) { + if (data + descriptors_loop_length > end - 4) { + GST_WARNING ("PID %d invalid SDT entry %d descriptors loop length %d", + section->pid, service_id, descriptors_loop_length); + gst_structure_free (service); + goto error; + } + + descriptors = g_value_array_new (0); + if (!mpegts_packetizer_parse_descriptors (packetizer, + &data, data + descriptors_loop_length, descriptors)) { + gst_structure_free (service); + g_value_array_free (descriptors); + goto error; + } + + gst_structure_set (service, "descriptors", G_TYPE_VALUE_ARRAY, + descriptors, NULL); + g_value_array_free (descriptors); + } + + g_value_init (&service_value, GST_TYPE_STRUCTURE); + g_value_take_boxed (&service_value, service); + gst_value_list_append_value (&services, &service_value); + g_value_unset (&service_value); + + sdt_info_length -= data - entry_begin; + } + + if (data != end - 4) { + GST_WARNING ("PID %d invalid SDT parsed %d length %d", + section->pid, data - GST_BUFFER_DATA (section->buffer), + GST_BUFFER_SIZE (section->buffer)); + goto error; + } + + gst_structure_set_value (sdt, "services", &services); + g_value_unset (&services); + + dbg_str = gst_structure_to_string (sdt); + g_free (dbg_str); + + return sdt; + +error: + if (sdt) + gst_structure_free (sdt); + + if (GST_VALUE_HOLDS_LIST (&services)) + g_value_unset (&services); + + return NULL; +} + +GstStructure * +mpegts_packetizer_parse_eit (MpegTSPacketizer * packetizer, + MpegTSPacketizerSection * section) +{ + GstStructure *eit = NULL, *event = NULL; + guint service_id, last_table_id, segment_last_section_number; + guint transport_stream_id, original_network_id; + gboolean free_ca_mode; + guint event_id, running_status; + guint64 start_and_duration; + GstClockTime start_time, duration; + guint8 *data, *end; + guint16 descriptors_loop_length; + GValue events = { 0 }; + GValue event_value = { 0 }; + GValueArray *descriptors = NULL; + gchar *dbg_str, *event_name; + guint tmp; + + /* fixed header + CRC == 16 */ + if (GST_BUFFER_SIZE (section->buffer) < 18) { + GST_WARNING ("PID %d invalid EIT size %d", + section->pid, section->section_length); + goto error; + } + + data = GST_BUFFER_DATA (section->buffer); + end = data + GST_BUFFER_SIZE (section->buffer); + + section->table_id = *data++; + section->section_length = GST_READ_UINT16_BE (data) & 0x0FFF; + data += 2; + + if (data + section->section_length != end) { + GST_WARNING ("PID %d invalid EIT section length %d expected %d", + section->pid, section->section_length, end - data); + goto error; + } + + service_id = GST_READ_UINT16_BE (data); + data += 2; + + tmp = *data++; + section->version_number = (tmp >> 1) & 0x1F; + section->current_next_indicator = tmp & 0x01; + + /* skip section_number and last_section_number */ + data += 2; + + transport_stream_id = GST_READ_UINT16_BE (data); + data += 2; + original_network_id = GST_READ_UINT16_BE (data); + data += 2; + segment_last_section_number = *data; + data += 1; + last_table_id = *data; + data += 1; + + eit = gst_structure_new ("eit", + "version-number", G_TYPE_UINT, section->version_number, + "current-next-indicator", G_TYPE_UINT, section->current_next_indicator, + "service-id", G_TYPE_UINT, service_id, + "transport-stream-id", G_TYPE_UINT, transport_stream_id, + "original-network-id", G_TYPE_UINT, original_network_id, + "segment-last-section-number", G_TYPE_UINT, segment_last_section_number, + "last-table-id", G_TYPE_UINT, last_table_id, NULL); + + g_value_init (&events, GST_TYPE_LIST); + while (data < end - 4) { + /* 12 is the minimum entry size + CRC */ + if (end - data < 12 + 4) { + GST_WARNING ("PID %d invalid EIT entry length %d", + section->pid, end - 4 - data); + gst_structure_free (eit); + goto error; + } + + event_id = GST_READ_UINT16_BE (data); + data += 2; + start_and_duration = GST_READ_UINT64_BE (data); + start_time = start_and_duration >> 24; + duration = start_and_duration & 0xFFFFFF; + data += 8; + running_status = *data >> 5; + free_ca_mode = (*data >> 4) & 0x01; + descriptors_loop_length = GST_READ_UINT16_BE (data) & 0x0FFF; + data += 2; + + event_name = g_strdup_printf ("event-%d", event_id); + /* FIXME: parse the date */ + event = gst_structure_new (event_name, + "event-id", G_TYPE_UINT, event_id, + "start-time", G_TYPE_UINT, 0, + "duration", G_TYPE_UINT, 0, + "running-status", G_TYPE_UINT, running_status, + "free-ca-mode", G_TYPE_BOOLEAN, free_ca_mode, NULL); + g_free (event_name); + + if (descriptors_loop_length) { + if (data + descriptors_loop_length > end - 4) { + GST_WARNING ("PID %d invalid EIT descriptors loop length %d", + section->pid, descriptors_loop_length); + gst_structure_free (event); + goto error; + } + + descriptors = g_value_array_new (0); + if (!mpegts_packetizer_parse_descriptors (packetizer, + &data, data + descriptors_loop_length, descriptors)) { + gst_structure_free (event); + g_value_array_free (descriptors); + goto error; + } + gst_structure_set (event, "descriptors", G_TYPE_VALUE_ARRAY, descriptors, + NULL); + g_value_array_free (descriptors); + } + + g_value_init (&event_value, GST_TYPE_STRUCTURE); + g_value_take_boxed (&event_value, event); + gst_value_list_append_value (&events, &event_value); + g_value_unset (&event_value); + } + + if (data != end - 4) { + GST_WARNING ("PID %d invalid EIT parsed %d length %d", + section->pid, data - GST_BUFFER_DATA (section->buffer), + GST_BUFFER_SIZE (section->buffer)); + goto error; + } + + gst_structure_set_value (eit, "events", &events); + g_value_unset (&events); + + dbg_str = gst_structure_to_string (eit); + GST_DEBUG ("EIT %s", dbg_str); + g_free (dbg_str); + + return eit; + +error: + if (eit) + gst_structure_free (eit); + + if (GST_VALUE_HOLDS_LIST (&events)) + g_value_unset (&events); + return NULL; } @@ -611,6 +1131,7 @@ mpegts_packetizer_push_section (MpegTSPacketizer * packetizer, * section_length */ if (gst_adapter_available (stream->section_adapter) >= stream->section_length + 3) { + res = mpegts_packetizer_parse_section_header (packetizer, stream, section); diff --git a/gst/mpegtsparse/mpegtspacketizer.h b/gst/mpegtsparse/mpegtspacketizer.h index b617a7aa..d8901ac0 100644 --- a/gst/mpegtsparse/mpegtspacketizer.h +++ b/gst/mpegtsparse/mpegtspacketizer.h @@ -97,9 +97,15 @@ void mpegts_packetizer_clear_packet (MpegTSPacketizer *packetizer, gboolean mpegts_packetizer_push_section (MpegTSPacketizer *packetzer, MpegTSPacketizerPacket *packet, MpegTSPacketizerSection *section); -GValueArray *mpegts_packetizer_parse_pat (MpegTSPacketizer *packetizer, +GstStructure *mpegts_packetizer_parse_pat (MpegTSPacketizer *packetizer, MpegTSPacketizerSection *section); -GObject *mpegts_packetizer_parse_pmt (MpegTSPacketizer *packetizer, +GstStructure *mpegts_packetizer_parse_pmt (MpegTSPacketizer *packetizer, + MpegTSPacketizerSection *section); +GstStructure *mpegts_packetizer_parse_nit (MpegTSPacketizer *packetizer, + MpegTSPacketizerSection *section); +GstStructure *mpegts_packetizer_parse_sdt (MpegTSPacketizer *packetizer, + MpegTSPacketizerSection *section); +GstStructure *mpegts_packetizer_parse_eit (MpegTSPacketizer *packetizer, MpegTSPacketizerSection *section); G_END_DECLS diff --git a/gst/mpegtsparse/mpegtsparse.c b/gst/mpegtsparse/mpegtsparse.c index c0496711..31cf1478 100644 --- a/gst/mpegtsparse/mpegtsparse.c +++ b/gst/mpegtsparse/mpegtsparse.c @@ -29,9 +29,6 @@ #include "mpegtsparse.h" #include "mpegtsparsemarshal.h" -#include "flutspatinfo.h" -#include "flutspmtinfo.h" -#include "flutspmtstreaminfo.h" GST_DEBUG_CATEGORY_STATIC (mpegts_parse_debug); #define GST_CAT_DEFAULT mpegts_parse_debug @@ -49,7 +46,7 @@ typedef struct gint program_number; guint16 pmt_pid; guint16 pcr_pid; - GObject *pmt_info; + GstStructure *pmt_info; GHashTable *streams; gint patcount; gint selected; @@ -98,7 +95,11 @@ GST_STATIC_PAD_TEMPLATE ("program_%d", GST_PAD_SRC, enum { + SIGNAL_PAT, SIGNAL_PMT, + SIGNAL_NIT, + SIGNAL_SDT, + SIGNAL_EIT, /* FILL ME */ LAST_SIGNAL }; @@ -107,8 +108,7 @@ enum { ARG_0, PROP_PROGRAM_NUMBERS, - PROP_PAT_INFO - /* FILL ME */ + /* FILL ME */ }; static void mpegts_parse_set_property (GObject * object, guint prop_id, @@ -180,21 +180,26 @@ mpegts_parse_class_init (MpegTSParseClass * klass) "Program Numbers", "Colon separated list of programs", "", G_PARAM_READWRITE)); - g_object_class_install_property (gobject_class, PROP_PAT_INFO, - g_param_spec_value_array ("pat-info", - "GValueArray containing GObjects with properties", - "Array of GObjects containing information from the TS PAT " - "about all programs listed in the current Program Association " - "Table (PAT)", - g_param_spec_object ("flu-pat-streaminfo", "FluPATStreamInfo", - "Fluendo TS Demuxer PAT Stream info object", - MPEGTS_TYPE_PAT_INFO, G_PARAM_READABLE), G_PARAM_READABLE)); - + signals[SIGNAL_PAT] = + g_signal_new ("pat-info", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (MpegTSParseClass, pat_info), NULL, NULL, + g_cclosure_marshal_VOID__BOXED, G_TYPE_NONE, 1, GST_TYPE_STRUCTURE); signals[SIGNAL_PMT] = g_signal_new ("pmt-info", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (MpegTSParseClass, pmt_info), NULL, NULL, - mpegts_parse_marshal_VOID__INT_OBJECT, G_TYPE_NONE, 2, G_TYPE_INT, - MPEGTS_TYPE_PMT_INFO); + g_cclosure_marshal_VOID__BOXED, G_TYPE_NONE, 1, GST_TYPE_STRUCTURE); + signals[SIGNAL_NIT] = + g_signal_new ("nit-info", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (MpegTSParseClass, nit_info), NULL, NULL, + g_cclosure_marshal_VOID__BOXED, G_TYPE_NONE, 1, GST_TYPE_STRUCTURE); + signals[SIGNAL_SDT] = + g_signal_new ("sdt-info", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (MpegTSParseClass, sdt_info), NULL, NULL, + g_cclosure_marshal_VOID__BOXED, G_TYPE_NONE, 1, GST_TYPE_STRUCTURE); + signals[SIGNAL_EIT] = + g_signal_new ("eit-info", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (MpegTSParseClass, eit_info), NULL, NULL, + g_cclosure_marshal_VOID__BOXED, G_TYPE_NONE, 1, GST_TYPE_STRUCTURE); } static gboolean @@ -213,6 +218,18 @@ mpegts_parse_reset (MpegTSParse * parse) g_hash_table_insert (parse->psi_pids, GINT_TO_POINTER (0), GINT_TO_POINTER (1)); + /* NIT */ + g_hash_table_insert (parse->psi_pids, + GINT_TO_POINTER (0x10), GINT_TO_POINTER (1)); + + /* SDT */ + g_hash_table_insert (parse->psi_pids, + GINT_TO_POINTER (0x11), GINT_TO_POINTER (1)); + + /* EIT */ + g_hash_table_insert (parse->psi_pids, + GINT_TO_POINTER (0x12), GINT_TO_POINTER (1)); + /* pmt pids will be added and removed dinamically */ } @@ -254,8 +271,8 @@ mpegts_parse_finalize (GObject * object) MpegTSParse *parse = GST_MPEGTS_PARSE (object); g_free (parse->program_numbers); - if (parse->pat_info) - g_value_array_free (parse->pat_info); + if (parse->pat) + gst_structure_free (parse->pat); g_hash_table_destroy (parse->programs); g_hash_table_destroy (parse->psi_pids); @@ -288,9 +305,6 @@ mpegts_parse_get_property (GObject * object, guint prop_id, case PROP_PROGRAM_NUMBERS: g_value_set_string (value, parse->program_numbers); break; - case PROP_PAT_INFO: - g_value_set_boxed (value, parse->pat_info); - break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } @@ -368,7 +382,7 @@ static void mpegts_parse_free_program (MpegTSParseProgram * program) { if (program->pmt_info) - g_object_unref (program->pmt_info); + gst_structure_free (program->pmt_info); g_hash_table_destroy (program->streams); @@ -714,30 +728,38 @@ mpegts_parse_is_psi_pid (MpegTSParse * parse, guint16 pid) } static void -mpegts_parse_apply_pat (MpegTSParse * parse, GValueArray * pat_info) +mpegts_parse_apply_pat (MpegTSParse * parse, GstStructure * pat_info) { - GValue *value; - GValueArray *old_pat; - GObject *program_info; - gint program_number; + const GValue *value; + GstStructure *old_pat; + GstStructure *program_info; + guint program_number; guint pid; MpegTSParseProgram *program; gint i; GList *pads_to_add = NULL; GList *pads_to_remove = NULL; + const GValue *programs; + gchar *dbg; - old_pat = parse->pat_info; - parse->pat_info = pat_info; - g_object_notify (G_OBJECT (parse), "pat-info"); + old_pat = parse->pat; + parse->pat = pat_info; + + dbg = gst_structure_to_string (pat_info); + GST_INFO_OBJECT (parse, "PAT %s", dbg); + g_free (dbg); + + g_signal_emit (parse, signals[SIGNAL_PAT], 0, pat_info); GST_OBJECT_LOCK (parse); + programs = gst_structure_get_value (pat_info, "programs"); /* activate the new table */ - for (i = 0; i < pat_info->n_values; ++i) { - value = g_value_array_get_nth (pat_info, i); + for (i = 0; i < gst_value_list_get_size (programs); ++i) { + value = gst_value_list_get_value (programs, i); - program_info = g_value_get_object (value); - g_object_get (program_info, - "program-number", &program_number, "pid", &pid, NULL); + program_info = g_value_get_boxed (value); + gst_structure_get_uint (program_info, "program-number", &program_number); + gst_structure_get_uint (program_info, "pid", &pid); program = mpegts_parse_get_program (parse, program_number); if (program) { @@ -755,9 +777,6 @@ mpegts_parse_apply_pat (MpegTSParse * parse, GValueArray * pat_info) program->patcount += 1; } else { - GST_INFO_OBJECT (parse, "PAT adding program %d pmt_pid %d", - program_number, pid); - g_hash_table_insert (parse->psi_pids, GINT_TO_POINTER ((gint) pid), GINT_TO_POINTER (1)); program = mpegts_parse_add_program (parse, program_number, pid); @@ -771,12 +790,13 @@ mpegts_parse_apply_pat (MpegTSParse * parse, GValueArray * pat_info) if (old_pat) { /* deactivate the old table */ - for (i = 0; i < old_pat->n_values; ++i) { - value = g_value_array_get_nth (old_pat, i); + programs = gst_structure_get_value (old_pat, "programs"); + for (i = 0; i < gst_value_list_get_size (programs); ++i) { + value = gst_value_list_get_value (programs, i); - program_info = g_value_get_object (value); - g_object_get (program_info, - "program-number", &program_number, "pid", &pid, NULL); + program_info = g_value_get_boxed (value); + gst_structure_get_uint (program_info, "program-number", &program_number); + gst_structure_get_uint (program_info, "pid", &pid); program = mpegts_parse_get_program (parse, program_number); if (program == NULL) { @@ -789,8 +809,12 @@ mpegts_parse_apply_pat (MpegTSParse * parse, GValueArray * pat_info) /* the program has been referenced by the new pat, keep it */ continue; - GST_INFO_OBJECT (parse, "PAT removing program %d pmt_pid %d", - program_number, pid); + { + gchar *dbg = gst_structure_to_string (program_info); + + GST_INFO_OBJECT (parse, "PAT removing program %s", dbg); + g_free (dbg); + } if (program->active) parse->pads_to_remove = g_list_append (parse->pads_to_remove, @@ -800,7 +824,7 @@ mpegts_parse_apply_pat (MpegTSParse * parse, GValueArray * pat_info) g_hash_table_remove (parse->psi_pids, GINT_TO_POINTER ((gint) pid)); } - g_value_array_free (old_pat); + gst_structure_free (old_pat); } pads_to_add = parse->pads_to_add; @@ -814,39 +838,40 @@ mpegts_parse_apply_pat (MpegTSParse * parse, GValueArray * pat_info) static void mpegts_parse_apply_pmt (MpegTSParse * parse, - guint16 pmt_pid, GObject * pmt_info) + guint16 pmt_pid, GstStructure * pmt_info) { MpegTSParseProgram *program; - gint program_number; + guint program_number; guint pcr_pid; guint pid; guint stream_type; - GValueArray *old_streams; - GValueArray *new_streams; - GValue *value; - GObject *stream; + GstStructure *stream; gint i; + const GValue *old_streams; + const GValue *new_streams; + const GValue *value; - g_object_get (pmt_info, "program_number", &program_number, - "pcr-pid", &pcr_pid, "stream-info", &new_streams, NULL); + gst_structure_get_uint (pmt_info, "program-number", &program_number); + gst_structure_get_uint (pmt_info, "pcr-pid", &pcr_pid); + new_streams = gst_structure_get_value (pmt_info, "streams"); GST_OBJECT_LOCK (parse); program = mpegts_parse_get_program (parse, program_number); if (program) { if (program->pmt_info) { /* deactivate old pmt */ - g_object_get (program->pmt_info, "stream-info", &old_streams, NULL); + old_streams = gst_structure_get_value (program->pmt_info, "streams"); - for (i = 0; i < old_streams->n_values; ++i) { - value = g_value_array_get_nth (old_streams, i); - stream = g_value_get_object (value); + for (i = 0; i < gst_value_list_get_size (old_streams); ++i) { + value = gst_value_list_get_value (old_streams, i); + stream = g_value_get_boxed (value); - g_object_get (stream, "pid", &pid, "stream-type", &stream_type, NULL); + gst_structure_get_uint (stream, "pid", &pid); + gst_structure_get_uint (stream, "stream-type", &stream_type); mpegts_parse_program_remove_stream (parse, program, (guint16) pid); } - g_value_array_free (old_streams); - g_object_unref (program->pmt_info); + gst_structure_free (program->pmt_info); } } else { /* no PAT?? */ @@ -862,20 +887,46 @@ mpegts_parse_apply_pmt (MpegTSParse * parse, program->pcr_pid = pcr_pid; mpegts_parse_program_add_stream (parse, program, (guint16) pcr_pid, -1); - for (i = 0; i < new_streams->n_values; ++i) { - value = g_value_array_get_nth (new_streams, i); - stream = g_value_get_object (value); + for (i = 0; i < gst_value_list_get_size (new_streams); ++i) { + value = gst_value_list_get_value (new_streams, i); + stream = g_value_get_boxed (value); - g_object_get (stream, "pid", &pid, "stream-type", &stream_type, NULL); - GST_DEBUG_OBJECT (parse, "PMT program %d pid %d", program_number, pid); - mpegts_parse_program_add_stream (parse, program, (guint16) pid, - (guint8) stream_type); + gst_structure_get_uint (stream, "pid", &pid); + gst_structure_get_uint (stream, "stream-type", &stream_type); + mpegts_parse_program_add_stream (parse, program, + (guint16) pid, (guint8) stream_type); } GST_OBJECT_UNLOCK (parse); - g_value_array_free (new_streams); + { + gchar *dbg = gst_structure_to_string (pmt_info); + + GST_DEBUG_OBJECT (parse, "new pmt %s", dbg); + g_free (dbg); + } + + g_signal_emit (parse, signals[SIGNAL_PMT], 0, pmt_info); +} - g_signal_emit (parse, signals[SIGNAL_PMT], 0, program_number, pmt_info); +static void +mpegts_parse_apply_nit (MpegTSParse * parse, + guint16 pmt_pid, GstStructure * nit_info) +{ + g_signal_emit (parse, signals[SIGNAL_NIT], 0, nit_info); +} + +static void +mpegts_parse_apply_sdt (MpegTSParse * parse, + guint16 pmt_pid, GstStructure * sdt_info) +{ + g_signal_emit (parse, signals[SIGNAL_SDT], 0, sdt_info); +} + +static void +mpegts_parse_apply_eit (MpegTSParse * parse, + guint16 pmt_pid, GstStructure * eit_info) +{ + g_signal_emit (parse, signals[SIGNAL_EIT], 0, eit_info); } static gboolean @@ -887,7 +938,7 @@ mpegts_parse_handle_psi (MpegTSParse * parse, MpegTSPacketizerSection * section) case 0x00: { /* PAT */ - GValueArray *pat_info; + GstStructure *pat_info; pat_info = mpegts_packetizer_parse_pat (parse->packetizer, section); if (pat_info) @@ -900,7 +951,7 @@ mpegts_parse_handle_psi (MpegTSParse * parse, MpegTSPacketizerSection * section) case 0x02: { /* PMT */ - GObject *pmt_info; + GstStructure *pmt_info; pmt_info = mpegts_packetizer_parse_pmt (parse->packetizer, section); if (pmt_info) @@ -910,6 +961,63 @@ mpegts_parse_handle_psi (MpegTSParse * parse, MpegTSPacketizerSection * section) break; } + case 0x40: + /* NIT, actual network */ + case 0x41: + /* NIT, other network */ + { + GstStructure *nit_info; + + nit_info = mpegts_packetizer_parse_nit (parse->packetizer, section); + if (nit_info) + mpegts_parse_apply_nit (parse, section->pid, nit_info); + else + res = FALSE; + + break; + } + case 0x42: + { + /* SDT */ + GstStructure *sdt_info; + + sdt_info = mpegts_packetizer_parse_sdt (parse->packetizer, section); + if (sdt_info) + mpegts_parse_apply_sdt (parse, section->pid, sdt_info); + else + res = FALSE; + break; + } + case 0x4E: + /* EIT, present/following */ + case 0x50: + case 0x51: + case 0x52: + case 0x53: + case 0x54: + case 0x55: + case 0x56: + case 0x57: + case 0x58: + case 0x59: + case 0x5A: + case 0x5B: + case 0x5C: + case 0x5D: + case 0x5E: + case 0x5F: + /* EIT, schedule */ + { + /* EIT */ + GstStructure *eit_info; + + eit_info = mpegts_packetizer_parse_eit (parse->packetizer, section); + if (eit_info) + mpegts_parse_apply_eit (parse, section->pid, eit_info); + else + res = FALSE; + break; + } default: break; } diff --git a/gst/mpegtsparse/mpegtsparse.h b/gst/mpegtsparse/mpegtsparse.h index 557520f8..60f079ab 100644 --- a/gst/mpegtsparse/mpegtsparse.h +++ b/gst/mpegtsparse/mpegtsparse.h @@ -57,7 +57,7 @@ struct _MpegTSParse { GHashTable *programs; guint req_pads; - GValueArray *pat_info; + GstStructure *pat; MpegTSPacketizer *packetizer; GHashTable *psi_pids; gboolean disposed; @@ -67,7 +67,11 @@ struct _MpegTSParseClass { GstElementClass parent_class; /* signals */ - void (*pmt_info) (GObject *pmt_info); + void (*pat_info) (GstStructure *pat); + void (*pmt_info) (GstStructure *pmt); + void (*nit_info) (GstStructure *nit); + void (*sdt_info) (GstStructure *sdt); + void (*eit_info) (GstStructure *eit); }; GType gst_mpegts_parse_get_type(void); |