mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-02-17 11:45:25 +00:00
tsdemux/tsparse: Port to 0.11
This is a naive port that somewhat works but is inefficient. I need to rethink how to make the best out of GstMemory/GstBuffer
This commit is contained in:
parent
0243e4f536
commit
6abe2134bf
7 changed files with 309 additions and 238 deletions
|
@ -298,7 +298,7 @@ GST_PLUGINS_NONPORTED=" adpcmdec adpcmenc aiff asfmux \
|
|||
dccp debugutils dtmf faceoverlay festival \
|
||||
fieldanalysis freeze frei0r gaudieffects geometrictransform h264parse \
|
||||
hdvparse hls id3tag inter interlace ivfparse jpegformat jp2kdecimator \
|
||||
liveadder legacyresample librfb mpegdemux mpegtsdemux mpegtsmux \
|
||||
liveadder legacyresample librfb mpegdemux mpegtsmux \
|
||||
mpegpsmux mpegvideoparse mve mxf nsf nuvdemux \
|
||||
patchdetect pcapparse pnm rawparse real removesilence rtpmux rtpvp8 scaletempo \
|
||||
sdi segmentclip siren speed subenc stereo tta videofilters \
|
||||
|
|
|
@ -84,15 +84,26 @@ static GstFlowReturn mpegts_base_chain (GstPad * pad, GstBuffer * buf);
|
|||
static gboolean mpegts_base_sink_event (GstPad * pad, GstEvent * event);
|
||||
static GstStateChangeReturn mpegts_base_change_state (GstElement * element,
|
||||
GstStateChange transition);
|
||||
static void _extra_init (GType type);
|
||||
|
||||
static void mpegts_base_get_tags_from_sdt (MpegTSBase * base,
|
||||
GstStructure * sdt_info);
|
||||
static void mpegts_base_get_tags_from_eit (MpegTSBase * base,
|
||||
GstStructure * eit_info);
|
||||
|
||||
GST_BOILERPLATE_FULL (MpegTSBase, mpegts_base, GstElement, GST_TYPE_ELEMENT,
|
||||
_extra_init);
|
||||
static void
|
||||
_extra_init (void)
|
||||
{
|
||||
QUARK_PROGRAMS = g_quark_from_string ("programs");
|
||||
QUARK_PROGRAM_NUMBER = g_quark_from_string ("program-number");
|
||||
QUARK_PID = g_quark_from_string ("pid");
|
||||
QUARK_PCR_PID = g_quark_from_string ("pcr-pid");
|
||||
QUARK_STREAMS = g_quark_from_string ("streams");
|
||||
QUARK_STREAM_TYPE = g_quark_from_string ("stream-type");
|
||||
}
|
||||
|
||||
#define mpegts_base_parent_class parent_class
|
||||
G_DEFINE_TYPE_WITH_CODE (MpegTSBase, mpegts_base, GST_TYPE_ELEMENT,
|
||||
_extra_init ());
|
||||
|
||||
static const guint32 crc_tab[256] = {
|
||||
0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b,
|
||||
|
@ -153,26 +164,6 @@ mpegts_base_calc_crc32 (guint8 * data, guint datalen)
|
|||
return crc;
|
||||
}
|
||||
|
||||
static void
|
||||
_extra_init (GType type)
|
||||
{
|
||||
QUARK_PROGRAMS = g_quark_from_string ("programs");
|
||||
QUARK_PROGRAM_NUMBER = g_quark_from_string ("program-number");
|
||||
QUARK_PID = g_quark_from_string ("pid");
|
||||
QUARK_PCR_PID = g_quark_from_string ("pcr-pid");
|
||||
QUARK_STREAMS = g_quark_from_string ("streams");
|
||||
QUARK_STREAM_TYPE = g_quark_from_string ("stream-type");
|
||||
}
|
||||
|
||||
static void
|
||||
mpegts_base_base_init (gpointer klass)
|
||||
{
|
||||
GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
|
||||
|
||||
gst_element_class_add_pad_template (element_class,
|
||||
gst_static_pad_template_get (&sink_template));
|
||||
}
|
||||
|
||||
static void
|
||||
mpegts_base_class_init (MpegTSBaseClass * klass)
|
||||
{
|
||||
|
@ -181,13 +172,14 @@ mpegts_base_class_init (MpegTSBaseClass * klass)
|
|||
|
||||
element_class = GST_ELEMENT_CLASS (klass);
|
||||
element_class->change_state = mpegts_base_change_state;
|
||||
gst_element_class_add_pad_template (element_class,
|
||||
gst_static_pad_template_get (&sink_template));
|
||||
|
||||
gobject_class = G_OBJECT_CLASS (klass);
|
||||
gobject_class->set_property = mpegts_base_set_property;
|
||||
gobject_class->get_property = mpegts_base_get_property;
|
||||
gobject_class->dispose = mpegts_base_dispose;
|
||||
gobject_class->finalize = mpegts_base_finalize;
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -227,7 +219,7 @@ mpegts_base_reset (MpegTSBase * base)
|
|||
}
|
||||
|
||||
static void
|
||||
mpegts_base_init (MpegTSBase * base, MpegTSBaseClass * klass)
|
||||
mpegts_base_init (MpegTSBase * base)
|
||||
{
|
||||
base->sinkpad = gst_pad_new_from_static_template (&sink_template, "sink");
|
||||
gst_pad_set_activate_function (base->sinkpad, mpegts_base_sink_activate);
|
||||
|
@ -956,11 +948,16 @@ mpegts_base_handle_psi (MpegTSBase * base, MpegTSPacketizerSection * section)
|
|||
|
||||
/* table ids 0x70 - 0x73 do not have a crc */
|
||||
if (G_LIKELY (section->table_id < 0x70 || section->table_id > 0x73)) {
|
||||
if (G_UNLIKELY (mpegts_base_calc_crc32 (GST_BUFFER_DATA (section->buffer),
|
||||
GST_BUFFER_SIZE (section->buffer)) != 0)) {
|
||||
gpointer data;
|
||||
gsize size;
|
||||
|
||||
data = gst_buffer_map (section->buffer, &size, 0, GST_MAP_READ);
|
||||
if (G_UNLIKELY (mpegts_base_calc_crc32 (data, size) != 0)) {
|
||||
gst_buffer_unmap (section->buffer, data, size);
|
||||
GST_WARNING_OBJECT (base, "bad crc in psi pid 0x%x", section->pid);
|
||||
return FALSE;
|
||||
}
|
||||
gst_buffer_unmap (section->buffer, data, size);
|
||||
}
|
||||
|
||||
switch (section->table_id) {
|
||||
|
@ -1180,24 +1177,12 @@ mpegts_base_sink_event (GstPad * pad, GstEvent * event)
|
|||
gst_event_type_get_name (GST_EVENT_TYPE (event)));
|
||||
|
||||
switch (GST_EVENT_TYPE (event)) {
|
||||
case GST_EVENT_NEWSEGMENT:
|
||||
case GST_EVENT_SEGMENT:
|
||||
{
|
||||
gboolean update;
|
||||
gdouble rate, applied_rate;
|
||||
GstFormat format;
|
||||
gint64 start, stop, position;
|
||||
gst_event_copy_segment (event, &base->segment);
|
||||
|
||||
gst_event_parse_new_segment_full (event, &update, &rate, &applied_rate,
|
||||
&format, &start, &stop, &position);
|
||||
GST_DEBUG_OBJECT (base,
|
||||
"Segment update:%d, rate:%f, applied_rate:%f, format:%s", update,
|
||||
rate, applied_rate, gst_format_get_name (format));
|
||||
GST_DEBUG_OBJECT (base,
|
||||
" start:%" G_GINT64_FORMAT ", stop:%" G_GINT64_FORMAT
|
||||
", position:%" G_GINT64_FORMAT, start, stop, position);
|
||||
gst_segment_set_newsegment_full (&base->segment, update, rate,
|
||||
applied_rate, format, start, stop, position);
|
||||
gst_event_unref (event);
|
||||
|
||||
base->in_gap = GST_CLOCK_TIME_NONE;
|
||||
base->first_buf_ts = GST_CLOCK_TIME_NONE;
|
||||
}
|
||||
|
@ -1268,10 +1253,14 @@ mpegts_base_chain (GstPad * pad, GstBuffer * buf)
|
|||
/* bad header, skip the packet */
|
||||
goto next;
|
||||
|
||||
GST_DEBUG ("Got packet (buffer:%p)", packet.buffer);
|
||||
|
||||
/* base PSI data */
|
||||
if (packet.payload != NULL && mpegts_base_is_psi (base, &packet)) {
|
||||
MpegTSPacketizerSection section;
|
||||
|
||||
based = mpegts_packetizer_push_section (packetizer, &packet, §ion);
|
||||
|
||||
if (G_UNLIKELY (!based))
|
||||
/* bad section data */
|
||||
goto next;
|
||||
|
@ -1279,6 +1268,8 @@ mpegts_base_chain (GstPad * pad, GstBuffer * buf)
|
|||
if (G_LIKELY (section.complete)) {
|
||||
/* section complete */
|
||||
based = mpegts_base_handle_psi (base, §ion);
|
||||
|
||||
GST_DEBUG ("Unreffing section buffer %p", section.buffer);
|
||||
gst_buffer_unref (section.buffer);
|
||||
|
||||
if (G_UNLIKELY (!based))
|
||||
|
@ -1287,7 +1278,6 @@ mpegts_base_chain (GstPad * pad, GstBuffer * buf)
|
|||
}
|
||||
/* we need to push section packet downstream */
|
||||
res = mpegts_base_push (base, &packet, §ion);
|
||||
|
||||
} else if (MPEGTS_BIT_IS_SET (base->is_pes, packet.pid)) {
|
||||
/* push the packet downstream */
|
||||
res = mpegts_base_push (base, &packet, NULL);
|
||||
|
@ -1349,6 +1339,7 @@ mpegts_base_scan (MpegTSBase * base)
|
|||
ret = GST_FLOW_ERROR;
|
||||
|
||||
beach:
|
||||
GST_DEBUG ("Returning %s", gst_flow_get_name (ret));
|
||||
mpegts_packetizer_clear (base->packetizer);
|
||||
return ret;
|
||||
|
||||
|
@ -1382,7 +1373,7 @@ mpegts_base_loop (MpegTSBase * base)
|
|||
100 * base->packetsize, &buf);
|
||||
if (G_UNLIKELY (ret != GST_FLOW_OK))
|
||||
goto error;
|
||||
base->seek_offset += GST_BUFFER_SIZE (buf);
|
||||
base->seek_offset += gst_buffer_get_size (buf);
|
||||
ret = mpegts_base_chain (base->sinkpad, buf);
|
||||
if (G_UNLIKELY (ret != GST_FLOW_OK))
|
||||
goto error;
|
||||
|
@ -1398,6 +1389,7 @@ mpegts_base_loop (MpegTSBase * base)
|
|||
error:
|
||||
{
|
||||
const gchar *reason = gst_flow_get_name (ret);
|
||||
|
||||
GST_DEBUG_OBJECT (base, "Pausing task, reason %s", reason);
|
||||
if (ret == GST_FLOW_UNEXPECTED)
|
||||
GST_MPEGTS_BASE_GET_CLASS (base)->push_event (base, gst_event_new_eos ());
|
||||
|
@ -1477,7 +1469,7 @@ mpegts_base_handle_seek_event (MpegTSBase * base, GstPad * pad,
|
|||
if (flush) {
|
||||
/* send a FLUSH_STOP for the sinkpad, since we need data for seeking */
|
||||
GST_DEBUG_OBJECT (base, "sending flush stop");
|
||||
gst_pad_push_event (base->sinkpad, gst_event_new_flush_stop ());
|
||||
gst_pad_push_event (base->sinkpad, gst_event_new_flush_stop (TRUE));
|
||||
}
|
||||
|
||||
if (flags & (GST_SEEK_FLAG_SEGMENT | GST_SEEK_FLAG_SKIP)) {
|
||||
|
@ -1505,7 +1497,7 @@ mpegts_base_handle_seek_event (MpegTSBase * base, GstPad * pad,
|
|||
GST_DEBUG_OBJECT (base, "sending flush stop");
|
||||
//gst_pad_push_event (base->sinkpad, gst_event_new_flush_stop ());
|
||||
GST_MPEGTS_BASE_GET_CLASS (base)->push_event (base,
|
||||
gst_event_new_flush_stop ());
|
||||
gst_event_new_flush_stop (TRUE));
|
||||
}
|
||||
//else
|
||||
done:
|
||||
|
@ -1517,14 +1509,31 @@ push_mode:
|
|||
|
||||
|
||||
static gboolean
|
||||
mpegts_base_sink_activate (GstPad * pad)
|
||||
mpegts_base_sink_activate (GstPad * sinkpad)
|
||||
{
|
||||
if (gst_pad_check_pull_range (pad)) {
|
||||
GST_DEBUG_OBJECT (pad, "activating pull");
|
||||
return gst_pad_activate_pull (pad, TRUE);
|
||||
} else {
|
||||
GST_DEBUG_OBJECT (pad, "activating push");
|
||||
return gst_pad_activate_push (pad, TRUE);
|
||||
GstQuery *query;
|
||||
gboolean pull_mode;
|
||||
|
||||
query = gst_query_new_scheduling ();
|
||||
|
||||
if (!gst_pad_peer_query (sinkpad, query)) {
|
||||
gst_query_unref (query);
|
||||
goto activate_push;
|
||||
}
|
||||
|
||||
gst_query_parse_scheduling (query, &pull_mode, NULL, NULL, NULL, NULL, NULL);
|
||||
gst_query_unref (query);
|
||||
|
||||
if (!pull_mode)
|
||||
goto activate_push;
|
||||
|
||||
GST_DEBUG_OBJECT (sinkpad, "activating pull");
|
||||
return gst_pad_activate_pull (sinkpad, TRUE);
|
||||
|
||||
activate_push:
|
||||
{
|
||||
GST_DEBUG_OBJECT (sinkpad, "activating push");
|
||||
return gst_pad_activate_push (sinkpad, TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -287,6 +287,8 @@ mpegts_packetizer_parse_packet (MpegTSPacketizer2 * packetizer,
|
|||
|
||||
packet->data = data;
|
||||
|
||||
gst_buffer_unmap (packet->buffer, packet->bufdata, packet->bufsize);
|
||||
|
||||
if (packet->adaptation_field_control & 0x02)
|
||||
if (!mpegts_packetizer_parse_adaptation_field_control (packetizer, packet))
|
||||
return FALSE;
|
||||
|
@ -304,15 +306,17 @@ mpegts_packetizer_parse_section_header (MpegTSPacketizer2 * packetizer,
|
|||
MpegTSPacketizerStream * stream, MpegTSPacketizerSection * section)
|
||||
{
|
||||
guint8 tmp;
|
||||
guint8 *data, *crc_data;
|
||||
guint8 *bufdata, *data, *crc_data;
|
||||
gsize size;
|
||||
MpegTSPacketizerStreamSubtable *subtable;
|
||||
GSList *subtable_list = NULL;
|
||||
|
||||
section->complete = TRUE;
|
||||
|
||||
/* get the section buffer, pass the ownership to the caller */
|
||||
section->buffer = gst_adapter_take_buffer (stream->section_adapter,
|
||||
3 + stream->section_length);
|
||||
data = GST_BUFFER_DATA (section->buffer);
|
||||
bufdata = data = gst_buffer_map (section->buffer, &size, 0, GST_MAP_READ);
|
||||
GST_BUFFER_OFFSET (section->buffer) = stream->offset;
|
||||
|
||||
section->table_id = *data++;
|
||||
|
@ -348,8 +352,7 @@ mpegts_packetizer_parse_section_header (MpegTSPacketizer2 * packetizer,
|
|||
goto not_applicable;
|
||||
|
||||
/* CRC is at the end of the section */
|
||||
crc_data =
|
||||
GST_BUFFER_DATA (section->buffer) + GST_BUFFER_SIZE (section->buffer) - 4;
|
||||
crc_data = bufdata + size - 4;
|
||||
section->crc = GST_READ_UINT32_BE (crc_data);
|
||||
|
||||
if (section->version_number == subtable->version_number &&
|
||||
|
@ -360,6 +363,8 @@ mpegts_packetizer_parse_section_header (MpegTSPacketizer2 * packetizer,
|
|||
subtable->crc = section->crc;
|
||||
stream->section_table_id = section->table_id;
|
||||
|
||||
gst_buffer_unmap (section->buffer, bufdata, size);
|
||||
|
||||
return TRUE;
|
||||
|
||||
not_applicable:
|
||||
|
@ -368,6 +373,7 @@ not_applicable:
|
|||
section->pid, section->table_id, section->subtable_extension,
|
||||
section->current_next_indicator, section->version_number, section->crc);
|
||||
section->complete = FALSE;
|
||||
gst_buffer_unmap (section->buffer, bufdata, size);
|
||||
gst_buffer_unref (section->buffer);
|
||||
return TRUE;
|
||||
}
|
||||
|
@ -421,7 +427,8 @@ mpegts_packetizer_parse_pat (MpegTSPacketizer2 * packetizer,
|
|||
MpegTSPacketizerSection * section)
|
||||
{
|
||||
GstStructure *pat_info = NULL;
|
||||
guint8 *data, *end;
|
||||
guint8 *bufdata, *data, *end;
|
||||
gsize size;
|
||||
guint transport_stream_id;
|
||||
guint8 tmp;
|
||||
guint program_number;
|
||||
|
@ -431,7 +438,7 @@ mpegts_packetizer_parse_pat (MpegTSPacketizer2 * packetizer,
|
|||
GstStructure *entry = NULL;
|
||||
gchar *struct_name;
|
||||
|
||||
data = GST_BUFFER_DATA (section->buffer);
|
||||
bufdata = data = gst_buffer_map (section->buffer, &size, 0, GST_MAP_READ);
|
||||
|
||||
section->table_id = *data++;
|
||||
section->section_length = GST_READ_UINT16_BE (data) & 0x0FFF;
|
||||
|
@ -450,8 +457,10 @@ mpegts_packetizer_parse_pat (MpegTSPacketizer2 * packetizer,
|
|||
pat_info = gst_structure_id_new (QUARK_PAT,
|
||||
QUARK_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);
|
||||
end = bufdata + size;
|
||||
|
||||
while (data < end - 4) {
|
||||
program_number = GST_READ_UINT16_BE (data);
|
||||
data += 2;
|
||||
|
@ -474,6 +483,8 @@ mpegts_packetizer_parse_pat (MpegTSPacketizer2 * packetizer,
|
|||
gst_structure_id_set_value (pat_info, QUARK_PROGRAMS, &entries);
|
||||
g_value_unset (&entries);
|
||||
|
||||
gst_buffer_unmap (section->buffer, bufdata, size);
|
||||
|
||||
if (data != end - 4) {
|
||||
/* FIXME: check the CRC before parsing the packet */
|
||||
GST_ERROR ("at the end of PAT data != end - 4");
|
||||
|
@ -490,7 +501,8 @@ mpegts_packetizer_parse_pmt (MpegTSPacketizer2 * packetizer,
|
|||
MpegTSPacketizerSection * section)
|
||||
{
|
||||
GstStructure *pmt = NULL;
|
||||
guint8 *data, *end;
|
||||
guint8 *bufdata, *data, *end;
|
||||
gsize size;
|
||||
guint16 program_number;
|
||||
guint8 tmp;
|
||||
guint pcr_pid;
|
||||
|
@ -504,15 +516,16 @@ mpegts_packetizer_parse_pmt (MpegTSPacketizer2 * packetizer,
|
|||
GstStructure *stream_info = NULL;
|
||||
gchar *struct_name;
|
||||
|
||||
data = bufdata = gst_buffer_map (section->buffer, &size, 0, GST_MAP_READ);
|
||||
|
||||
/* fixed header + CRC == 16 */
|
||||
if (GST_BUFFER_SIZE (section->buffer) < 16) {
|
||||
if (size < 16) {
|
||||
GST_WARNING ("PID %d invalid PMT size %d",
|
||||
section->pid, section->section_length);
|
||||
goto error;
|
||||
}
|
||||
|
||||
data = GST_BUFFER_DATA (section->buffer);
|
||||
end = data + GST_BUFFER_SIZE (section->buffer);
|
||||
end = data + size;
|
||||
|
||||
section->table_id = *data++;
|
||||
section->section_length = GST_READ_UINT16_BE (data) & 0x0FFF;
|
||||
|
@ -682,6 +695,8 @@ mpegts_packetizer_parse_pmt (MpegTSPacketizer2 * packetizer,
|
|||
gst_structure_id_set_value (pmt, QUARK_STREAMS, &programs);
|
||||
g_value_unset (&programs);
|
||||
|
||||
gst_buffer_unmap (section->buffer, bufdata, size);
|
||||
|
||||
g_assert (data == end - 4);
|
||||
|
||||
return pmt;
|
||||
|
@ -689,6 +704,7 @@ mpegts_packetizer_parse_pmt (MpegTSPacketizer2 * packetizer,
|
|||
error:
|
||||
if (pmt)
|
||||
gst_structure_free (pmt);
|
||||
gst_buffer_unmap (section->buffer, bufdata, size);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
@ -698,7 +714,8 @@ mpegts_packetizer_parse_nit (MpegTSPacketizer2 * packetizer,
|
|||
MpegTSPacketizerSection * section)
|
||||
{
|
||||
GstStructure *nit = NULL, *transport = NULL, *delivery_structure = NULL;
|
||||
guint8 *data, *end, *entry_begin;
|
||||
guint8 *bufdata, *data, *end, *entry_begin;
|
||||
gsize size;
|
||||
guint16 network_id, transport_stream_id, original_network_id;
|
||||
guint tmp;
|
||||
guint16 descriptors_loop_length, transport_stream_loop_length;
|
||||
|
@ -707,15 +724,17 @@ mpegts_packetizer_parse_nit (MpegTSPacketizer2 * packetizer,
|
|||
GValueArray *descriptors = NULL;
|
||||
|
||||
GST_DEBUG ("NIT");
|
||||
|
||||
data = bufdata = gst_buffer_map (section->buffer, &size, 0, GST_MAP_READ);
|
||||
|
||||
/* fixed header + CRC == 16 */
|
||||
if (GST_BUFFER_SIZE (section->buffer) < 23) {
|
||||
if (size < 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);
|
||||
end = data + size;
|
||||
|
||||
section->table_id = *data++;
|
||||
section->section_length = GST_READ_UINT16_BE (data) & 0x0FFF;
|
||||
|
@ -1304,14 +1323,15 @@ mpegts_packetizer_parse_nit (MpegTSPacketizer2 * packetizer,
|
|||
|
||||
if (data != end - 4) {
|
||||
GST_WARNING ("PID %d invalid NIT parsed %d length %d",
|
||||
section->pid, (gint) (data - GST_BUFFER_DATA (section->buffer)),
|
||||
GST_BUFFER_SIZE (section->buffer));
|
||||
section->pid, (gint) (data - bufdata), size);
|
||||
goto error;
|
||||
}
|
||||
|
||||
gst_structure_id_set_value (nit, QUARK_TRANSPORTS, &transports);
|
||||
g_value_unset (&transports);
|
||||
|
||||
gst_buffer_unmap (section->buffer, bufdata, size);
|
||||
|
||||
GST_DEBUG ("NIT %" GST_PTR_FORMAT, nit);
|
||||
|
||||
return nit;
|
||||
|
@ -1320,6 +1340,8 @@ error:
|
|||
if (nit)
|
||||
gst_structure_free (nit);
|
||||
|
||||
gst_buffer_unmap (section->buffer, bufdata, size);
|
||||
|
||||
if (GST_VALUE_HOLDS_LIST (&transports))
|
||||
g_value_unset (&transports);
|
||||
|
||||
|
@ -1331,7 +1353,8 @@ mpegts_packetizer_parse_sdt (MpegTSPacketizer2 * packetizer,
|
|||
MpegTSPacketizerSection * section)
|
||||
{
|
||||
GstStructure *sdt = NULL, *service = NULL;
|
||||
guint8 *data, *end, *entry_begin;
|
||||
guint8 *data, *bufdata, *end, *entry_begin;
|
||||
gsize size;
|
||||
guint16 transport_stream_id, original_network_id, service_id;
|
||||
guint tmp;
|
||||
guint sdt_info_length;
|
||||
|
@ -1343,15 +1366,17 @@ mpegts_packetizer_parse_sdt (MpegTSPacketizer2 * packetizer,
|
|||
GValue service_value = { 0 };
|
||||
|
||||
GST_DEBUG ("SDT");
|
||||
|
||||
data = bufdata = gst_buffer_map (section->buffer, &size, 0, GST_MAP_READ);
|
||||
|
||||
/* fixed header + CRC == 16 */
|
||||
if (GST_BUFFER_SIZE (section->buffer) < 14) {
|
||||
if (size < 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);
|
||||
end = data + size;
|
||||
|
||||
section->table_id = *data++;
|
||||
section->section_length = GST_READ_UINT16_BE (data) & 0x0FFF;
|
||||
|
@ -1509,20 +1534,23 @@ mpegts_packetizer_parse_sdt (MpegTSPacketizer2 * packetizer,
|
|||
|
||||
if (data != end - 4) {
|
||||
GST_WARNING ("PID %d invalid SDT parsed %d length %d",
|
||||
section->pid, (gint) (data - GST_BUFFER_DATA (section->buffer)),
|
||||
GST_BUFFER_SIZE (section->buffer));
|
||||
section->pid, (gint) (data - bufdata), size);
|
||||
goto error;
|
||||
}
|
||||
|
||||
gst_structure_id_set_value (sdt, QUARK_SERVICES, &services);
|
||||
g_value_unset (&services);
|
||||
|
||||
gst_buffer_unmap (section->buffer, bufdata, size);
|
||||
|
||||
return sdt;
|
||||
|
||||
error:
|
||||
if (sdt)
|
||||
gst_structure_free (sdt);
|
||||
|
||||
gst_buffer_unmap (section->buffer, bufdata, size);
|
||||
|
||||
if (GST_VALUE_HOLDS_LIST (&services))
|
||||
g_value_unset (&services);
|
||||
|
||||
|
@ -1541,7 +1569,8 @@ mpegts_packetizer_parse_eit (MpegTSPacketizer2 * packetizer,
|
|||
guint16 mjd;
|
||||
guint year, month, day, hour, minute, second;
|
||||
guint duration;
|
||||
guint8 *data, *end, *duration_ptr, *utc_ptr;
|
||||
guint8 *data, *bufdata, *end, *duration_ptr, *utc_ptr;
|
||||
gsize size;
|
||||
guint16 descriptors_loop_length;
|
||||
GValue events = { 0 };
|
||||
GValue event_value = { 0 };
|
||||
|
@ -1549,15 +1578,16 @@ mpegts_packetizer_parse_eit (MpegTSPacketizer2 * packetizer,
|
|||
gchar *event_name;
|
||||
guint tmp;
|
||||
|
||||
data = bufdata = gst_buffer_map (section->buffer, &size, 0, GST_MAP_READ);
|
||||
|
||||
/* fixed header + CRC == 16 */
|
||||
if (GST_BUFFER_SIZE (section->buffer) < 18) {
|
||||
if (size < 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);
|
||||
end = data + size;
|
||||
|
||||
section->table_id = *data++;
|
||||
section->section_length = GST_READ_UINT16_BE (data) & 0x0FFF;
|
||||
|
@ -1968,14 +1998,15 @@ mpegts_packetizer_parse_eit (MpegTSPacketizer2 * packetizer,
|
|||
|
||||
if (data != end - 4) {
|
||||
GST_WARNING ("PID %d invalid EIT parsed %d length %d",
|
||||
section->pid, (gint) (data - GST_BUFFER_DATA (section->buffer)),
|
||||
GST_BUFFER_SIZE (section->buffer));
|
||||
section->pid, (gint) (data - bufdata), size);
|
||||
goto error;
|
||||
}
|
||||
|
||||
gst_structure_id_set_value (eit, QUARK_EVENTS, &events);
|
||||
g_value_unset (&events);
|
||||
|
||||
gst_buffer_unmap (section->buffer, bufdata, size);
|
||||
|
||||
GST_DEBUG ("EIT %" GST_PTR_FORMAT, eit);
|
||||
|
||||
return eit;
|
||||
|
@ -1984,6 +2015,8 @@ error:
|
|||
if (eit)
|
||||
gst_structure_free (eit);
|
||||
|
||||
gst_buffer_unmap (section->buffer, bufdata, size);
|
||||
|
||||
if (GST_VALUE_HOLDS_LIST (&events))
|
||||
g_value_unset (&events);
|
||||
|
||||
|
@ -1997,18 +2030,21 @@ mpegts_packetizer_parse_tdt (MpegTSPacketizer2 * packetizer,
|
|||
GstStructure *tdt = NULL;
|
||||
guint16 mjd;
|
||||
guint year, month, day, hour, minute, second;
|
||||
guint8 *data, *end, *utc_ptr;
|
||||
guint8 *data, *bufdata, *end, *utc_ptr;
|
||||
gsize size;
|
||||
|
||||
GST_DEBUG ("TDT");
|
||||
|
||||
data = bufdata = gst_buffer_map (section->buffer, &size, 0, GST_MAP_READ);
|
||||
|
||||
/* length always 8 */
|
||||
if (G_UNLIKELY (GST_BUFFER_SIZE (section->buffer) != 8)) {
|
||||
if (G_UNLIKELY (size != 8)) {
|
||||
GST_WARNING ("PID %d invalid TDT size %d",
|
||||
section->pid, section->section_length);
|
||||
goto error;
|
||||
}
|
||||
|
||||
data = GST_BUFFER_DATA (section->buffer);
|
||||
end = data + GST_BUFFER_SIZE (section->buffer);
|
||||
end = data + size;
|
||||
|
||||
section->table_id = *data++;
|
||||
section->section_length = GST_READ_UINT16_BE (data) & 0x0FFF;
|
||||
|
@ -2049,12 +2085,16 @@ mpegts_packetizer_parse_tdt (MpegTSPacketizer2 * packetizer,
|
|||
"hour", G_TYPE_UINT, hour,
|
||||
"minute", G_TYPE_UINT, minute, "second", G_TYPE_UINT, second, NULL);
|
||||
|
||||
gst_buffer_unmap (section->buffer, bufdata, size);
|
||||
|
||||
return tdt;
|
||||
|
||||
error:
|
||||
if (tdt)
|
||||
gst_structure_free (tdt);
|
||||
|
||||
gst_buffer_unmap (section->buffer, bufdata, size);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -2133,7 +2173,7 @@ mpegts_packetizer_push (MpegTSPacketizer2 * packetizer, GstBuffer * buffer)
|
|||
}
|
||||
|
||||
GST_DEBUG ("Pushing %u byte from offset %" G_GUINT64_FORMAT,
|
||||
GST_BUFFER_SIZE (buffer), GST_BUFFER_OFFSET (buffer));
|
||||
gst_buffer_get_size (buffer), GST_BUFFER_OFFSET (buffer));
|
||||
gst_adapter_push (packetizer->adapter, buffer);
|
||||
}
|
||||
|
||||
|
@ -2227,77 +2267,87 @@ mpegts_packetizer_next_packet (MpegTSPacketizer2 * packetizer,
|
|||
|
||||
packet->buffer = NULL;
|
||||
|
||||
/* Resync if needed */
|
||||
if (G_UNLIKELY (!packetizer->know_packet_size)) {
|
||||
if (!mpegts_try_discover_packet_size (packetizer))
|
||||
return PACKET_NEED_MORE;
|
||||
}
|
||||
|
||||
while ((avail = packetizer->adapter->size) >= packetizer->packet_size) {
|
||||
guint i;
|
||||
GstBuffer *tmpbuf;
|
||||
guint8 *bufdata;
|
||||
|
||||
packet->buffer = gst_adapter_take_buffer (packetizer->adapter,
|
||||
packetizer->packet_size);
|
||||
|
||||
bufdata = packet->bufdata = packet->data_start =
|
||||
gst_buffer_map (packet->buffer, &packet->bufsize, 0, GST_MAP_READ);
|
||||
|
||||
/* M2TS packets don't start with the sync byte, all other variants do */
|
||||
if (packetizer->packet_size == MPEGTS_M2TS_PACKETSIZE) {
|
||||
packet->data_start = GST_BUFFER_DATA (packet->buffer) + 4;
|
||||
} else {
|
||||
packet->data_start = GST_BUFFER_DATA (packet->buffer);
|
||||
}
|
||||
if (packetizer->packet_size == MPEGTS_M2TS_PACKETSIZE)
|
||||
packet->data_start += 4;
|
||||
|
||||
/* ALL mpeg-ts variants contain 188 bytes of data. Those with bigger packet
|
||||
* sizes contain either extra data (timesync, FEC, ..) either before or after
|
||||
* the data */
|
||||
packet->data_end = packet->data_start + 188;
|
||||
GST_BUFFER_OFFSET (packet->buffer) = packet->offset = packetizer->offset;
|
||||
GST_DEBUG ("offset %" G_GUINT64_FORMAT, packet->offset);
|
||||
|
||||
packetizer->offset += packetizer->packet_size;
|
||||
GST_MEMDUMP ("buffer", GST_BUFFER_DATA (packet->buffer), 16);
|
||||
GST_MEMDUMP ("buffer", bufdata, 16);
|
||||
GST_MEMDUMP ("data_start", packet->data_start, 16);
|
||||
|
||||
/* Check sync byte */
|
||||
if (G_UNLIKELY (packet->data_start[0] != 0x47)) {
|
||||
guint i;
|
||||
GstBuffer *tmpbuf;
|
||||
if (G_LIKELY (packet->data_start[0] == 0x47))
|
||||
goto got_valid_packet;
|
||||
|
||||
GST_LOG ("Lost sync %d", packetizer->packet_size);
|
||||
/* Find the 0x47 in the buffer */
|
||||
for (i = 0; i < packetizer->packet_size; i++)
|
||||
if (GST_BUFFER_DATA (packet->buffer)[i] == 0x47)
|
||||
break;
|
||||
if (G_UNLIKELY (i == packetizer->packet_size)) {
|
||||
GST_ERROR ("REALLY lost the sync");
|
||||
gst_buffer_unref (packet->buffer);
|
||||
goto done;
|
||||
}
|
||||
GST_LOG ("Lost sync %d", packetizer->packet_size);
|
||||
|
||||
if (packetizer->packet_size == MPEGTS_M2TS_PACKETSIZE) {
|
||||
if (i >= 4)
|
||||
i -= 4;
|
||||
else
|
||||
i += 188;
|
||||
}
|
||||
/* Find the 0x47 in the buffer */
|
||||
for (i = 0; i < packetizer->packet_size; i++)
|
||||
if (bufdata[i] == 0x47)
|
||||
break;
|
||||
|
||||
/* Pop out the remaining data... */
|
||||
GST_BUFFER_DATA (packet->buffer) += i;
|
||||
GST_BUFFER_SIZE (packet->buffer) -= i;
|
||||
GST_BUFFER_OFFSET (packet->buffer) += i;
|
||||
tmpbuf =
|
||||
gst_adapter_take_buffer (packetizer->adapter,
|
||||
packetizer->adapter->size);
|
||||
/* ... and push everything back in */
|
||||
gst_adapter_push (packetizer->adapter, packet->buffer);
|
||||
gst_adapter_push (packetizer->adapter, tmpbuf);
|
||||
continue;
|
||||
if (G_UNLIKELY (i == packetizer->packet_size)) {
|
||||
GST_ERROR ("REALLY lost the sync");
|
||||
gst_buffer_unmap (packet->buffer, bufdata, packet->bufsize);
|
||||
gst_buffer_unref (packet->buffer);
|
||||
goto done;
|
||||
}
|
||||
|
||||
return mpegts_packetizer_parse_packet (packetizer, packet);
|
||||
if (packetizer->packet_size == MPEGTS_M2TS_PACKETSIZE) {
|
||||
if (i >= 4)
|
||||
i -= 4;
|
||||
else
|
||||
i += 188;
|
||||
}
|
||||
|
||||
/* Pop out the remaining data... */
|
||||
gst_buffer_resize (packet->buffer, i, packet->bufsize - i);
|
||||
GST_BUFFER_OFFSET (packet->buffer) += i;
|
||||
tmpbuf =
|
||||
gst_adapter_take_buffer (packetizer->adapter,
|
||||
packetizer->adapter->size);
|
||||
/* ... and push everything back in */
|
||||
gst_adapter_push (packetizer->adapter, packet->buffer);
|
||||
gst_adapter_push (packetizer->adapter, tmpbuf);
|
||||
}
|
||||
|
||||
done:
|
||||
return PACKET_NEED_MORE;
|
||||
|
||||
got_valid_packet:
|
||||
return mpegts_packetizer_parse_packet (packetizer, packet);
|
||||
}
|
||||
|
||||
void
|
||||
mpegts_packetizer_clear_packet (MpegTSPacketizer2 * packetizer,
|
||||
MpegTSPacketizerPacket * packet)
|
||||
{
|
||||
GST_DEBUG ("packet:%p, buffer:%p", packet, packet->buffer);
|
||||
|
||||
memset (packet, 0, sizeof (MpegTSPacketizerPacket));
|
||||
}
|
||||
|
||||
|
@ -2332,8 +2382,9 @@ mpegts_packetizer_push_section (MpegTSPacketizer2 * packetizer,
|
|||
if (packet->pid == 0x14) {
|
||||
table_id = data[0];
|
||||
section->section_length = GST_READ_UINT24_BE (data) & 0x000FFF;
|
||||
section->buffer = gst_buffer_create_sub (packet->buffer,
|
||||
data - GST_BUFFER_DATA (packet->buffer), section->section_length + 3);
|
||||
section->buffer =
|
||||
gst_buffer_copy_region (packet->buffer, GST_BUFFER_COPY_ALL,
|
||||
data - packet->bufdata, section->section_length + 3);
|
||||
section->table_id = table_id;
|
||||
section->complete = TRUE;
|
||||
res = TRUE;
|
||||
|
@ -2344,8 +2395,8 @@ mpegts_packetizer_push_section (MpegTSPacketizer2 * packetizer,
|
|||
|
||||
/* create a sub buffer from the start of the section (table_id and
|
||||
* section_length included) to the end */
|
||||
sub_buf = gst_buffer_create_sub (packet->buffer,
|
||||
data - GST_BUFFER_DATA (packet->buffer), packet->data_end - data);
|
||||
sub_buf = gst_buffer_copy_region (packet->buffer, GST_BUFFER_COPY_ALL,
|
||||
data - packet->bufdata, packet->data_end - data);
|
||||
|
||||
|
||||
stream = packetizer->streams[packet->pid];
|
||||
|
@ -2372,8 +2423,8 @@ mpegts_packetizer_push_section (MpegTSPacketizer2 * packetizer,
|
|||
("PID %d table_id %d sub_table_extension %d payload_unit_start_indicator set but section "
|
||||
"not complete (last_continuity: %d continuity: %d sec len %d buffer %d avail %d",
|
||||
packet->pid, table_id, subtable_extension, stream->continuity_counter,
|
||||
packet->continuity_counter, section_length, GST_BUFFER_SIZE (sub_buf),
|
||||
stream->section_adapter->size);
|
||||
packet->continuity_counter, section_length,
|
||||
gst_buffer_get_size (sub_buf), stream->section_adapter->size);
|
||||
mpegts_packetizer_clear_section (packetizer, stream);
|
||||
} else {
|
||||
GST_DEBUG
|
||||
|
|
|
@ -94,9 +94,13 @@ typedef struct
|
|||
guint8 continuity_counter;
|
||||
guint8 *payload;
|
||||
|
||||
guint8 *data_start;
|
||||
/* temporary copies of gst_buffer_map */
|
||||
guint8 *bufdata;
|
||||
gsize bufsize;
|
||||
|
||||
guint8 *data_start; /* Location of 0x47 marker byte */
|
||||
guint8 *data_end;
|
||||
guint8 *data;
|
||||
guint8 *data; /* Location of post-TS-header data */
|
||||
|
||||
guint8 afc_flags;
|
||||
guint64 pcr;
|
||||
|
@ -144,7 +148,7 @@ gboolean mpegts_packetizer_has_packets (MpegTSPacketizer2 *packetizer);
|
|||
MpegTSPacketizerPacketReturn mpegts_packetizer_next_packet (MpegTSPacketizer2 *packetizer,
|
||||
MpegTSPacketizerPacket *packet);
|
||||
void mpegts_packetizer_clear_packet (MpegTSPacketizer2 *packetizer,
|
||||
MpegTSPacketizerPacket *packet);
|
||||
MpegTSPacketizerPacket *packet);
|
||||
void mpegts_packetizer_remove_stream(MpegTSPacketizer2 *packetizer,
|
||||
gint16 pid);
|
||||
|
||||
|
|
|
@ -113,29 +113,13 @@ static void mpegts_parse_reset_selected_programs (MpegTSParse2 * parse,
|
|||
|
||||
static void mpegts_parse_pad_removed (GstElement * element, GstPad * pad);
|
||||
static GstPad *mpegts_parse_request_new_pad (GstElement * element,
|
||||
GstPadTemplate * templ, const gchar * name);
|
||||
GstPadTemplate * templ, const gchar * name, const GstCaps * caps);
|
||||
static void mpegts_parse_release_pad (GstElement * element, GstPad * pad);
|
||||
static gboolean mpegts_parse_src_pad_query (GstPad * pad, GstQuery * query);
|
||||
static gboolean push_event (MpegTSBase * base, GstEvent * event);
|
||||
|
||||
GST_BOILERPLATE (MpegTSParse2, mpegts_parse, MpegTSBase, GST_TYPE_MPEGTS_BASE);
|
||||
|
||||
static void
|
||||
mpegts_parse_base_init (gpointer klass)
|
||||
{
|
||||
GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
|
||||
|
||||
gst_element_class_add_pad_template (element_class,
|
||||
gst_static_pad_template_get (&src_template));
|
||||
gst_element_class_add_pad_template (element_class,
|
||||
gst_static_pad_template_get (&program_template));
|
||||
|
||||
gst_element_class_set_details_simple (element_class,
|
||||
"MPEG transport stream parser", "Codec/Parser",
|
||||
"Parses MPEG2 transport streams",
|
||||
"Alessandro Decina <alessandro@nnva.org>, "
|
||||
"Zaheer Abbas Merali <zaheerabbas at merali dot org>");
|
||||
}
|
||||
#define mpegts_parse_parent_class parent_class
|
||||
G_DEFINE_TYPE (MpegTSParse2, mpegts_parse, GST_TYPE_MPEGTS_BASE);
|
||||
|
||||
static void
|
||||
mpegts_parse_class_init (MpegTSParse2Class * klass)
|
||||
|
@ -149,6 +133,17 @@ mpegts_parse_class_init (MpegTSParse2Class * klass)
|
|||
element_class->request_new_pad = mpegts_parse_request_new_pad;
|
||||
element_class->release_pad = mpegts_parse_release_pad;
|
||||
|
||||
gst_element_class_add_pad_template (element_class,
|
||||
gst_static_pad_template_get (&src_template));
|
||||
gst_element_class_add_pad_template (element_class,
|
||||
gst_static_pad_template_get (&program_template));
|
||||
|
||||
gst_element_class_set_details_simple (element_class,
|
||||
"MPEG transport stream parser", "Codec/Parser",
|
||||
"Parses MPEG2 transport streams",
|
||||
"Alessandro Decina <alessandro@nnva.org>, "
|
||||
"Zaheer Abbas Merali <zaheerabbas at merali dot org>");
|
||||
|
||||
gobject_class = G_OBJECT_CLASS (klass);
|
||||
gobject_class->set_property = mpegts_parse_set_property;
|
||||
gobject_class->get_property = mpegts_parse_get_property;
|
||||
|
@ -168,7 +163,7 @@ mpegts_parse_class_init (MpegTSParse2Class * klass)
|
|||
}
|
||||
|
||||
static void
|
||||
mpegts_parse_init (MpegTSParse2 * parse, MpegTSParse2Class * klass)
|
||||
mpegts_parse_init (MpegTSParse2 * parse)
|
||||
{
|
||||
parse->need_sync_program_pads = FALSE;
|
||||
parse->program_numbers = g_strdup ("");
|
||||
|
@ -429,7 +424,7 @@ mpegts_parse_pad_removed (GstElement * element, GstPad * pad)
|
|||
|
||||
static GstPad *
|
||||
mpegts_parse_request_new_pad (GstElement * element, GstPadTemplate * template,
|
||||
const gchar * unused)
|
||||
const gchar * unused, const GstCaps * caps)
|
||||
{
|
||||
MpegTSParse2 *parse;
|
||||
gchar *name;
|
||||
|
@ -564,9 +559,15 @@ mpegts_parse_push (MpegTSBase * base, MpegTSPacketizerPacket * packet,
|
|||
mpegts_parse_sync_program_pads (parse);
|
||||
|
||||
pid = packet->pid;
|
||||
|
||||
#if 0
|
||||
buffer = gst_buffer_make_metadata_writable (packet->buffer);
|
||||
|
||||
/* we have the same caps on all the src pads */
|
||||
gst_buffer_set_caps (buffer, base->packetizer->caps);
|
||||
#else
|
||||
buffer = packet->buffer;
|
||||
#endif
|
||||
|
||||
GST_OBJECT_LOCK (parse);
|
||||
/* clear tspad->pushed on pads */
|
||||
|
|
|
@ -109,7 +109,6 @@ struct _TSDemuxStream
|
|||
|
||||
/* Current data to be pushed out */
|
||||
GstBufferList *current;
|
||||
GstBufferListIterator *currentit;
|
||||
GList *currentlist;
|
||||
|
||||
/* Current PTS for this stream */
|
||||
|
@ -126,7 +125,7 @@ struct _TSDemuxStream
|
|||
"video/x-dirac;" \
|
||||
"video/x-wmv," \
|
||||
"wmvversion = (int) 3, " \
|
||||
"format = (fourcc) WVC1" \
|
||||
"format = (string) WVC1" \
|
||||
)
|
||||
|
||||
#define AUDIO_CAPS \
|
||||
|
@ -217,13 +216,9 @@ static GstFlowReturn
|
|||
gst_ts_demux_push_pending_data (GstTSDemux * demux, TSDemuxStream * stream);
|
||||
|
||||
static gboolean push_event (MpegTSBase * base, GstEvent * event);
|
||||
static void _extra_init (GType type);
|
||||
|
||||
GST_BOILERPLATE_FULL (GstTSDemux, gst_ts_demux, MpegTSBase,
|
||||
GST_TYPE_MPEGTS_BASE, _extra_init);
|
||||
|
||||
static void
|
||||
_extra_init (GType type)
|
||||
_extra_init (void)
|
||||
{
|
||||
QUARK_TSDEMUX = g_quark_from_string ("tsdemux");
|
||||
QUARK_PID = g_quark_from_string ("pid");
|
||||
|
@ -234,32 +229,15 @@ _extra_init (GType type)
|
|||
QUARK_OFFSET = g_quark_from_string ("offset");
|
||||
}
|
||||
|
||||
static void
|
||||
gst_ts_demux_base_init (gpointer klass)
|
||||
{
|
||||
GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
|
||||
|
||||
gst_element_class_add_pad_template (element_class,
|
||||
gst_static_pad_template_get (&video_template));
|
||||
gst_element_class_add_pad_template (element_class,
|
||||
gst_static_pad_template_get (&audio_template));
|
||||
gst_element_class_add_pad_template (element_class,
|
||||
gst_static_pad_template_get (&subpicture_template));
|
||||
gst_element_class_add_pad_template (element_class,
|
||||
gst_static_pad_template_get (&private_template));
|
||||
|
||||
gst_element_class_set_details_simple (element_class,
|
||||
"MPEG transport stream demuxer",
|
||||
"Codec/Demuxer",
|
||||
"Demuxes MPEG2 transport streams",
|
||||
"Zaheer Abbas Merali <zaheerabbas at merali dot org>\n"
|
||||
"Edward Hervey <edward.hervey@collabora.co.uk>");
|
||||
}
|
||||
#define gst_ts_demux_parent_class parent_class
|
||||
G_DEFINE_TYPE_WITH_CODE (GstTSDemux, gst_ts_demux, GST_TYPE_MPEGTS_BASE,
|
||||
_extra_init ());
|
||||
|
||||
static void
|
||||
gst_ts_demux_class_init (GstTSDemuxClass * klass)
|
||||
{
|
||||
GObjectClass *gobject_class;
|
||||
GstElementClass *element_class;
|
||||
MpegTSBaseClass *ts_class;
|
||||
|
||||
gobject_class = G_OBJECT_CLASS (klass);
|
||||
|
@ -277,6 +255,22 @@ gst_ts_demux_class_init (GstTSDemuxClass * klass)
|
|||
"Emit messages for every pcr/opcr/pts/dts", FALSE,
|
||||
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
element_class = GST_ELEMENT_CLASS (klass);
|
||||
gst_element_class_add_pad_template (element_class,
|
||||
gst_static_pad_template_get (&video_template));
|
||||
gst_element_class_add_pad_template (element_class,
|
||||
gst_static_pad_template_get (&audio_template));
|
||||
gst_element_class_add_pad_template (element_class,
|
||||
gst_static_pad_template_get (&subpicture_template));
|
||||
gst_element_class_add_pad_template (element_class,
|
||||
gst_static_pad_template_get (&private_template));
|
||||
|
||||
gst_element_class_set_details_simple (element_class,
|
||||
"MPEG transport stream demuxer",
|
||||
"Codec/Demuxer",
|
||||
"Demuxes MPEG2 transport streams",
|
||||
"Zaheer Abbas Merali <zaheerabbas at merali dot org>\n"
|
||||
"Edward Hervey <edward.hervey@collabora.co.uk>");
|
||||
|
||||
ts_class = GST_MPEGTS_BASE_CLASS (klass);
|
||||
ts_class->reset = GST_DEBUG_FUNCPTR (gst_ts_demux_reset);
|
||||
|
@ -291,7 +285,7 @@ gst_ts_demux_class_init (GstTSDemuxClass * klass)
|
|||
}
|
||||
|
||||
static void
|
||||
gst_ts_demux_init (GstTSDemux * demux, GstTSDemuxClass * klass)
|
||||
gst_ts_demux_init (GstTSDemux * demux)
|
||||
{
|
||||
demux->need_newsegment = TRUE;
|
||||
demux->program_number = -1;
|
||||
|
@ -615,8 +609,7 @@ gst_ts_demux_perform_seek (MpegTSBase * base, GstSegment * segment, guint16 pid)
|
|||
max_loop_cnt = (segment->flags & GST_SEEK_FLAG_ACCURATE) ? 25 : 10;
|
||||
|
||||
seektime =
|
||||
MAX (0,
|
||||
segment->last_stop - SEEK_TIMESTAMP_OFFSET) + demux->first_pcr.gsttime;
|
||||
MAX (0, segment->stop - SEEK_TIMESTAMP_OFFSET) + demux->first_pcr.gsttime;
|
||||
seekpcroffset.gsttime = seektime;
|
||||
|
||||
GST_DEBUG ("seeking to %" GST_TIME_FORMAT, GST_TIME_ARGS (seektime));
|
||||
|
@ -789,7 +782,9 @@ gst_ts_demux_perform_seek (MpegTSBase * base, GstSegment * segment, guint16 pid)
|
|||
|
||||
seektime -= demux->first_pcr.gsttime;
|
||||
|
||||
#if 0
|
||||
segment->last_stop = seektime;
|
||||
#endif
|
||||
segment->time = seektime;
|
||||
|
||||
/* we stop at the end */
|
||||
|
@ -838,24 +833,21 @@ gst_ts_demux_do_seek (MpegTSBase * base, GstEvent * event, guint16 pid)
|
|||
/* copy segment, we need this because we still need the old
|
||||
* segment when we close the current segment. */
|
||||
memcpy (&seeksegment, &demux->segment, sizeof (GstSegment));
|
||||
|
||||
/* configure the segment with the seek variables */
|
||||
GST_DEBUG_OBJECT (demux, "configuring seek");
|
||||
GST_DEBUG ("seeksegment: start: %" GST_TIME_FORMAT " stop: %"
|
||||
GST_TIME_FORMAT " time: %" GST_TIME_FORMAT " accum: %" GST_TIME_FORMAT
|
||||
" last_stop: %" GST_TIME_FORMAT " duration: %" GST_TIME_FORMAT,
|
||||
GST_TIME_FORMAT " time: %" GST_TIME_FORMAT
|
||||
" duration: %" GST_TIME_FORMAT,
|
||||
GST_TIME_ARGS (seeksegment.start), GST_TIME_ARGS (seeksegment.stop),
|
||||
GST_TIME_ARGS (seeksegment.time), GST_TIME_ARGS (seeksegment.accum),
|
||||
GST_TIME_ARGS (seeksegment.last_stop),
|
||||
GST_TIME_ARGS (seeksegment.duration));
|
||||
gst_segment_set_seek (&seeksegment, rate, format, flags, start_type, start,
|
||||
GST_TIME_ARGS (seeksegment.time), GST_TIME_ARGS (seeksegment.duration));
|
||||
gst_segment_do_seek (&seeksegment, rate, format, flags, start_type, start,
|
||||
stop_type, stop, &update);
|
||||
GST_DEBUG ("seeksegment: start: %" GST_TIME_FORMAT " stop: %"
|
||||
GST_TIME_FORMAT " time: %" GST_TIME_FORMAT " accum: %" GST_TIME_FORMAT
|
||||
" last_stop: %" GST_TIME_FORMAT " duration: %" GST_TIME_FORMAT,
|
||||
GST_TIME_FORMAT " time: %" GST_TIME_FORMAT
|
||||
" duration: %" GST_TIME_FORMAT,
|
||||
GST_TIME_ARGS (seeksegment.start), GST_TIME_ARGS (seeksegment.stop),
|
||||
GST_TIME_ARGS (seeksegment.time), GST_TIME_ARGS (seeksegment.accum),
|
||||
GST_TIME_ARGS (seeksegment.last_stop),
|
||||
GST_TIME_ARGS (seeksegment.duration));
|
||||
GST_TIME_ARGS (seeksegment.time), GST_TIME_ARGS (seeksegment.duration));
|
||||
|
||||
res = gst_ts_demux_perform_seek (base, &seeksegment, pid);
|
||||
if (G_UNLIKELY (res != GST_FLOW_OK)) {
|
||||
|
@ -869,7 +861,7 @@ gst_ts_demux_do_seek (MpegTSBase * base, GstEvent * event, guint16 pid)
|
|||
if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
|
||||
gst_element_post_message (GST_ELEMENT_CAST (demux),
|
||||
gst_message_new_segment_start (GST_OBJECT_CAST (demux),
|
||||
demux->segment.format, demux->segment.last_stop));
|
||||
demux->segment.format, demux->segment.stop));
|
||||
}
|
||||
|
||||
done:
|
||||
|
@ -1113,8 +1105,7 @@ create_pad_for_stream (MpegTSBase * base, MpegTSBaseStream * bstream,
|
|||
name = g_strdup_printf ("video_%04x", bstream->pid);
|
||||
caps = gst_caps_new_simple ("video/x-wmv",
|
||||
"wmvversion", G_TYPE_INT, 3,
|
||||
"format", GST_TYPE_FOURCC, GST_MAKE_FOURCC ('W', 'V', 'C', '1'),
|
||||
NULL);
|
||||
"format", G_TYPE_STRING, "WVC1", NULL);
|
||||
}
|
||||
}
|
||||
g_free (desc);
|
||||
|
@ -1375,6 +1366,7 @@ process_section (MpegTSBase * base)
|
|||
next:
|
||||
mpegts_packetizer_clear_packet (base->packetizer, &packet);
|
||||
}
|
||||
|
||||
return done;
|
||||
}
|
||||
|
||||
|
@ -1553,7 +1545,6 @@ find_timestamps (MpegTSBase * base, guint64 initoff, guint64 * offset)
|
|||
GstFlowReturn ret = GST_FLOW_OK;
|
||||
GstBuffer *buf;
|
||||
gboolean done = FALSE;
|
||||
GstFormat format = GST_FORMAT_BYTES;
|
||||
gint64 total_bytes;
|
||||
guint64 scan_offset;
|
||||
guint i = 0;
|
||||
|
@ -1600,8 +1591,8 @@ find_timestamps (MpegTSBase * base, guint64 initoff, guint64 * offset)
|
|||
demux->program = NULL;
|
||||
|
||||
/* Find end position */
|
||||
if (G_UNLIKELY (!gst_pad_query_peer_duration (base->sinkpad, &format,
|
||||
&total_bytes) || format != GST_FORMAT_BYTES)) {
|
||||
if (G_UNLIKELY (!gst_pad_query_peer_duration (base->sinkpad, GST_FORMAT_BYTES,
|
||||
&total_bytes))) {
|
||||
GST_WARNING_OBJECT (base, "Couldn't get upstream size in bytes");
|
||||
ret = GST_FLOW_ERROR;
|
||||
mpegts_packetizer_clear (base->packetizer);
|
||||
|
@ -1641,9 +1632,8 @@ find_timestamps (MpegTSBase * base, guint64 initoff, guint64 * offset)
|
|||
|
||||
verify_timestamps (base, &initial, &final);
|
||||
|
||||
gst_segment_set_duration (&demux->segment, GST_FORMAT_TIME,
|
||||
demux->last_pcr.gsttime - demux->first_pcr.gsttime);
|
||||
demux->duration = demux->last_pcr.gsttime - demux->first_pcr.gsttime;
|
||||
demux->duration = demux->segment.duration =
|
||||
demux->last_pcr.gsttime - demux->first_pcr.gsttime;
|
||||
GST_DEBUG ("Done, duration:%" GST_TIME_FORMAT,
|
||||
GST_TIME_ARGS (demux->duration));
|
||||
|
||||
|
@ -1699,7 +1689,9 @@ process_pcr (MpegTSBase * base, guint64 initoff, TSPcrOffset * pcroffset,
|
|||
pcrpattern = 0x47000020 | ((program->pcr_pid & 0x1fff) << 8);
|
||||
|
||||
for (i = 0; (i < 20) && (nbpcr < numpcr); i++) {
|
||||
guint offset, size;
|
||||
guint offset;
|
||||
gsize size, bufsize;
|
||||
gpointer data;
|
||||
|
||||
ret =
|
||||
gst_pad_pull_range (base->sinkpad,
|
||||
|
@ -1708,17 +1700,21 @@ process_pcr (MpegTSBase * base, guint64 initoff, TSPcrOffset * pcroffset,
|
|||
if (G_UNLIKELY (ret != GST_FLOW_OK))
|
||||
goto beach;
|
||||
|
||||
gst_byte_reader_init_from_buffer (&br, buf);
|
||||
data = gst_buffer_map (buf, &bufsize, 0, GST_MAP_READ);
|
||||
size = bufsize;
|
||||
|
||||
gst_byte_reader_init (&br, data, size);
|
||||
|
||||
offset = 0;
|
||||
size = GST_BUFFER_SIZE (buf);
|
||||
|
||||
resync:
|
||||
offset = gst_byte_reader_masked_scan_uint32 (&br, 0xff000000, 0x47000000,
|
||||
0, base->packetsize);
|
||||
|
||||
if (offset == -1)
|
||||
if (offset == -1) {
|
||||
gst_buffer_unmap (buf, data, bufsize);
|
||||
continue;
|
||||
}
|
||||
|
||||
while ((nbpcr < numpcr) && (size >= base->packetsize)) {
|
||||
|
||||
|
@ -1767,6 +1763,7 @@ process_pcr (MpegTSBase * base, guint64 initoff, TSPcrOffset * pcroffset,
|
|||
size -= base->packetsize;
|
||||
offset += base->packetsize;
|
||||
}
|
||||
gst_buffer_unmap (buf, data, bufsize);
|
||||
}
|
||||
|
||||
beach:
|
||||
|
@ -1930,21 +1927,22 @@ gst_ts_demux_parse_pes_header (GstTSDemux * demux, TSDemuxStream * stream)
|
|||
{
|
||||
MpegTSBase *base = (MpegTSBase *) demux;
|
||||
PESHeader header;
|
||||
GstBuffer *buf = stream->pendingbuffers[0];
|
||||
GstFlowReturn res = GST_FLOW_OK;
|
||||
gint offset = 0;
|
||||
guint8 *data;
|
||||
guint32 length;
|
||||
gsize length;
|
||||
guint64 bufferoffset;
|
||||
GstClockTime time;
|
||||
PESParsingResult parseres;
|
||||
|
||||
data = GST_BUFFER_DATA (stream->pendingbuffers[0]);
|
||||
length = GST_BUFFER_SIZE (stream->pendingbuffers[0]);
|
||||
bufferoffset = GST_BUFFER_OFFSET (stream->pendingbuffers[0]);
|
||||
data = gst_buffer_map (buf, &length, 0, GST_MAP_READ);
|
||||
bufferoffset = GST_BUFFER_OFFSET (buf);
|
||||
|
||||
GST_MEMDUMP ("Header buffer", data, MIN (length, 32));
|
||||
|
||||
parseres = mpegts_parse_pes_header (data, length, &header, &offset);
|
||||
|
||||
if (G_UNLIKELY (parseres == PES_PARSING_NEED_MORE))
|
||||
goto discont;
|
||||
if (G_UNLIKELY (parseres == PES_PARSING_BAD)) {
|
||||
|
@ -2008,16 +2006,17 @@ gst_ts_demux_parse_pes_header (GstTSDemux * demux, TSDemuxStream * stream)
|
|||
if (!GST_CLOCK_TIME_IS_VALID (base->in_gap))
|
||||
base->in_gap = 0;
|
||||
|
||||
GST_BUFFER_TIMESTAMP (stream->pendingbuffers[0]) = time + base->in_gap;
|
||||
GST_BUFFER_TIMESTAMP (buf) = time + base->in_gap;
|
||||
}
|
||||
|
||||
if (header.DTS != -1)
|
||||
gst_ts_demux_record_dts (demux, stream, header.DTS, bufferoffset);
|
||||
|
||||
gst_buffer_unmap (buf, data, length);
|
||||
|
||||
/* Remove PES headers */
|
||||
GST_DEBUG ("Moving data forward by %d bytes", header.header_size);
|
||||
GST_BUFFER_DATA (stream->pendingbuffers[0]) += header.header_size;
|
||||
GST_BUFFER_SIZE (stream->pendingbuffers[0]) -= header.header_size;
|
||||
gst_buffer_resize (buf, header.header_size, length - header.header_size);
|
||||
|
||||
/* FIXME : responsible for switching to PENDING_PACKET_BUFFER and
|
||||
* creating the bufferlist */
|
||||
|
@ -2028,9 +2027,7 @@ gst_ts_demux_parse_pes_header (GstTSDemux * demux, TSDemuxStream * stream)
|
|||
|
||||
/* Create a new bufferlist */
|
||||
stream->current = gst_buffer_list_new ();
|
||||
stream->currentit = gst_buffer_list_iterate (stream->current);
|
||||
stream->currentlist = NULL;
|
||||
gst_buffer_list_iterator_add_group (stream->currentit);
|
||||
|
||||
/* Push pending buffers into the list */
|
||||
for (i = stream->nbpending; i; i--)
|
||||
|
@ -2058,14 +2055,20 @@ gst_ts_demux_queue_data (GstTSDemux * demux, TSDemuxStream * stream,
|
|||
MpegTSPacketizerPacket * packet)
|
||||
{
|
||||
GstBuffer *buf;
|
||||
guint8 *data;
|
||||
gsize size;
|
||||
|
||||
GST_DEBUG ("state:%d", stream->state);
|
||||
|
||||
buf = packet->buffer;
|
||||
/* HACK : Instead of creating a new buffer, we just modify the data/size
|
||||
* of the buffer to point to the payload */
|
||||
GST_BUFFER_DATA (buf) = packet->payload;
|
||||
GST_BUFFER_SIZE (buf) = packet->data_end - packet->payload;
|
||||
data = gst_buffer_map (buf, &size, 0, GST_MAP_READ);
|
||||
|
||||
GST_DEBUG ("Resizing buffer to %d (size:%d) (Was %d bytes long)",
|
||||
packet->payload - data, packet->data_end - packet->payload, size);
|
||||
gst_buffer_unmap (buf, data, size);
|
||||
|
||||
gst_buffer_resize (buf, packet->payload - data,
|
||||
packet->data_end - packet->payload);
|
||||
|
||||
if (stream->state == PENDING_PACKET_EMPTY) {
|
||||
if (G_UNLIKELY (!packet->payload_unit_start_indicator)) {
|
||||
|
@ -2074,10 +2077,6 @@ gst_ts_demux_queue_data (GstTSDemux * demux, TSDemuxStream * stream,
|
|||
} else {
|
||||
GST_LOG ("EMPTY=>HEADER");
|
||||
stream->state = PENDING_PACKET_HEADER;
|
||||
if (stream->pad) {
|
||||
GST_DEBUG ("Setting pad caps on buffer %p", buf);
|
||||
gst_buffer_set_caps (buf, GST_PAD_CAPS (stream->pad));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2170,9 +2169,7 @@ calculate_and_push_newsegment (GstTSDemux * demux, TSDemuxStream * stream)
|
|||
GST_DEBUG ("new segment: start: %" GST_TIME_FORMAT " stop: %"
|
||||
GST_TIME_FORMAT " time: %" GST_TIME_FORMAT, GST_TIME_ARGS (start),
|
||||
GST_TIME_ARGS (stop), GST_TIME_ARGS (position));
|
||||
newsegmentevent =
|
||||
gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_TIME, start, stop,
|
||||
position);
|
||||
newsegmentevent = gst_event_new_segment (&demux->segment);
|
||||
|
||||
push_event ((MpegTSBase *) demux, newsegmentevent);
|
||||
|
||||
|
@ -2183,7 +2180,9 @@ static GstFlowReturn
|
|||
gst_ts_demux_push_pending_data (GstTSDemux * demux, TSDemuxStream * stream)
|
||||
{
|
||||
GstFlowReturn res = GST_FLOW_OK;
|
||||
GList *tmp;
|
||||
MpegTSBaseStream *bs = (MpegTSBaseStream *) stream;
|
||||
GstBuffer *buf;
|
||||
|
||||
GST_DEBUG ("stream:%p, pid:0x%04x stream_type:%d state:%d pad:%s:%s",
|
||||
stream, bs->pid, bs->stream_type, stream->state,
|
||||
|
@ -2205,7 +2204,6 @@ gst_ts_demux_push_pending_data (GstTSDemux * demux, TSDemuxStream * stream)
|
|||
if (G_UNLIKELY (stream->pad == NULL)) {
|
||||
g_list_foreach (stream->currentlist, (GFunc) gst_buffer_unref, NULL);
|
||||
g_list_free (stream->currentlist);
|
||||
gst_buffer_list_iterator_free (stream->currentit);
|
||||
gst_buffer_list_unref (stream->current);
|
||||
goto beach;
|
||||
}
|
||||
|
@ -2215,16 +2213,19 @@ gst_ts_demux_push_pending_data (GstTSDemux * demux, TSDemuxStream * stream)
|
|||
|
||||
/* We have a confirmed buffer, let's push it out */
|
||||
GST_LOG ("Putting pending data into GstBufferList");
|
||||
|
||||
stream->currentlist = g_list_reverse (stream->currentlist);
|
||||
gst_buffer_list_iterator_add_list (stream->currentit, stream->currentlist);
|
||||
gst_buffer_list_iterator_free (stream->currentit);
|
||||
buf = (GstBuffer *) stream->currentlist->data;
|
||||
|
||||
for (tmp = stream->currentlist->next; tmp; tmp = tmp->next) {
|
||||
buf = gst_buffer_merge (buf, (GstBuffer *) tmp->data);
|
||||
}
|
||||
|
||||
GST_DEBUG_OBJECT (stream->pad,
|
||||
"Pushing buffer list with timestamp: %" GST_TIME_FORMAT,
|
||||
GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (gst_buffer_list_get
|
||||
(stream->current, 0, 0))));
|
||||
"Pushing buffer with timestamp: %" GST_TIME_FORMAT,
|
||||
GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)));
|
||||
|
||||
res = gst_pad_push_list (stream->pad, stream->current);
|
||||
res = gst_pad_push (stream->pad, buf);
|
||||
GST_DEBUG_OBJECT (stream->pad, "Returned %s", gst_flow_get_name (res));
|
||||
res = tsdemux_combine_flows (demux, stream, res);
|
||||
GST_DEBUG_OBJECT (stream->pad, "combined %s", gst_flow_get_name (res));
|
||||
|
@ -2246,8 +2247,10 @@ gst_ts_demux_handle_packet (GstTSDemux * demux, TSDemuxStream * stream,
|
|||
{
|
||||
GstFlowReturn res = GST_FLOW_OK;
|
||||
|
||||
#if 0
|
||||
GST_DEBUG ("buffer:%p, data:%p", GST_BUFFER_DATA (packet->buffer),
|
||||
packet->data);
|
||||
#endif
|
||||
GST_LOG ("pid 0x%04x pusi:%d, afc:%d, cont:%d, payload:%p",
|
||||
packet->pid,
|
||||
packet->payload_unit_start_indicator,
|
||||
|
@ -2256,7 +2259,7 @@ gst_ts_demux_handle_packet (GstTSDemux * demux, TSDemuxStream * stream,
|
|||
|
||||
if (section) {
|
||||
GST_DEBUG ("section complete:%d, buffer size %d",
|
||||
section->complete, GST_BUFFER_SIZE (section->buffer));
|
||||
section->complete, gst_buffer_get_size (section->buffer));
|
||||
gst_buffer_unref (packet->buffer);
|
||||
return res;
|
||||
}
|
||||
|
@ -2299,6 +2302,8 @@ gst_ts_demux_push (MpegTSBase * base, MpegTSPacketizerPacket * packet,
|
|||
TSDemuxStream *stream = NULL;
|
||||
GstFlowReturn res = GST_FLOW_OK;
|
||||
|
||||
GST_DEBUG ("packet->buffer %p", packet->buffer);
|
||||
|
||||
if (G_LIKELY (demux->program)) {
|
||||
stream = (TSDemuxStream *) demux->program->streams[packet->pid];
|
||||
|
||||
|
|
|
@ -70,6 +70,7 @@ struct _GstTSDemux
|
|||
MpegTSBaseProgram *program; /* Current program */
|
||||
guint current_program_number;
|
||||
gboolean need_newsegment;
|
||||
|
||||
/* Downstream segment */
|
||||
GstSegment segment;
|
||||
GstClockTime duration; /* Total duration */
|
||||
|
|
Loading…
Reference in a new issue