From 8ef8daf4dbdbab23ff49757a6223c3a9bfba11d3 Mon Sep 17 00:00:00 2001 From: Vincent Genieux Date: Sun, 3 May 2009 17:21:22 +0100 Subject: mpegtsparse: make safe changing the program-numbers property dynamically Fixes #569437. --- gst/mpegdemux/mpegtsparse.c | 48 ++++++++++++++++++++++----------------------- gst/mpegdemux/mpegtsparse.h | 1 + 2 files changed, 25 insertions(+), 24 deletions(-) (limited to 'gst/mpegdemux') diff --git a/gst/mpegdemux/mpegtsparse.c b/gst/mpegdemux/mpegtsparse.c index 3a2d647d..de4de35f 100644 --- a/gst/mpegdemux/mpegtsparse.c +++ b/gst/mpegdemux/mpegtsparse.c @@ -266,9 +266,11 @@ mpegts_parse_init (MpegTSParse * parse, MpegTSParseClass * klass) gst_element_add_pad (GST_ELEMENT (parse), parse->sinkpad); parse->disposed = FALSE; + parse->need_sync_program_pads = FALSE; parse->packetizer = mpegts_packetizer_new (); parse->program_numbers = g_strdup (""); parse->pads_to_add = NULL; + parse->pads_to_remove = NULL; parse->programs = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, (GDestroyNotify) mpegts_parse_free_program); parse->psi_pids = g_hash_table_new (g_direct_hash, g_direct_equal); @@ -422,22 +424,30 @@ mpegts_parse_remove_program (MpegTSParse * parse, gint program_number) } static void -mpegts_parse_sync_program_pads (MpegTSParse * parse, - GList * to_add, GList * to_remove) +mpegts_parse_sync_program_pads (MpegTSParse * parse) { GList *walk; - for (walk = to_remove; walk; walk = walk->next) + GST_INFO_OBJECT (parse, "begin sync pads"); + for (walk = parse->pads_to_remove; walk; walk = walk->next) gst_element_remove_pad (GST_ELEMENT (parse), GST_PAD (walk->data)); - for (walk = to_add; walk; walk = walk->next) + for (walk = parse->pads_to_add; walk; walk = walk->next) gst_element_add_pad (GST_ELEMENT (parse), GST_PAD (walk->data)); - if (to_add) - g_list_free (to_add); + if (parse->pads_to_add) + g_list_free (parse->pads_to_add); + + if (parse->pads_to_remove) + g_list_free (parse->pads_to_remove); + + GST_OBJECT_LOCK (parse); + parse->pads_to_remove = NULL; + parse->pads_to_add = NULL; + parse->need_sync_program_pads = FALSE; + GST_OBJECT_UNLOCK (parse); - if (to_remove) - g_list_free (to_remove); + GST_INFO_OBJECT (parse, "end sync pads"); } @@ -493,9 +503,6 @@ static void mpegts_parse_reset_selected_programs (MpegTSParse * parse, gchar * program_numbers) { - GList *pads_to_add = NULL; - GList *pads_to_remove = NULL; - GST_OBJECT_LOCK (parse); if (parse->program_numbers) g_free (parse->program_numbers); @@ -526,13 +533,9 @@ mpegts_parse_reset_selected_programs (MpegTSParse * parse, g_hash_table_foreach (parse->programs, foreach_program_activate_or_deactivate, parse); - pads_to_add = parse->pads_to_add; - parse->pads_to_add = NULL; - pads_to_remove = parse->pads_to_remove; - parse->pads_to_remove = NULL; + if (parse->pads_to_remove || parse->pads_to_add) + parse->need_sync_program_pads = TRUE; GST_OBJECT_UNLOCK (parse); - - mpegts_parse_sync_program_pads (parse, pads_to_add, pads_to_remove); } static void @@ -850,8 +853,6 @@ mpegts_parse_apply_pat (MpegTSParse * parse, GstStructure * pat_info) guint pid; MpegTSParseProgram *program; gint i; - GList *pads_to_add = NULL; - GList *pads_to_remove = NULL; const GValue *programs; gchar *dbg; @@ -942,13 +943,9 @@ mpegts_parse_apply_pat (MpegTSParse * parse, GstStructure * pat_info) gst_structure_free (old_pat); } - pads_to_add = parse->pads_to_add; - parse->pads_to_add = NULL; - pads_to_remove = parse->pads_to_remove; - parse->pads_to_remove = NULL; GST_OBJECT_UNLOCK (parse); - mpegts_parse_sync_program_pads (parse, pads_to_add, pads_to_remove); + mpegts_parse_sync_program_pads (parse); } static void @@ -1226,6 +1223,9 @@ mpegts_parse_chain (GstPad * pad, GstBuffer * buf) mpegts_packetizer_clear_packet (parse->packetizer, &packet); } + if (parse->need_sync_program_pads) + mpegts_parse_sync_program_pads (parse); + gst_object_unref (parse); return res; } diff --git a/gst/mpegdemux/mpegtsparse.h b/gst/mpegdemux/mpegtsparse.h index 34a78634..d4dc5b1e 100644 --- a/gst/mpegdemux/mpegtsparse.h +++ b/gst/mpegdemux/mpegtsparse.h @@ -61,6 +61,7 @@ struct _MpegTSParse { MpegTSPacketizer *packetizer; GHashTable *psi_pids; gboolean disposed; + gboolean need_sync_program_pads; }; struct _MpegTSParseClass { -- cgit v1.2.1 From e41401e3174b80b2e2ce4febf99f15e766dfc5c6 Mon Sep 17 00:00:00 2001 From: Vincent Genieux Date: Sun, 3 May 2009 17:42:44 +0100 Subject: mpegtsparse: Ignore subtable extension when parsing PAT Fixes #569673. --- gst/mpegdemux/mpegtspacketizer.c | 19 ++++++++++++++++++- gst/mpegdemux/mpegtspacketizer.h | 2 ++ gst/mpegdemux/mpegtsparse.c | 7 +++---- 3 files changed, 23 insertions(+), 5 deletions(-) (limited to 'gst/mpegdemux') diff --git a/gst/mpegdemux/mpegtspacketizer.c b/gst/mpegdemux/mpegtspacketizer.c index 1abbf1fe..b986fa60 100644 --- a/gst/mpegdemux/mpegtspacketizer.c +++ b/gst/mpegdemux/mpegtspacketizer.c @@ -241,7 +241,8 @@ mpegts_packetizer_parse_section_header (MpegTSPacketizer * packetizer, data = GST_BUFFER_DATA (section->buffer); section->table_id = *data++; - if ((data[0] & 0x80) == 0) + /* if table_id is 0 (pat) then ignore the subtable extension */ + if ((data[0] & 0x80) == 0 || section->table_id == 0) section->subtable_extension = 0; else section->subtable_extension = GST_READ_UINT16_BE (data + 2); @@ -1844,6 +1845,22 @@ mpegts_packetizer_clear (MpegTSPacketizer * packetizer) gst_adapter_clear (packetizer->adapter); } +void +mpegts_packetizer_remove_stream (MpegTSPacketizer * packetizer, gint16 pid) +{ + MpegTSPacketizerStream *stream = + (MpegTSPacketizerStream *) g_hash_table_lookup (packetizer->streams, + GINT_TO_POINTER ((gint) pid)); + if (stream) { + GST_INFO ("Removing stream for PID %d", pid); + + g_hash_table_remove (packetizer->streams, GINT_TO_POINTER ((gint) pid)); + + g_object_unref (stream->section_adapter); + g_free (stream); + } +} + MpegTSPacketizer * mpegts_packetizer_new () { diff --git a/gst/mpegdemux/mpegtspacketizer.h b/gst/mpegdemux/mpegtspacketizer.h index c54228af..97e15cf2 100644 --- a/gst/mpegdemux/mpegtspacketizer.h +++ b/gst/mpegdemux/mpegtspacketizer.h @@ -116,6 +116,8 @@ gboolean mpegts_packetizer_next_packet (MpegTSPacketizer *packetizer, MpegTSPacketizerPacket *packet); void mpegts_packetizer_clear_packet (MpegTSPacketizer *packetizer, MpegTSPacketizerPacket *packet); +void mpegts_packetizer_remove_stream(MpegTSPacketizer *packetizer, + gint16 pid); gboolean mpegts_packetizer_push_section (MpegTSPacketizer *packetzer, MpegTSPacketizerPacket *packet, MpegTSPacketizerSection *section); diff --git a/gst/mpegdemux/mpegtsparse.c b/gst/mpegdemux/mpegtsparse.c index de4de35f..614da36c 100644 --- a/gst/mpegdemux/mpegtsparse.c +++ b/gst/mpegdemux/mpegtsparse.c @@ -350,7 +350,7 @@ mpegts_parse_add_program (MpegTSParse * parse, program->pcr_pid = G_MAXUINT16; program->streams = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, (GDestroyNotify) mpegts_parse_free_stream); - program->patcount = 1; + program->patcount = 0; program->selected = 0; program->active = FALSE; @@ -890,14 +890,12 @@ mpegts_parse_apply_pat (MpegTSParse * parse, GstStructure * pat_info) g_hash_table_insert (parse->psi_pids, GINT_TO_POINTER ((gint) pid), GINT_TO_POINTER (1)); } - - program->patcount += 1; } else { 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); } - + program->patcount += 1; if (program->selected && !program->active) parse->pads_to_add = g_list_append (parse->pads_to_add, mpegts_parse_activate_program (parse, program)); @@ -938,6 +936,7 @@ mpegts_parse_apply_pat (MpegTSParse * parse, GstStructure * pat_info) mpegts_parse_remove_program (parse, program_number); g_hash_table_remove (parse->psi_pids, GINT_TO_POINTER ((gint) pid)); + mpegts_packetizer_remove_stream (parse->packetizer, pid); } gst_structure_free (old_pat); -- cgit v1.2.1 From 179f5bb850d0df3841889d88e3ee7ee96cc914aa Mon Sep 17 00:00:00 2001 From: Zaheer Abbas Merali Date: Mon, 4 May 2009 22:09:05 +0100 Subject: mpegtsparse: Remember pids that are meant to be stream pids. Fixes #569781 --- gst/mpegdemux/mpegtsparse.c | 14 ++++++++++++++ gst/mpegdemux/mpegtsparse.h | 1 + 2 files changed, 15 insertions(+) (limited to 'gst/mpegdemux') diff --git a/gst/mpegdemux/mpegtsparse.c b/gst/mpegdemux/mpegtsparse.c index 614da36c..976935f2 100644 --- a/gst/mpegdemux/mpegtsparse.c +++ b/gst/mpegdemux/mpegtsparse.c @@ -274,6 +274,7 @@ mpegts_parse_init (MpegTSParse * parse, MpegTSParseClass * klass) parse->programs = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, (GDestroyNotify) mpegts_parse_free_program); parse->psi_pids = g_hash_table_new (g_direct_hash, g_direct_equal); + parse->pes_pids = g_hash_table_new (g_direct_hash, g_direct_equal); mpegts_parse_reset (parse); } @@ -303,6 +304,7 @@ mpegts_parse_finalize (GObject * object) } g_hash_table_destroy (parse->programs); g_hash_table_destroy (parse->psi_pids); + g_hash_table_destroy (parse->pes_pids); if (G_OBJECT_CLASS (parent_class)->finalize) G_OBJECT_CLASS (parent_class)->finalize (object); @@ -807,6 +809,10 @@ mpegts_parse_is_psi (MpegTSParse * parse, MpegTSPacketizerPacket * packet) if (g_hash_table_lookup (parse->psi_pids, GINT_TO_POINTER ((gint) packet->pid)) != NULL) retval = TRUE; + /* check is it is a pes pid */ + if (g_hash_table_lookup (parse->pes_pids, + GINT_TO_POINTER ((gint) packet->pid)) != NULL) + return FALSE; if (!retval) { if (packet->payload_unit_start_indicator) { table_id = *(packet->data); @@ -979,10 +985,13 @@ mpegts_parse_apply_pmt (MpegTSParse * parse, 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_hash_table_remove (parse->pes_pids, GINT_TO_POINTER ((gint) pid)); } /* remove pcr stream */ mpegts_parse_program_remove_stream (parse, program, program->pcr_pid); + g_hash_table_remove (parse->pes_pids, + GINT_TO_POINTER ((gint) program->pcr_pid)); gst_structure_free (program->pmt_info); program->pmt_info = NULL; @@ -999,6 +1008,8 @@ mpegts_parse_apply_pmt (MpegTSParse * parse, program->pmt_pid = pmt_pid; program->pcr_pid = pcr_pid; mpegts_parse_program_add_stream (parse, program, (guint16) pcr_pid, -1); + g_hash_table_insert (parse->pes_pids, GINT_TO_POINTER ((gint) pcr_pid), + GINT_TO_POINTER (1)); for (i = 0; i < gst_value_list_get_size (new_streams); ++i) { value = gst_value_list_get_value (new_streams, i); @@ -1008,6 +1019,9 @@ mpegts_parse_apply_pmt (MpegTSParse * parse, gst_structure_get_uint (stream, "stream-type", &stream_type); mpegts_parse_program_add_stream (parse, program, (guint16) pid, (guint8) stream_type); + g_hash_table_insert (parse->pes_pids, GINT_TO_POINTER ((gint) pid), + GINT_TO_POINTER ((gint) 1)); + } GST_OBJECT_UNLOCK (parse); diff --git a/gst/mpegdemux/mpegtsparse.h b/gst/mpegdemux/mpegtsparse.h index d4dc5b1e..36466b81 100644 --- a/gst/mpegdemux/mpegtsparse.h +++ b/gst/mpegdemux/mpegtsparse.h @@ -60,6 +60,7 @@ struct _MpegTSParse { GstStructure *pat; MpegTSPacketizer *packetizer; GHashTable *psi_pids; + GHashTable *pes_pids; gboolean disposed; gboolean need_sync_program_pads; }; -- cgit v1.2.1 From ff7b54e7da95a401665f8d7ae922155a32edac91 Mon Sep 17 00:00:00 2001 From: Zaheer Merali Date: Fri, 8 May 2009 18:24:28 +0100 Subject: mpegtsdemux: Add initial naive seeking support and fix duration query. Sync from gst-fluendo-mpegdemux and have seeking/duration query improvements in. No support however for wrapped around pcrs etc. but a start nonetheless. Also fix indentation issues. --- gst/mpegdemux/gstmpegtsdemux.c | 272 ++++++++++++++++++++++++++++++++++++----- gst/mpegdemux/gstmpegtsdemux.h | 186 +++++++++++++++------------- 2 files changed, 341 insertions(+), 117 deletions(-) (limited to 'gst/mpegdemux') diff --git a/gst/mpegdemux/gstmpegtsdemux.c b/gst/mpegdemux/gstmpegtsdemux.c index 4464cdf8..99a499a0 100644 --- a/gst/mpegdemux/gstmpegtsdemux.c +++ b/gst/mpegdemux/gstmpegtsdemux.c @@ -34,9 +34,9 @@ * * The Original Code is Fluendo MPEG Demuxer plugin. * - * The Initial Developer of the Original Code is Fluendo, S.L. - * Portions created by Fluendo, S.L. are Copyright (C) 2005 - * Fluendo, S.L. All Rights Reserved. + * The Initial Developer of the Original Code is Fluendo, S.A. + * Portions created by Fluendo, S.L. are Copyright (C) 2005,2006,2007,2008,2009 + * Fluendo, S.A. All Rights Reserved. * * Contributor(s): Wim Taymans */ @@ -126,6 +126,13 @@ enum PROP_M2TS }; +#define GSTTIME_TO_BYTES(time) \ + ((time != -1) ? gst_util_uint64_scale (MAX(0,(gint64) ((time))), \ + demux->bitrate, GST_SECOND) : -1) +#define BYTES_TO_GSTTIME(bytes) \ + ((bytes != -1) ? (gst_util_uint64_scale (bytes, GST_SECOND, \ + demux->bitrate)) : -1) + #define VIDEO_CAPS \ GST_STATIC_CAPS (\ "video/mpeg, " \ @@ -189,6 +196,7 @@ static void gst_mpegts_demux_get_property (GObject * object, guint prop_id, static gboolean gst_mpegts_demux_is_PMT (GstMpegTSDemux * demux, guint16 PID); static gboolean gst_mpegts_demux_sink_event (GstPad * pad, GstEvent * event); +static gboolean gst_mpegts_demux_src_event (GstPad * pad, GstEvent * event); static GstFlowReturn gst_mpegts_demux_chain (GstPad * pad, GstBuffer * buffer); static gboolean gst_mpegts_demux_sink_setcaps (GstPad * pad, GstCaps * caps); @@ -327,7 +335,12 @@ gst_mpegts_demux_init (GstMpegTSDemux * demux) demux->m2ts_mode = FALSE; demux->sync_lut = NULL; demux->sync_lut_len = 0; - + demux->bitrate = -1; + demux->num_packets = 0; + demux->pcr[0] = -1; + demux->pcr[1] = -1; + demux->cache_duration = GST_CLOCK_TIME_NONE; + demux->base_pts = GST_CLOCK_TIME_NONE; #ifdef USE_LIBOIL oil_init (); #endif @@ -668,6 +681,8 @@ gst_mpegts_demux_fill_stream (GstMpegTSStream * stream, guint8 id, gst_caps_unref (caps); gst_pad_set_query_function (stream->pad, GST_DEBUG_FUNCPTR (gst_mpegts_demux_src_pad_query)); + gst_pad_set_event_function (stream->pad, + GST_DEBUG_FUNCPTR (gst_mpegts_demux_src_event)); g_free (name); return TRUE; @@ -730,7 +745,7 @@ gst_mpegts_demux_send_new_segment (GstMpegTSDemux * demux, } base_PCR = PCR_stream->base_PCR; - time = MPEGTIME_TO_GSTTIME (base_PCR); + demux->base_pts = time = MPEGTIME_TO_GSTTIME (base_PCR); GST_DEBUG_OBJECT (demux, "segment PTS to (%" G_GUINT64_FORMAT ") time: %" G_GUINT64_FORMAT, base_PCR, time); @@ -1680,7 +1695,13 @@ gst_mpegts_demux_parse_adaptation_field (GstMpegTSStream * stream, "valid pcr: %d last PCR difference: %" G_GUINT64_FORMAT, valid_pcr, stream->last_PCR_difference); if (valid_pcr) { - + if (demux->pcr[0] == -1) { + demux->pcr[0] = pcr; + demux->num_packets = 0; + } /* Considering a difference of 1 sec ie 90000 ticks */ + else if (demux->pcr[1] == -1 && ((pcr - demux->pcr[0]) >= 90000)) { + demux->pcr[1] = pcr; + } stream->last_PCR = pcr; if (demux->clock && demux->clock_base != GST_CLOCK_TIME_NONE) { @@ -1955,15 +1976,20 @@ gst_mpegts_demux_is_PMT (GstMpegTSDemux * demux, guint16 PID) } static FORCE_INLINE GstFlowReturn -gst_mpegts_stream_pes_buffer_flush (GstMpegTSStream * stream) +gst_mpegts_stream_pes_buffer_flush (GstMpegTSStream * stream, gboolean discard) { GstFlowReturn ret = GST_FLOW_OK; if (stream->pes_buffer) { - GST_BUFFER_SIZE (stream->pes_buffer) = stream->pes_buffer_used; - ret = gst_pes_filter_push (&stream->filter, stream->pes_buffer); - if (ret == GST_FLOW_LOST_SYNC) + if (discard) { + gst_buffer_unref (stream->pes_buffer); stream->pes_buffer_in_sync = FALSE; + } else { + GST_BUFFER_SIZE (stream->pes_buffer) = stream->pes_buffer_used; + ret = gst_pes_filter_push (&stream->filter, stream->pes_buffer); + if (ret == GST_FLOW_LOST_SYNC) + stream->pes_buffer_in_sync = FALSE; + } stream->pes_buffer = NULL; } return ret; @@ -1985,7 +2011,7 @@ gst_mpegts_stream_pes_buffer_push (GstMpegTSStream * stream, if (stream->pes_buffer_size < (MPEGTS_MAX_PES_BUFFER_SIZE >> 1)) stream->pes_buffer_size <<= 1; - ret = gst_mpegts_stream_pes_buffer_flush (stream); + ret = gst_mpegts_stream_pes_buffer_flush (stream, FALSE); if (ret == GST_FLOW_LOST_SYNC) goto done; } @@ -2010,7 +2036,7 @@ done: } static FORCE_INLINE GstFlowReturn -gst_mpegts_demux_pes_buffer_flush (GstMpegTSDemux * demux) +gst_mpegts_demux_pes_buffer_flush (GstMpegTSDemux * demux, gboolean discard) { gint i; GstFlowReturn ret = GST_FLOW_OK; @@ -2018,7 +2044,7 @@ gst_mpegts_demux_pes_buffer_flush (GstMpegTSDemux * demux) for (i = 0; i < MPEGTS_MAX_PID + 1; i++) { GstMpegTSStream *stream = demux->streams[i]; if (stream && stream->pad) { - gst_mpegts_stream_pes_buffer_flush (stream); + gst_mpegts_stream_pes_buffer_flush (stream, discard); stream->pes_buffer_in_sync = FALSE; } } @@ -2233,7 +2259,7 @@ gst_mpegts_demux_parse_stream (GstMpegTSDemux * demux, GstMpegTSStream * stream, "bytes of %u bytes in the PES buffer", PID, stream->pes_buffer_used, stream->pes_buffer_size); /* Flush buffered PES data */ - gst_mpegts_stream_pes_buffer_flush (stream); + gst_mpegts_stream_pes_buffer_flush (stream, FALSE); gst_pes_filter_drain (&stream->filter); /* Resize the buffer to half if no overflow detected and * had been used less than half of it */ @@ -2319,11 +2345,137 @@ gst_mpegts_demux_parse_transport_packet (GstMpegTSDemux * demux, ret = gst_mpegts_demux_parse_stream (demux, stream, data, MPEGTS_NORMAL_TS_PACKETSIZE - 1); + if (demux->pcr[1] != -1 && demux->bitrate == -1) { + GST_DEBUG_OBJECT (demux, "stream->last_PCR_difference: %" G_GINT64_FORMAT + ", demux->num_packets %" G_GUINT64_FORMAT, + demux->pcr[1] - demux->pcr[0], demux->num_packets); + demux->bitrate = gst_util_uint64_scale (GST_SECOND, + MPEGTS_NORMAL_TS_PACKETSIZE * demux->num_packets, + MPEGTIME_TO_GSTTIME (demux->pcr[1] - demux->pcr[0])); + GST_DEBUG_OBJECT (demux, "bitrate is %" G_GINT64_FORMAT + " bytes per second", demux->bitrate); + } + demux->num_packets++; return ret; /* ERRORS */ } +static gboolean +gst_mpegts_demux_handle_seek_push (GstMpegTSDemux * demux, GstEvent * event) +{ + gboolean res = FALSE; + gdouble rate; + GstFormat format; + GstSeekFlags flags; + GstSeekType start_type, stop_type; + gint64 start, stop, bstart, bstop; + GstEvent *bevent; + + gst_event_parse_seek (event, &rate, &format, &flags, &start_type, &start, + &stop_type, &stop); + + GST_DEBUG_OBJECT (demux, "seek event, rate: %f start: %" GST_TIME_FORMAT + " stop: %" GST_TIME_FORMAT, rate, GST_TIME_ARGS (start), + GST_TIME_ARGS (stop)); + + if (format == GST_FORMAT_BYTES) { + GST_DEBUG_OBJECT (demux, "seek not supported on format %d", format); + goto beach; + } + + GST_DEBUG_OBJECT (demux, "seek - trying directly upstream first"); + + /* first try original format seek */ + res = gst_pad_push_event (demux->sinkpad, gst_event_ref (event)); + if (res == TRUE) + goto beach; + GST_DEBUG_OBJECT (demux, "seek - no upstream"); + + if (format != GST_FORMAT_TIME) { + /* From here down, we only support time based seeks */ + GST_DEBUG_OBJECT (demux, "seek not supported on format %d", format); + goto beach; + } + + /* We need to convert to byte based seek and we need a scr_rate for that. */ + if (demux->bitrate == -1) { + GST_DEBUG_OBJECT (demux, "seek not possible, no bitrate"); + goto beach; + } + + GST_DEBUG_OBJECT (demux, "try with bitrate"); + + bstart = GSTTIME_TO_BYTES (start); + bstop = GSTTIME_TO_BYTES (stop); + + GST_DEBUG_OBJECT (demux, "in bytes bstart %" G_GINT64_FORMAT " bstop %" + G_GINT64_FORMAT, bstart, bstop); + bevent = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, start_type, + bstart, stop_type, bstop); + + res = gst_pad_push_event (demux->sinkpad, bevent); + +beach: + gst_event_unref (event); + return res; +} + +static gboolean +gst_mpegts_demux_src_event (GstPad * pad, GstEvent * event) +{ + GstMpegTSDemux *demux = GST_MPEGTS_DEMUX (gst_pad_get_parent (pad)); + gboolean res = FALSE; + + GST_DEBUG_OBJECT (demux, "got event %s", + gst_event_type_get_name (GST_EVENT_TYPE (event))); + + switch (GST_EVENT_TYPE (event)) { + case GST_EVENT_SEEK: + res = gst_mpegts_demux_handle_seek_push (demux, event); + break; + default: + res = gst_pad_push_event (demux->sinkpad, event); + break; + } + + gst_object_unref (demux); + + return res; +} + +static void +gst_mpegts_demux_flush (GstMpegTSDemux * demux, gboolean discard) +{ + GstMpegTSStream *PCR_stream; + GstMpegTSStream *PMT_stream; + + GST_DEBUG_OBJECT (demux, "flushing MPEG TS demuxer (discard %d)", discard); + + /* Start by flushing internal buffers */ + gst_mpegts_demux_pes_buffer_flush (demux, discard); + + /* Clear adapter */ + gst_adapter_clear (demux->adapter); + + /* Try resetting the last_PCR value as we will have a discont */ + if (demux->current_PMT == 0) + goto beach; + + PMT_stream = demux->streams[demux->current_PMT]; + if (PMT_stream == NULL) + goto beach; + + PCR_stream = demux->streams[PMT_stream->PMT.PCR_PID]; + if (PCR_stream == NULL) + goto beach; + + PCR_stream->last_PCR = -1; + +beach: + return; +} + static gboolean gst_mpegts_demux_send_event (GstMpegTSDemux * demux, GstEvent * event) { @@ -2347,7 +2499,7 @@ static gboolean gst_mpegts_demux_sink_event (GstPad * pad, GstEvent * event) { GstMpegTSDemux *demux = GST_MPEGTS_DEMUX (gst_pad_get_parent (pad)); - gboolean res; + gboolean res = FALSE; GST_DEBUG_OBJECT (demux, "got event %s", gst_event_type_get_name (GST_EVENT_TYPE (event))); @@ -2358,11 +2510,11 @@ gst_mpegts_demux_sink_event (GstPad * pad, GstEvent * event) break; case GST_EVENT_FLUSH_STOP: gst_adapter_clear (demux->adapter); + gst_mpegts_demux_flush (demux, TRUE); res = gst_mpegts_demux_send_event (demux, event); break; case GST_EVENT_EOS: - /* Flush buffered PES data */ - gst_mpegts_demux_pes_buffer_flush (demux); + gst_mpegts_demux_flush (demux, FALSE); /* Send the EOS event on each stream */ if (!(res = gst_mpegts_demux_send_event (demux, event))) { /* we have no streams */ @@ -2371,15 +2523,46 @@ gst_mpegts_demux_sink_event (GstPad * pad, GstEvent * event) } break; case GST_EVENT_NEWSEGMENT: - res = gst_mpegts_demux_send_event (demux, event); + { + gboolean update; + gdouble rate; + GstFormat format; + gint64 start, stop, time; + + gst_event_parse_new_segment (event, &update, &rate, &format, + &start, &stop, &time); + + gst_event_unref (event); + GST_INFO_OBJECT (demux, "received new segment: rate %g " + "format %d, start: %" G_GINT64_FORMAT ", stop: %" G_GINT64_FORMAT + ", time: %" G_GINT64_FORMAT, rate, format, start, stop, time); + if (format == GST_FORMAT_BYTES && demux->bitrate != -1) { + gint64 tstart = 0, tstop = 0, pos = 0; + + if (demux->base_pts != GST_CLOCK_TIME_NONE) { + tstart = tstop = demux->base_pts; + } + tstart += BYTES_TO_GSTTIME (start); + tstop += BYTES_TO_GSTTIME (stop); + pos = BYTES_TO_GSTTIME (time); + + event = gst_event_new_new_segment (update, rate, + GST_FORMAT_TIME, tstart, tstop, pos); + GST_DEBUG_OBJECT (demux, "pushing time newsegment from %" + GST_TIME_FORMAT " to %" GST_TIME_FORMAT " pos %" GST_TIME_FORMAT, + GST_TIME_ARGS (tstart), GST_TIME_ARGS (tstop), GST_TIME_ARGS (pos)); + + res = gst_mpegts_demux_send_event (demux, event); + } break; + } default: res = gst_mpegts_demux_send_event (demux, event); break; } gst_object_unref (demux); - return TRUE; + return res; } static gboolean @@ -2455,21 +2638,54 @@ gst_mpegts_demux_src_pad_query (GstPad * pad, GstQuery * query) case GST_QUERY_DURATION: { GstFormat format; - gint64 duration; + GstPad *peer; - gst_query_parse_duration (query, &format, &duration); + gst_query_parse_duration (query, &format, NULL); - if (format == GST_FORMAT_BYTES) { - res = FALSE; - } else { - res = gst_pad_query_default (pad, query); + /* Try query upstream first */ + peer = gst_pad_get_peer (demux->sinkpad); + if (peer) { + res = gst_pad_query (peer, query); + /* Try doing something with that query if it failed */ + if (!res && format == GST_FORMAT_TIME && demux->bitrate != -1) { + /* Try using cache first */ + if (GST_CLOCK_TIME_IS_VALID (demux->cache_duration)) { + GST_LOG_OBJECT (demux, "replying duration query from cache %" + GST_TIME_FORMAT, GST_TIME_ARGS (demux->cache_duration)); + gst_query_set_duration (query, GST_FORMAT_TIME, + demux->cache_duration); + res = TRUE; + } else { /* Query upstream and approximate */ + GstQuery *bquery = gst_query_new_duration (GST_FORMAT_BYTES); + gint64 duration = 0; + + /* Query peer for duration in bytes */ + res = gst_pad_query (peer, bquery); + if (res) { + /* Convert to time format */ + gst_query_parse_duration (bquery, &format, &duration); + GST_DEBUG_OBJECT (demux, "query on peer pad reported bytes %" + G_GUINT64_FORMAT, duration); + demux->cache_duration = BYTES_TO_GSTTIME (duration); + GST_DEBUG_OBJECT (demux, "converted to time %" GST_TIME_FORMAT, + GST_TIME_ARGS (demux->cache_duration)); + gst_query_set_duration (query, GST_FORMAT_TIME, + demux->cache_duration); + } + gst_query_unref (bquery); + } + } else { + GST_WARNING_OBJECT (demux, "unsupported query format or no bitrate " + "yet to approximate duration from bytes"); + } + gst_object_unref (peer); } - break; } default: res = gst_pad_query_default (pad, query); } + gst_object_unref (demux); return res; } @@ -2554,9 +2770,7 @@ gst_mpegts_demux_chain (GstPad * pad, GstBuffer * buffer) guint sync_count; if (GST_BUFFER_IS_DISCONT (buffer)) { - /* Flush buffered PES data */ - gst_mpegts_demux_pes_buffer_flush (demux); - gst_adapter_clear (demux->adapter); + gst_mpegts_demux_flush (demux, FALSE); } /* first push the new buffer into the adapter */ gst_adapter_push (demux->adapter, buffer); diff --git a/gst/mpegdemux/gstmpegtsdemux.h b/gst/mpegdemux/gstmpegtsdemux.h index 8a4ca3d2..c4a907a5 100644 --- a/gst/mpegdemux/gstmpegtsdemux.h +++ b/gst/mpegdemux/gstmpegtsdemux.h @@ -34,9 +34,9 @@ * * The Original Code is Fluendo MPEG Demuxer plugin. * - * The Initial Developer of the Original Code is Fluendo, S.L. - * Portions created by Fluendo, S.L. are Copyright (C) 2005 - * Fluendo, S.L. All Rights Reserved. + * The Initial Developer of the Original Code is Fluendo, S.A. + * Portions created by Fluendo, S.A. are Copyright (C) 2005,2006,2007,2008,2009 + * Fluendo, S.A. All Rights Reserved. * * Contributor(s): Wim Taymans */ @@ -52,18 +52,14 @@ #include "gstsectionfilter.h" G_BEGIN_DECLS - #define MPEGTS_MIN_PES_BUFFER_SIZE 4 * 1024 #define MPEGTS_MAX_PES_BUFFER_SIZE 256 * 1024 - #define MPEGTS_MAX_PID 0x1fff #define MPEGTS_NORMAL_TS_PACKETSIZE 188 #define MPEGTS_M2TS_TS_PACKETSIZE 192 - #define IS_MPEGTS_SYNC(data) (((data)[0] == 0x47) && \ (((data)[1] & 0x80) == 0x00) && \ (((data)[3] & 0x10) == 0x10)) - #define GST_TYPE_MPEGTS_DEMUX (gst_mpegts_demux_get_type()) #define GST_MPEGTS_DEMUX(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),\ GST_TYPE_MPEGTS_DEMUX,GstMpegTSDemux)) @@ -75,7 +71,6 @@ G_BEGIN_DECLS GST_TYPE_MPEGTS_DEMUX)) #define GST_IS_MPEGTS_DEMUX_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE((klass),\ GST_TYPE_MPEGTS_DEMUX)) - typedef struct _GstMpegTSStream GstMpegTSStream; typedef struct _GstMpegTSPMTEntry GstMpegTSPMTEntry; typedef struct _GstMpegTSPMT GstMpegTSPMT; @@ -84,142 +79,157 @@ typedef struct _GstMpegTSPAT GstMpegTSPAT; typedef struct _GstMpegTSDemux GstMpegTSDemux; typedef struct _GstMpegTSDemuxClass GstMpegTSDemuxClass; -struct _GstMpegTSPMTEntry { - guint16 PID; +struct _GstMpegTSPMTEntry +{ + guint16 PID; }; -struct _GstMpegTSPMT { - guint16 program_number; - guint8 version_number; - gboolean current_next_indicator; - guint8 section_number; - guint8 last_section_number; - guint16 PCR_PID; - guint16 program_info_length; - GstMPEGDescriptor * program_info; - - GArray * entries; +struct _GstMpegTSPMT +{ + guint16 program_number; + guint8 version_number; + gboolean current_next_indicator; + guint8 section_number; + guint8 last_section_number; + guint16 PCR_PID; + guint16 program_info_length; + GstMPEGDescriptor *program_info; + + GArray *entries; }; -struct _GstMpegTSPATEntry { - guint16 program_number; - guint16 PID; +struct _GstMpegTSPATEntry +{ + guint16 program_number; + guint16 PID; }; -struct _GstMpegTSPAT { - guint16 transport_stream_id; - guint8 version_number; - gboolean current_next_indicator; - guint8 section_number; - guint8 last_section_number; +struct _GstMpegTSPAT +{ + guint16 transport_stream_id; + guint8 version_number; + gboolean current_next_indicator; + guint8 section_number; + guint8 last_section_number; - GArray * entries; + GArray *entries; }; -typedef enum _MpegTsStreamFlags { +typedef enum _MpegTsStreamFlags +{ MPEGTS_STREAM_FLAG_STREAM_TYPE_UNKNOWN = 0x01, MPEGTS_STREAM_FLAG_PMT_VALID = 0x02, - MPEGTS_STREAM_FLAG_IS_VIDEO = 0x04 + MPEGTS_STREAM_FLAG_IS_VIDEO = 0x04 } MpegTsStreamFlags; /* Information associated to a single MPEG stream. */ -struct _GstMpegTSStream { - GstMpegTSDemux * demux; +struct _GstMpegTSStream +{ + GstMpegTSDemux *demux; - MpegTsStreamFlags flags; + MpegTsStreamFlags flags; /* PID and type */ - guint16 PID; - guint8 PID_type; + guint16 PID; + guint8 PID_type; /* adaptation_field data */ - guint64 last_PCR; - guint64 base_PCR; - guint64 last_OPCR; - guint64 last_PCR_difference; - gboolean discont_PCR; - GstClockTimeDiff discont_difference; + guint64 last_PCR; + guint64 base_PCR; + guint64 last_OPCR; + guint64 last_PCR_difference; + gboolean discont_PCR; + GstClockTimeDiff discont_difference; /* for PAT streams */ - GstMpegTSPAT PAT; + GstMpegTSPAT PAT; /* for PMT streams */ - GstMpegTSPMT PMT; + GstMpegTSPMT PMT; /* for CA streams */ /* for PAT, PMT, CA and private streams */ - GstSectionFilter section_filter; + GstSectionFilter section_filter; /* for PES streams */ - guint8 id; - guint8 stream_type; - GstBuffer * pes_buffer; - guint32 pes_buffer_size; - guint32 pes_buffer_used; - gboolean pes_buffer_overflow; - gboolean pes_buffer_in_sync; - GstPESFilter filter; - GstPad * pad; - GstFlowReturn last_ret; + guint8 id; + guint8 stream_type; + GstBuffer *pes_buffer; + guint32 pes_buffer_size; + guint32 pes_buffer_used; + gboolean pes_buffer_overflow; + gboolean pes_buffer_in_sync; + GstPESFilter filter; + GstPad *pad; + GstFlowReturn last_ret; GstMPEGDescriptor *ES_info; /* needed because 33bit mpeg timestamps wrap around every (approx) 26.5 hrs */ - GstClockTimeDiff base_time; - GstClockTime last_time; + GstClockTimeDiff base_time; + GstClockTime last_time; /* pid of PMT that this stream belongs to */ - guint16 PMT_pid; + guint16 PMT_pid; }; -struct _GstMpegTSDemux { - GstElement parent; +struct _GstMpegTSDemux +{ + GstElement parent; /* properties */ - gboolean check_crc; + gboolean check_crc; /* sink pad and adapter */ - GstPad * sinkpad; - GstAdapter * adapter; - guint8 ** sync_lut; - guint sync_lut_len; + GstPad *sinkpad; + GstAdapter *adapter; + guint8 **sync_lut; + guint sync_lut_len; /* current PMT PID */ - guint16 current_PMT; + guint16 current_PMT; /* Array of MPEGTS_MAX_PID + 1 stream entries */ - GstMpegTSStream ** streams; + GstMpegTSStream **streams; /* Array to perform pmts checks at gst_mpegts_demux_parse_adaptation_field */ - gboolean pmts_checked[MPEGTS_MAX_PID + 1]; - + gboolean pmts_checked[MPEGTS_MAX_PID + 1]; + /* Array of Elementary Stream pids for ts with PMT */ - guint16 * elementary_pids; - guint nb_elementary_pids; + guint16 *elementary_pids; + guint nb_elementary_pids; /* Program number to use */ - gint program_number; + gint program_number; /* indicates that we need to close our pad group, because we've added * at least one pad */ - gboolean need_no_more_pads; - guint16 packetsize; - gboolean m2ts_mode; + gboolean need_no_more_pads; + guint16 packetsize; + gboolean m2ts_mode; /* clocking */ - GstClock * clock; - GstClockTime clock_base; + GstClock *clock; + GstClockTime clock_base; + /* Additional information required for seeking */ + guint64 num_packets; + gint64 bitrate; + /* Two PCRs observations to calculate bitrate */ + gint64 pcr[2]; + GstClockTime cache_duration; + /* Cached base_PCR in GStreamer time. */ + GstClockTime base_pts; }; -struct _GstMpegTSDemuxClass { - GstElementClass parent_class; +struct _GstMpegTSDemuxClass +{ + GstElementClass parent_class; - GstPadTemplate * sink_template; - GstPadTemplate * video_template; - GstPadTemplate * audio_template; - GstPadTemplate * private_template; + GstPadTemplate *sink_template; + GstPadTemplate *video_template; + GstPadTemplate *audio_template; + GstPadTemplate *private_template; }; -GType gst_mpegts_demux_get_type (void); +GType gst_mpegts_demux_get_type (void); -gboolean gst_mpegts_demux_plugin_init (GstPlugin *plugin); +gboolean gst_mpegts_demux_plugin_init (GstPlugin * plugin); G_END_DECLS - #endif /* __GST_MPEGTS_DEMUX_H__ */ -- cgit v1.2.1 From 5aa3358f3b8604c8daf830847c77744824f53068 Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Sat, 9 May 2009 09:57:47 +0200 Subject: mpegtsdemux: Revert indentation and comment header file. One shouldn't run gst-indent on .h files, in this case it was un-beautifying the indentation :) --- gst/mpegdemux/gstmpegtsdemux.h | 191 +++++++++++++++++++++-------------------- 1 file changed, 98 insertions(+), 93 deletions(-) (limited to 'gst/mpegdemux') diff --git a/gst/mpegdemux/gstmpegtsdemux.h b/gst/mpegdemux/gstmpegtsdemux.h index c4a907a5..2e2a8e63 100644 --- a/gst/mpegdemux/gstmpegtsdemux.h +++ b/gst/mpegdemux/gstmpegtsdemux.h @@ -52,14 +52,18 @@ #include "gstsectionfilter.h" G_BEGIN_DECLS + #define MPEGTS_MIN_PES_BUFFER_SIZE 4 * 1024 #define MPEGTS_MAX_PES_BUFFER_SIZE 256 * 1024 + #define MPEGTS_MAX_PID 0x1fff #define MPEGTS_NORMAL_TS_PACKETSIZE 188 #define MPEGTS_M2TS_TS_PACKETSIZE 192 + #define IS_MPEGTS_SYNC(data) (((data)[0] == 0x47) && \ (((data)[1] & 0x80) == 0x00) && \ (((data)[3] & 0x10) == 0x10)) + #define GST_TYPE_MPEGTS_DEMUX (gst_mpegts_demux_get_type()) #define GST_MPEGTS_DEMUX(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),\ GST_TYPE_MPEGTS_DEMUX,GstMpegTSDemux)) @@ -71,6 +75,7 @@ G_BEGIN_DECLS GST_TYPE_MPEGTS_DEMUX)) #define GST_IS_MPEGTS_DEMUX_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE((klass),\ GST_TYPE_MPEGTS_DEMUX)) + typedef struct _GstMpegTSStream GstMpegTSStream; typedef struct _GstMpegTSPMTEntry GstMpegTSPMTEntry; typedef struct _GstMpegTSPMT GstMpegTSPMT; @@ -79,157 +84,157 @@ typedef struct _GstMpegTSPAT GstMpegTSPAT; typedef struct _GstMpegTSDemux GstMpegTSDemux; typedef struct _GstMpegTSDemuxClass GstMpegTSDemuxClass; -struct _GstMpegTSPMTEntry -{ - guint16 PID; +struct _GstMpegTSPMTEntry { + guint16 PID; }; -struct _GstMpegTSPMT -{ - guint16 program_number; - guint8 version_number; - gboolean current_next_indicator; - guint8 section_number; - guint8 last_section_number; - guint16 PCR_PID; - guint16 program_info_length; - GstMPEGDescriptor *program_info; - - GArray *entries; +struct _GstMpegTSPMT { + guint16 program_number; + guint8 version_number; + gboolean current_next_indicator; + guint8 section_number; + guint8 last_section_number; + guint16 PCR_PID; + guint16 program_info_length; + GstMPEGDescriptor * program_info; + + GArray * entries; }; -struct _GstMpegTSPATEntry -{ - guint16 program_number; - guint16 PID; +struct _GstMpegTSPATEntry { + guint16 program_number; + guint16 PID; }; -struct _GstMpegTSPAT -{ - guint16 transport_stream_id; - guint8 version_number; - gboolean current_next_indicator; - guint8 section_number; - guint8 last_section_number; +struct _GstMpegTSPAT { + guint16 transport_stream_id; + guint8 version_number; + gboolean current_next_indicator; + guint8 section_number; + guint8 last_section_number; - GArray *entries; + GArray * entries; }; -typedef enum _MpegTsStreamFlags -{ +typedef enum _MpegTsStreamFlags { MPEGTS_STREAM_FLAG_STREAM_TYPE_UNKNOWN = 0x01, MPEGTS_STREAM_FLAG_PMT_VALID = 0x02, - MPEGTS_STREAM_FLAG_IS_VIDEO = 0x04 + MPEGTS_STREAM_FLAG_IS_VIDEO = 0x04 } MpegTsStreamFlags; /* Information associated to a single MPEG stream. */ -struct _GstMpegTSStream -{ - GstMpegTSDemux *demux; +struct _GstMpegTSStream { + GstMpegTSDemux * demux; - MpegTsStreamFlags flags; + MpegTsStreamFlags flags; /* PID and type */ - guint16 PID; - guint8 PID_type; + guint16 PID; + guint8 PID_type; /* adaptation_field data */ - guint64 last_PCR; - guint64 base_PCR; - guint64 last_OPCR; - guint64 last_PCR_difference; - gboolean discont_PCR; - GstClockTimeDiff discont_difference; + guint64 last_PCR; + guint64 base_PCR; + guint64 last_OPCR; + guint64 last_PCR_difference; + gboolean discont_PCR; + GstClockTimeDiff discont_difference; /* for PAT streams */ - GstMpegTSPAT PAT; + GstMpegTSPAT PAT; /* for PMT streams */ - GstMpegTSPMT PMT; + GstMpegTSPMT PMT; /* for CA streams */ /* for PAT, PMT, CA and private streams */ - GstSectionFilter section_filter; + GstSectionFilter section_filter; /* for PES streams */ - guint8 id; - guint8 stream_type; - GstBuffer *pes_buffer; - guint32 pes_buffer_size; - guint32 pes_buffer_used; - gboolean pes_buffer_overflow; - gboolean pes_buffer_in_sync; - GstPESFilter filter; - GstPad *pad; - GstFlowReturn last_ret; + guint8 id; + guint8 stream_type; + GstBuffer * pes_buffer; + guint32 pes_buffer_size; + guint32 pes_buffer_used; + gboolean pes_buffer_overflow; + gboolean pes_buffer_in_sync; + GstPESFilter filter; + GstPad * pad; + GstFlowReturn last_ret; GstMPEGDescriptor *ES_info; /* needed because 33bit mpeg timestamps wrap around every (approx) 26.5 hrs */ - GstClockTimeDiff base_time; - GstClockTime last_time; + GstClockTimeDiff base_time; + GstClockTime last_time; /* pid of PMT that this stream belongs to */ - guint16 PMT_pid; + guint16 PMT_pid; }; -struct _GstMpegTSDemux -{ - GstElement parent; +struct _GstMpegTSDemux { + GstElement parent; /* properties */ - gboolean check_crc; + gboolean check_crc; /* sink pad and adapter */ - GstPad *sinkpad; - GstAdapter *adapter; - guint8 **sync_lut; - guint sync_lut_len; + GstPad * sinkpad; + GstAdapter * adapter; + guint8 ** sync_lut; + guint sync_lut_len; /* current PMT PID */ - guint16 current_PMT; + guint16 current_PMT; /* Array of MPEGTS_MAX_PID + 1 stream entries */ - GstMpegTSStream **streams; + GstMpegTSStream ** streams; /* Array to perform pmts checks at gst_mpegts_demux_parse_adaptation_field */ - gboolean pmts_checked[MPEGTS_MAX_PID + 1]; - + gboolean pmts_checked[MPEGTS_MAX_PID + 1]; + /* Array of Elementary Stream pids for ts with PMT */ - guint16 *elementary_pids; - guint nb_elementary_pids; + guint16 * elementary_pids; + guint nb_elementary_pids; /* Program number to use */ - gint program_number; + gint program_number; /* indicates that we need to close our pad group, because we've added * at least one pad */ - gboolean need_no_more_pads; - guint16 packetsize; - gboolean m2ts_mode; + gboolean need_no_more_pads; + guint16 packetsize; + gboolean m2ts_mode; /* clocking */ - GstClock *clock; - GstClockTime clock_base; - /* Additional information required for seeking */ - guint64 num_packets; - gint64 bitrate; + GstClock * clock; + GstClockTime clock_base; + + /* Additional information required for seeking. + * num_packets: Number of packets outputted + * bitrate: estimated bitrate (based on pcr and num_packets */ + guint64 num_packets; + gint64 bitrate; + /* Two PCRs observations to calculate bitrate */ - gint64 pcr[2]; - GstClockTime cache_duration; + gint64 pcr[2]; + + /* Cached duration estimation */ + GstClockTime cache_duration; + /* Cached base_PCR in GStreamer time. */ - GstClockTime base_pts; + GstClockTime base_pts; }; -struct _GstMpegTSDemuxClass -{ - GstElementClass parent_class; +struct _GstMpegTSDemuxClass { + GstElementClass parent_class; - GstPadTemplate *sink_template; - GstPadTemplate *video_template; - GstPadTemplate *audio_template; - GstPadTemplate *private_template; + GstPadTemplate * sink_template; + GstPadTemplate * video_template; + GstPadTemplate * audio_template; + GstPadTemplate * private_template; }; -GType gst_mpegts_demux_get_type (void); +GType gst_mpegts_demux_get_type (void); -gboolean gst_mpegts_demux_plugin_init (GstPlugin * plugin); +gboolean gst_mpegts_demux_plugin_init (GstPlugin *plugin); G_END_DECLS + #endif /* __GST_MPEGTS_DEMUX_H__ */ -- cgit v1.2.1 From 432dd98321f011582e17043470d1e4639c880155 Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Mon, 11 May 2009 16:40:46 +0200 Subject: mpegtsdemux: Change debugging levels for very frequent messages. This allows debugging with mpegtsdemux:4 while being able to track what's going on (and avoid taking up as much cpu for debugging as for the actual demuxing process). --- gst/mpegdemux/gstmpegtsdemux.c | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) (limited to 'gst/mpegdemux') diff --git a/gst/mpegdemux/gstmpegtsdemux.c b/gst/mpegdemux/gstmpegtsdemux.c index 99a499a0..213a4a22 100644 --- a/gst/mpegdemux/gstmpegtsdemux.c +++ b/gst/mpegdemux/gstmpegtsdemux.c @@ -843,7 +843,7 @@ gst_mpegts_demux_data_cb (GstPESFilter * filter, gboolean first, demux = stream->demux; srcpad = stream->pad; - GST_LOG_OBJECT (demux, "got data on PID 0x%04x", stream->PID); + GST_DEBUG_OBJECT (demux, "got data on PID 0x%04x", stream->PID); if (first && filter->pts != -1) { pts = filter->pts; @@ -947,7 +947,7 @@ gst_mpegts_demux_data_cb (GstPESFilter * filter, gboolean first, pts = -1; } - GST_LOG_OBJECT (demux, "setting PTS to (%" G_GUINT64_FORMAT ") time: %" + GST_DEBUG_OBJECT (demux, "setting PTS to (%" G_GUINT64_FORMAT ") time: %" GST_TIME_FORMAT " on buffer %p first buffer: %d base_time: %" GST_TIME_FORMAT, pts, GST_TIME_ARGS (time), buffer, first, GST_TIME_ARGS (stream->base_time)); @@ -996,7 +996,7 @@ gst_mpegts_demux_data_cb (GstPESFilter * filter, gboolean first, gst_mpegts_demux_send_new_segment (demux, stream, pts); } - GST_DEBUG_OBJECT (demux, "pushing buffer"); + GST_DEBUG_OBJECT (srcpad, "pushing buffer"); gst_buffer_set_caps (buffer, GST_PAD_CAPS (srcpad)); ret = gst_pad_push (srcpad, buffer); ret = gst_mpegts_demux_combine_flows (demux, stream, ret); @@ -1199,16 +1199,16 @@ gst_mpegts_stream_parse_pmt (GstMpegTSStream * stream, if (gst_mpegts_demux_calc_crc32 (data - 3, datalen) != 0) goto wrong_crc; - GST_DEBUG_OBJECT (demux, "PMT section_length: %d", datalen - 3); + GST_LOG_OBJECT (demux, "PMT section_length: %d", datalen - 3); PMT = &stream->PMT; /* check if version number changed */ version_number = (data[2] & 0x3e) >> 1; - GST_DEBUG_OBJECT (demux, "PMT version_number: %d", version_number); + GST_LOG_OBJECT (demux, "PMT version_number: %d", version_number); current_next_indicator = (data[2] & 0x01); - GST_DEBUG_OBJECT (demux, "PMT current_next_indicator %d", + GST_LOG_OBJECT (demux, "PMT current_next_indicator %d", current_next_indicator); if (current_next_indicator == 0) goto not_yet_applicable; @@ -1574,7 +1574,7 @@ gst_mpegts_demux_parse_adaptation_field (GstMpegTSStream * stream, if (length > 0) { guint8 flags = *data++; - GST_DEBUG_OBJECT (demux, "flags 0x%02x", flags); + GST_LOG_OBJECT (demux, "flags 0x%02x", flags); /* discontinuity flag */ if (flags & 0x80) { GST_DEBUG_OBJECT (demux, "discontinuity flag set"); @@ -1593,9 +1593,12 @@ gst_mpegts_demux_parse_adaptation_field (GstMpegTSStream * stream, pcr_ext = (pcr2 & 0x01ff); if (pcr_ext) pcr = (pcr * 300 + pcr_ext % 300) / 300; - GST_DEBUG_OBJECT (demux, "have PCR %" G_GUINT64_FORMAT " on PID 0x%04x " - "and last pcr is %" G_GUINT64_FORMAT, - pcr, stream->PID, stream->last_PCR); + GST_DEBUG_OBJECT (demux, + "have PCR %" G_GUINT64_FORMAT "(%" GST_TIME_FORMAT ") on PID 0x%04x " + "and last pcr is %" G_GUINT64_FORMAT " (%" GST_TIME_FORMAT ")", pcr, + GST_TIME_ARGS (MPEGTIME_TO_GSTTIME (pcr)), stream->PID, + stream->last_PCR, + GST_TIME_ARGS (MPEGTIME_TO_GSTTIME (stream->last_PCR))); /* pcr has been converted into units of 90Khz ticks * so assume discont if last pcr was > 900000 (10 second) lower */ if (stream->last_PCR != -1 && @@ -2119,7 +2122,7 @@ gst_mpegts_demux_parse_stream (GstMpegTSDemux * demux, GstMpegTSStream * stream, data += 3; datalen -= 3; - GST_DEBUG_OBJECT (demux, "afc 0x%x, pusi %d, PID 0x%04x datalen %u", + GST_LOG_OBJECT (demux, "afc 0x%x, pusi %d, PID 0x%04x datalen %u", adaptation_field_control, payload_unit_start_indicator, PID, datalen); ret = GST_FLOW_OK; @@ -2141,13 +2144,12 @@ gst_mpegts_demux_parse_stream (GstMpegTSDemux * demux, GstMpegTSStream * stream, data += consumed; datalen -= consumed; - GST_DEBUG_OBJECT (demux, "consumed: %u datalen: %u", consumed, datalen); + GST_LOG_OBJECT (demux, "consumed: %u datalen: %u", consumed, datalen); } /* If this packet has a payload, handle it */ if (adaptation_field_control & 0x1) { - GST_DEBUG_OBJECT (demux, "Packet payload %d bytes, PID 0x%04x", datalen, - PID); + GST_LOG_OBJECT (demux, "Packet payload %d bytes, PID 0x%04x", datalen, PID); /* For unknown streams, check if the PID is in the partial PIDs * list as an elementary stream and override the type if so -- cgit v1.2.1 From bc062b9acf1232ee5643dd7976741c7a47378cd6 Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Mon, 11 May 2009 16:58:58 +0200 Subject: mpegtsdemux: Only take PCR from the active stream for bitrate estimation. --- gst/mpegdemux/gstmpegtsdemux.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) (limited to 'gst/mpegdemux') diff --git a/gst/mpegdemux/gstmpegtsdemux.c b/gst/mpegdemux/gstmpegtsdemux.c index 213a4a22..f07e1743 100644 --- a/gst/mpegdemux/gstmpegtsdemux.c +++ b/gst/mpegdemux/gstmpegtsdemux.c @@ -1694,16 +1694,23 @@ gst_mpegts_demux_parse_adaptation_field (GstMpegTSStream * stream, } stream->last_PCR_difference = pcr - stream->last_PCR; } + GST_DEBUG_OBJECT (demux, "valid pcr: %d last PCR difference: %" G_GUINT64_FORMAT, valid_pcr, stream->last_PCR_difference); if (valid_pcr) { - if (demux->pcr[0] == -1) { - demux->pcr[0] = pcr; - demux->num_packets = 0; - } /* Considering a difference of 1 sec ie 90000 ticks */ - else if (demux->pcr[1] == -1 && ((pcr - demux->pcr[0]) >= 90000)) { - demux->pcr[1] = pcr; + GstMpegTSStream *PMT_stream = demux->streams[demux->current_PMT]; + + if (PMT_stream && PMT_stream->PMT.PCR_PID == stream->PID) { + if (demux->pcr[0] == -1) { + GST_DEBUG ("RECORDING pcr[0]:%" G_GUINT64_FORMAT, pcr); + demux->pcr[0] = pcr; + demux->num_packets = 0; + } /* Considering a difference of 1 sec ie 90000 ticks */ + else if (demux->pcr[1] == -1 && ((pcr - demux->pcr[0]) >= 90000)) { + GST_DEBUG ("RECORDING pcr[1]:%" G_GUINT64_FORMAT, pcr); + demux->pcr[1] = pcr; + } } stream->last_PCR = pcr; -- cgit v1.2.1 From f9dfc44a67320b6f73bb34e05ec80e67e9c8c087 Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Mon, 11 May 2009 16:59:20 +0200 Subject: mpegtsdemux: Protect bitrate estimation against bogus values. If the estimated bitrate is lower than 188 bytes, there's most likely something completely wrong with the two samples. If that happens, force recalculation. Use guint64 for observation PCR, I saw cases where it would overflow. --- gst/mpegdemux/gstmpegtsdemux.c | 21 +++++++++++++++++---- gst/mpegdemux/gstmpegtsdemux.h | 2 +- 2 files changed, 18 insertions(+), 5 deletions(-) (limited to 'gst/mpegdemux') diff --git a/gst/mpegdemux/gstmpegtsdemux.c b/gst/mpegdemux/gstmpegtsdemux.c index f07e1743..cad385d0 100644 --- a/gst/mpegdemux/gstmpegtsdemux.c +++ b/gst/mpegdemux/gstmpegtsdemux.c @@ -2355,14 +2355,27 @@ gst_mpegts_demux_parse_transport_packet (GstMpegTSDemux * demux, MPEGTS_NORMAL_TS_PACKETSIZE - 1); if (demux->pcr[1] != -1 && demux->bitrate == -1) { - GST_DEBUG_OBJECT (demux, "stream->last_PCR_difference: %" G_GINT64_FORMAT + guint64 bitrate; + GST_DEBUG_OBJECT (demux, "pcr[0]:%" G_GUINT64_FORMAT, demux->pcr[0]); + GST_DEBUG_OBJECT (demux, "pcr[1]:%" G_GUINT64_FORMAT, demux->pcr[1]); + GST_DEBUG_OBJECT (demux, "diff in time %" GST_TIME_FORMAT, + GST_TIME_ARGS (MPEGTIME_TO_GSTTIME (demux->pcr[1] - demux->pcr[0]))); + GST_DEBUG_OBJECT (demux, "stream->last_PCR_difference: %" G_GUINT64_FORMAT ", demux->num_packets %" G_GUINT64_FORMAT, demux->pcr[1] - demux->pcr[0], demux->num_packets); - demux->bitrate = gst_util_uint64_scale (GST_SECOND, + bitrate = gst_util_uint64_scale (GST_SECOND, MPEGTS_NORMAL_TS_PACKETSIZE * demux->num_packets, MPEGTIME_TO_GSTTIME (demux->pcr[1] - demux->pcr[0])); - GST_DEBUG_OBJECT (demux, "bitrate is %" G_GINT64_FORMAT - " bytes per second", demux->bitrate); + /* somehow... I doubt a bitrate below one packet per second is valid */ + if (bitrate > MPEGTS_NORMAL_TS_PACKETSIZE - 1) { + demux->bitrate = bitrate; + GST_DEBUG_OBJECT (demux, "bitrate is %" G_GINT64_FORMAT + " bytes per second", demux->bitrate); + } else { + GST_WARNING_OBJECT (demux, "Couldn't compute valid bitrate, recomputing"); + demux->pcr[0] = demux->pcr[1] = -1; + demux->num_packets = -1; + } } demux->num_packets++; return ret; diff --git a/gst/mpegdemux/gstmpegtsdemux.h b/gst/mpegdemux/gstmpegtsdemux.h index 2e2a8e63..dad2b023 100644 --- a/gst/mpegdemux/gstmpegtsdemux.h +++ b/gst/mpegdemux/gstmpegtsdemux.h @@ -213,7 +213,7 @@ struct _GstMpegTSDemux { gint64 bitrate; /* Two PCRs observations to calculate bitrate */ - gint64 pcr[2]; + guint64 pcr[2]; /* Cached duration estimation */ GstClockTime cache_duration; -- cgit v1.2.1 From 580b20d6cc155b21e7b0f74f0e4fd28af2c7ce41 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 21 May 2009 16:00:46 +0200 Subject: mpegtsdemux: fix memleaks and refcounts Use correct constants for PID_type so that we clear the right filter. provide_clock must return a ref to a clock. --- gst/mpegdemux/gstmpegtsdemux.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'gst/mpegdemux') diff --git a/gst/mpegdemux/gstmpegtsdemux.c b/gst/mpegdemux/gstmpegtsdemux.c index cad385d0..6438e880 100644 --- a/gst/mpegdemux/gstmpegtsdemux.c +++ b/gst/mpegdemux/gstmpegtsdemux.c @@ -382,8 +382,8 @@ gst_mpegts_demux_reset (GstMpegTSDemux * demux) case PID_TYPE_ELEMENTARY: gst_pes_filter_uninit (&stream->filter); break; - case PID_PROGRAM_ASSOCIATION_TABLE: - case PID_CONDITIONAL_ACCESS_TABLE: + case PID_TYPE_PROGRAM_ASSOCIATION: + case PID_TYPE_CONDITIONAL_ACCESS: case PID_TYPE_PROGRAM_MAP: gst_section_filter_uninit (&stream->section_filter); break; @@ -2620,8 +2620,7 @@ gst_mpegts_demux_provide_clock (GstElement * element) "MpegTSClock", NULL); demux->clock_base = GST_CLOCK_TIME_NONE; } - - return demux->clock; + return gst_object_ref (demux->clock); } return NULL; -- cgit v1.2.1 From f92f282874addd1091e2d03b25033a12f151eb83 Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Mon, 25 May 2009 15:21:12 +0200 Subject: mpegtsdemux: Add mapping for HDV private streams --- gst/mpegdemux/gstmpegdefs.h | 2 ++ gst/mpegdemux/gstmpegtsdemux.c | 10 ++++++++++ 2 files changed, 12 insertions(+) (limited to 'gst/mpegdemux') diff --git a/gst/mpegdemux/gstmpegdefs.h b/gst/mpegdemux/gstmpegdefs.h index 7f38f4de..d63667d8 100644 --- a/gst/mpegdemux/gstmpegdefs.h +++ b/gst/mpegdemux/gstmpegdefs.h @@ -170,6 +170,8 @@ #define ST_PS_AUDIO_AC3 0x81 #define ST_PS_AUDIO_DTS 0x8a #define ST_PS_AUDIO_LPCM 0x8b +#define ST_HDV_PRIVATE_A0 0xa0 +#define ST_HDV_PRIVATE_A1 0xa1 #define ST_PS_DVD_SUBPICTURE 0xff /* Un-official time-code stream */ diff --git a/gst/mpegdemux/gstmpegtsdemux.c b/gst/mpegdemux/gstmpegtsdemux.c index 6438e880..a4d32e36 100644 --- a/gst/mpegdemux/gstmpegtsdemux.c +++ b/gst/mpegdemux/gstmpegtsdemux.c @@ -620,6 +620,16 @@ gst_mpegts_demux_fill_stream (GstMpegTSStream * stream, guint8 id, caps = gst_caps_new_simple ("private/teletext", NULL); } break; + case ST_HDV_PRIVATE_A0: + template = klass->private_template; + name = g_strdup_printf ("private_%04x", stream->PID); + caps = gst_caps_new_simple ("private/hdv-a0", NULL); + break; + case ST_HDV_PRIVATE_A1: + template = klass->private_template; + name = g_strdup_printf ("private_%04x", stream->PID); + caps = gst_caps_new_simple ("private/hdv-a1", NULL); + break; case ST_PRIVATE_SECTIONS: case ST_MHEG: case ST_DSMCC: -- cgit v1.2.1 From 36cc757bdacbfbeadfce70040fd424b5e7bb2e8b Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Mon, 25 May 2009 15:21:52 +0200 Subject: mpegtsdemux: Ignore NULL packets as early as possible. This avoids: * creating a MpegTSStream structure for nothing * processing packet data for nothing --- gst/mpegdemux/gstmpegtsdemux.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'gst/mpegdemux') diff --git a/gst/mpegdemux/gstmpegtsdemux.c b/gst/mpegdemux/gstmpegtsdemux.c index a4d32e36..cd64a295 100644 --- a/gst/mpegdemux/gstmpegtsdemux.c +++ b/gst/mpegdemux/gstmpegtsdemux.c @@ -2347,7 +2347,7 @@ static FORCE_INLINE GstFlowReturn gst_mpegts_demux_parse_transport_packet (GstMpegTSDemux * demux, const guint8 * data) { - GstFlowReturn ret; + GstFlowReturn ret = GST_FLOW_OK; guint16 PID; GstMpegTSStream *stream; @@ -2357,6 +2357,10 @@ gst_mpegts_demux_parse_transport_packet (GstMpegTSDemux * demux, /* get PID */ PID = ((data[0] & 0x1f) << 8) | data[1]; + /* Skip NULL packets */ + if (G_UNLIKELY (PID == 0x1fff)) + goto beach; + /* get the stream. */ stream = gst_mpegts_demux_get_stream_for_PID (demux, PID); @@ -2387,6 +2391,8 @@ gst_mpegts_demux_parse_transport_packet (GstMpegTSDemux * demux, demux->num_packets = -1; } } + +beach: demux->num_packets++; return ret; -- cgit v1.2.1 From 849ea993587746eff034f5788569e7a991af716b Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Mon, 25 May 2009 16:25:42 +0200 Subject: gstpesfilter: Don't skip private streams PES but push them out. The one thing we *DO* need to do for those streams is to skip all the PTS/DTS/Scrambling/DSM/extension/... handling. --- gst/mpegdemux/gstpesfilter.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'gst/mpegdemux') diff --git a/gst/mpegdemux/gstpesfilter.c b/gst/mpegdemux/gstpesfilter.c index 1295a193..a2a6b764 100644 --- a/gst/mpegdemux/gstpesfilter.c +++ b/gst/mpegdemux/gstpesfilter.c @@ -189,7 +189,8 @@ gst_pes_filter_parse (GstPESFilter * filter) case ID_PROGRAM_STREAM_DIRECTORY: case ID_DSMCC_STREAM: case ID_ITU_TREC_H222_TYPE_E_STREAM: - goto skip; + /* Push directly out */ + goto push_out; case ID_PADDING_STREAM: GST_DEBUG ("skipping padding stream"); goto skip; @@ -404,6 +405,7 @@ gst_pes_filter_parse (GstPESFilter * filter) goto lost_sync; } +push_out: { GstBuffer *out; guint16 consumed; -- cgit v1.2.1 From 410d8f891035656606382c423e57ae289c17a9be Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Mon, 25 May 2009 16:27:34 +0200 Subject: gstpesfilter: Don't peek the adapter if we don't have enough data. --- gst/mpegdemux/gstpesfilter.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'gst/mpegdemux') diff --git a/gst/mpegdemux/gstpesfilter.c b/gst/mpegdemux/gstpesfilter.c index a2a6b764..4285c940 100644 --- a/gst/mpegdemux/gstpesfilter.c +++ b/gst/mpegdemux/gstpesfilter.c @@ -167,6 +167,9 @@ gst_pes_filter_parse (GstPESFilter * filter) avail = MIN (avail, filter->length + 6); } + if (avail < 7) + goto need_more_data; + /* read more data, either the whole packet if there is a length * or whatever we have available if this in an unbounded packet. */ if (!(data = gst_adapter_peek (filter->adapter, avail))) @@ -198,9 +201,6 @@ gst_pes_filter_parse (GstPESFilter * filter) break; } - if (datalen < 1) - goto need_more_data; - filter->pts = filter->dts = -1; /* stuffing bits, first two bits are '10' for mpeg2 pes so this code is -- cgit v1.2.1 From 023af351fba4b22db782b39f4aa8ae75b70cc10f Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Mon, 11 May 2009 19:30:34 +0200 Subject: gstpesfilter: Directly use gst_adapter_take_buffer(). --- gst/mpegdemux/gstpesfilter.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) (limited to 'gst/mpegdemux') diff --git a/gst/mpegdemux/gstpesfilter.c b/gst/mpegdemux/gstpesfilter.c index 4285c940..b520c766 100644 --- a/gst/mpegdemux/gstpesfilter.c +++ b/gst/mpegdemux/gstpesfilter.c @@ -565,14 +565,8 @@ gst_pes_filter_process (GstPESFilter * filter) ret = GST_FLOW_OK; } else { GstBuffer *out; - guint8 *data; - data = gst_adapter_take (filter->adapter, avail); - - out = gst_buffer_new (); - GST_BUFFER_DATA (out) = data; - GST_BUFFER_SIZE (out) = avail; - GST_BUFFER_MALLOCDATA (out) = data; + out = gst_adapter_take_buffer (filter->adapter, avail); ret = gst_pes_filter_data_push (filter, filter->first, out); filter->first = FALSE; -- cgit v1.2.1