From a82c0aa533158c6f43b462450deac2eb3b22168e Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 27 Nov 2002 21:00:12 +0000 Subject: [PATCH] Fix mpegdemux, implement caching Original commit message from CVS: Fix mpegdemux, implement caching --- gst/mpegstream/gstmpegdemux.c | 225 ++++++++++++++++++++---------- gst/mpegstream/gstmpegdemux.h | 55 +++----- gst/mpegstream/gstmpegpacketize.c | 2 + gst/mpegstream/gstmpegparse.c | 97 ++++++++++--- gst/mpegstream/gstmpegparse.h | 7 +- 5 files changed, 254 insertions(+), 132 deletions(-) diff --git a/gst/mpegstream/gstmpegdemux.c b/gst/mpegstream/gstmpegdemux.c index 195c29d148..b480222338 100644 --- a/gst/mpegstream/gstmpegdemux.c +++ b/gst/mpegstream/gstmpegdemux.c @@ -127,15 +127,20 @@ GST_PAD_TEMPLATE_FACTORY (subtitle_factory, ) ); -static void gst_mpeg_demux_class_init (GstMPEGDemuxClass *klass); -static void gst_mpeg_demux_init (GstMPEGDemux *mpeg_demux); +static void gst_mpeg_demux_class_init (GstMPEGDemuxClass *klass); +static void gst_mpeg_demux_init (GstMPEGDemux *mpeg_demux); -static gboolean gst_mpeg_demux_parse_packhead (GstMPEGParse *mpeg_parse, GstBuffer *buffer); -static gboolean gst_mpeg_demux_parse_syshead (GstMPEGParse *mpeg_parse, GstBuffer *buffer); -static gboolean gst_mpeg_demux_parse_packet (GstMPEGParse *mpeg_parse, GstBuffer *buffer); -static gboolean gst_mpeg_demux_parse_pes (GstMPEGParse *mpeg_parse, GstBuffer *buffer); -static void gst_mpeg_demux_send_data (GstMPEGParse *mpeg_parse, GstData *data, GstClockTime time); -static void gst_mpeg_demux_handle_discont (GstMPEGParse *mpeg_parse); +static gboolean gst_mpeg_demux_parse_packhead (GstMPEGParse *mpeg_parse, GstBuffer *buffer); +static gboolean gst_mpeg_demux_parse_syshead (GstMPEGParse *mpeg_parse, GstBuffer *buffer); +static gboolean gst_mpeg_demux_parse_packet (GstMPEGParse *mpeg_parse, GstBuffer *buffer); +static gboolean gst_mpeg_demux_parse_pes (GstMPEGParse *mpeg_parse, GstBuffer *buffer); +static void gst_mpeg_demux_send_data (GstMPEGParse *mpeg_parse, + GstData *data, GstClockTime time); + +static void gst_mpeg_demux_handle_discont (GstMPEGParse *mpeg_parse); + +static void gst_mpeg_demux_set_cache (GstElement *element, GstCache *cache); +static GstCache* gst_mpeg_demux_get_cache (GstElement *element); static GstElementStateReturn gst_mpeg_demux_change_state (GstElement *element); @@ -177,6 +182,8 @@ gst_mpeg_demux_class_init (GstMPEGDemuxClass *klass) gstelement_class = (GstElementClass *) klass; gstelement_class->change_state = gst_mpeg_demux_change_state; + gstelement_class->set_cache = gst_mpeg_demux_set_cache; + gstelement_class->get_cache = gst_mpeg_demux_get_cache; mpeg_parse_class->parse_packhead = gst_mpeg_demux_parse_packhead; mpeg_parse_class->parse_syshead = gst_mpeg_demux_parse_syshead; @@ -200,23 +207,33 @@ gst_mpeg_demux_init (GstMPEGDemux *mpeg_demux) gst_element_remove_pad (GST_ELEMENT (mpeg_parse), mpeg_parse->srcpad); /* i think everything is already zero'd, but oh well*/ - for (i=0;iprivate_1_pad[i] = NULL; + for (i=0;iprivate_1_stream[i] = NULL; } - for (i=0;isubtitle_pad[i] = NULL; + for (i=0;isubtitle_stream[i] = NULL; } - mpeg_demux->private_2_pad = NULL; - for (i=0;ivideo_pad[i] = NULL; + mpeg_demux->private_2_stream = NULL; + for (i=0;ivideo_stream[i] = NULL; } - for (i=0;iaudio_pad[i] = NULL; + for (i=0;iaudio_stream[i] = NULL; } GST_FLAG_SET (mpeg_demux, GST_ELEMENT_EVENT_AWARE); } +static GstMPEGStream* +gst_mpeg_demux_new_stream (void) +{ + GstMPEGStream *stream; + + stream = g_new0 (GstMPEGStream, 1); + + return stream; +} + static void gst_mpeg_demux_send_data (GstMPEGParse *mpeg_parse, GstData *data, GstClockTime time) { @@ -245,26 +262,26 @@ gst_mpeg_demux_handle_discont (GstMPEGParse *mpeg_parse) GST_DEBUG (GST_CAT_EVENT, "discont %llu\n", current_time); - for (i=0;ivideo_pad[i] && - GST_PAD_IS_USABLE (mpeg_demux->video_pad[i])) + for (i=0;ivideo_stream[i] && + GST_PAD_IS_USABLE (mpeg_demux->video_stream[i]->pad)) { GstEvent *discont; discont = gst_event_new_discontinuous (FALSE, GST_FORMAT_TIME, current_time, NULL); - gst_pad_push (mpeg_demux->video_pad[i], GST_BUFFER (discont)); + gst_pad_push (mpeg_demux->video_stream[i]->pad, GST_BUFFER (discont)); } - if (mpeg_demux->audio_pad[i] && - GST_PAD_IS_USABLE (mpeg_demux->audio_pad[i])) + if (mpeg_demux->audio_stream[i] && + GST_PAD_IS_USABLE (mpeg_demux->audio_stream[i]->pad)) { GstEvent *discont; discont = gst_event_new_discontinuous (FALSE, GST_FORMAT_TIME, current_time, NULL); - gst_pad_push (mpeg_demux->audio_pad[i], GST_BUFFER (discont)); + gst_pad_push (mpeg_demux->audio_stream[i]->pad, GST_BUFFER (discont)); } } } @@ -325,7 +342,7 @@ gst_mpeg_demux_parse_syshead (GstMPEGParse *mpeg_parse, GstBuffer *buffer) guint16 STD_buffer_size_bound; guint32 buf_byte_size_bound; gchar *name = NULL; - GstPad **outpad = NULL; + GstMPEGStream **outstream = NULL; GstPadTemplate *newtemp = NULL; stream_id = *buf++; @@ -355,24 +372,24 @@ gst_mpeg_demux_parse_syshead (GstMPEGParse *mpeg_parse, GstBuffer *buffer) /* private_stream_1 */ case 0xBD: name = NULL; - outpad = NULL; + outstream = NULL; break; /* private_stream_2 */ case 0xBF: name = g_strdup_printf ("private_stream_2"); - outpad = &mpeg_demux->private_2_pad; + outstream = &mpeg_demux->private_2_stream; newtemp = GST_PAD_TEMPLATE_GET (private2_factory); break; /* Audio */ case 0xC0 ... 0xDF: name = g_strdup_printf ("audio_%02d", stream_id & 0x1F); - outpad = &mpeg_demux->audio_pad[stream_id & 0x1F]; + outstream = &mpeg_demux->audio_stream[stream_id & 0x1F]; newtemp = GST_PAD_TEMPLATE_GET (audio_factory); break; /* Video */ case 0xE0 ... 0xEF: name = g_strdup_printf ("video_%02d", stream_id & 0x0F); - outpad = &mpeg_demux->video_pad[stream_id & 0x0F]; + outstream = &mpeg_demux->video_stream[stream_id & 0x0F]; if (!GST_MPEG_PARSE_IS_MPEG2 (mpeg_demux)) { newtemp = GST_PAD_TEMPLATE_GET (video_mpeg1_factory); } @@ -394,7 +411,12 @@ gst_mpeg_demux_parse_syshead (GstMPEGParse *mpeg_parse, GstBuffer *buffer) * this should trigger the NEW_PAD signal, which should be caught by * the app and used to attach to desired streams. */ - if (outpad && *outpad == NULL) { + if (outstream && *outstream == NULL) { + GstPad **outpad; + + *outstream = gst_mpeg_demux_new_stream (); + outpad = &((*outstream)->pad); + *outpad = gst_pad_new_from_template (newtemp, name); gst_pad_try_set_caps (*outpad, gst_pad_get_pad_template_caps (*outpad)); @@ -406,6 +428,11 @@ gst_mpeg_demux_parse_syshead (GstMPEGParse *mpeg_parse, GstBuffer *buffer) gst_element_add_pad (GST_ELEMENT (mpeg_demux), (*outpad)); + if (mpeg_demux->cache) { + gst_cache_get_writer_id (mpeg_demux->cache, GST_OBJECT (*outpad), + &(*outstream)->cache_id); + } + if (GST_PAD_IS_USABLE (*outpad)) { GstEvent *event; gint64 time; @@ -424,12 +451,6 @@ gst_mpeg_demux_parse_syshead (GstMPEGParse *mpeg_parse, GstBuffer *buffer) g_free (name); } - mpeg_demux->STD_buffer_info[j].stream_id = stream_id; - mpeg_demux->STD_buffer_info[j].STD_buffer_bound_scale = - STD_buffer_bound_scale; - mpeg_demux->STD_buffer_info[j].STD_buffer_size_bound = - STD_buffer_size_bound; - j++; } } @@ -453,9 +474,11 @@ gst_mpeg_demux_parse_packet (GstMPEGParse *mpeg_parse, GstBuffer *buffer) guint16 datalen; - GstPad **outpad = NULL; + GstMPEGStream **outstream = NULL; + GstPad *outpad = NULL; GstBuffer *outbuf; guint8 *buf, *basebuf; + gint64 timestamp; GST_DEBUG (0, "in parse_packet"); @@ -559,7 +582,7 @@ done: case 0x80 ... 0x87: GST_DEBUG (0, "0x%02X: we have a private_stream_1 (AC3) packet, track %d", id, ps_id_code - 0x80); - outpad = &mpeg_demux->private_1_pad[ps_id_code - 0x80]; + outstream = &mpeg_demux->private_1_stream[ps_id_code - 0x80]; /* scrap first 4 bytes (so-called "mystery AC3 tag") */ headerlen += 4; datalen -= 4; @@ -571,55 +594,66 @@ done: /* private_stream_2 */ case 0xBF: GST_DEBUG (0, "0x%02X: we have a private_stream_2 packet", id); - outpad = &mpeg_demux->private_2_pad; + outstream = &mpeg_demux->private_2_stream; break; /* audio */ case 0xC0 ... 0xDF: GST_DEBUG (0, "0x%02X: we have an audio packet", id); - outpad = &mpeg_demux->audio_pad[id & 0x1F]; + outstream = &mpeg_demux->audio_stream[id & 0x1F]; break; /* video */ case 0xE0 ... 0xEF: GST_DEBUG (0, "0x%02X: we have a video packet", id); - outpad = &mpeg_demux->video_pad[id & 0x0F]; + outstream = &mpeg_demux->video_stream[id & 0x0F]; break; default: break; } /* if we don't know what it is, bail */ - if (outpad == NULL) { + if (outstream == NULL) { GST_DEBUG (0, "unknown packet id 0x%02X !!", id); return FALSE; } + outpad = (*outstream)->pad; + /* the pad should have been created in parse_syshead */ - if ((*outpad) == NULL) { + if (outpad == NULL) { GST_DEBUG (0, "unexpected packet id 0x%02X!!", id); return FALSE; } + /* attach pts, if any */ + if (pts != -1) { + pts += mpeg_parse->adjust; + timestamp = MPEGTIME_TO_GSTTIME (pts); + + if (mpeg_demux->cache) { + gst_cache_add_association (mpeg_demux->cache, + (*outstream)->cache_id, 0, + GST_FORMAT_BYTES, GST_BUFFER_OFFSET (buffer), + GST_FORMAT_TIME, timestamp, + 0); + } + } + else { + timestamp = GST_CLOCK_TIME_NONE; + } + /* create the buffer and send it off to the Other Side */ - if (GST_PAD_IS_CONNECTED(*outpad) && datalen > 0) { + if (GST_PAD_IS_CONNECTED (outpad) && datalen > 0) { GST_DEBUG (0, "creating subbuffer len %d", datalen); /* if this is part of the buffer, create a subbuffer */ outbuf = gst_buffer_create_sub (buffer, headerlen + 4, datalen); - /* attach pts, if any */ - if (pts != -1) { - pts += mpeg_parse->adjust; - - GST_BUFFER_TIMESTAMP (outbuf) = MPEGTIME_TO_GSTTIME (pts); - } - else { - GST_BUFFER_TIMESTAMP (outbuf) = -1LL; - } + GST_BUFFER_TIMESTAMP (outbuf) = timestamp; GST_DEBUG (0, "pushing buffer of len %d id %d, ts %lld", datalen, id, GST_BUFFER_TIMESTAMP (outbuf)); - gst_pad_push ((*outpad), outbuf); + gst_pad_push (outpad, outbuf); } return TRUE; @@ -639,6 +673,7 @@ gst_mpeg_demux_parse_pes (GstMPEGParse *mpeg_parse, GstBuffer *buffer) guint16 headerlen; guint8 ps_id_code = 0x80; + GstMPEGStream **outstream = NULL; GstPad **outpad = NULL; GstBuffer *outbuf; GstPadTemplate *newtemp = NULL; @@ -723,7 +758,7 @@ gst_mpeg_demux_parse_pes (GstMPEGParse *mpeg_parse, GstBuffer *buffer) case 0x80 ... 0x87: GST_DEBUG (0, "we have a private_stream_1 (AC3) packet, track %d", ps_id_code - 0x80); - outpad = &mpeg_demux->private_1_pad[ps_id_code - 0x80]; + outstream = &mpeg_demux->private_1_stream[ps_id_code - 0x80]; /* scrap first 4 bytes (so-called "mystery AC3 tag") */ headerlen += 4; datalen -= 4; @@ -731,7 +766,7 @@ gst_mpeg_demux_parse_pes (GstMPEGParse *mpeg_parse, GstBuffer *buffer) case 0x20 ... 0x2f: GST_DEBUG (0, "we have a subtitle_stream packet, track %d", ps_id_code - 0x20); - outpad = &mpeg_demux->subtitle_pad[ps_id_code - 0x20]; + outstream = &mpeg_demux->subtitle_stream[ps_id_code - 0x20]; headerlen += 1; datalen -= 1; break; @@ -744,17 +779,17 @@ gst_mpeg_demux_parse_pes (GstMPEGParse *mpeg_parse, GstBuffer *buffer) /* private_stream_2 */ case 0xBF: GST_DEBUG (0, "we have a private_stream_2 packet"); - outpad = &mpeg_demux->private_2_pad; + outstream = &mpeg_demux->private_2_stream; break; /* audio */ case 0xC0 ... 0xDF: GST_DEBUG (0, "we have an audio packet"); - outpad = &mpeg_demux->audio_pad[id - 0xC0]; + outstream = &mpeg_demux->audio_stream[id - 0xC0]; break; /* video */ case 0xE0 ... 0xEF: GST_DEBUG (0, "we have a video packet"); - outpad = &mpeg_demux->video_pad[id - 0xE0]; + outstream = &mpeg_demux->video_stream[id - 0xE0]; break; default: GST_DEBUG (0, "we have a unkown packet"); @@ -762,13 +797,13 @@ gst_mpeg_demux_parse_pes (GstMPEGParse *mpeg_parse, GstBuffer *buffer) } /* if we don't know what it is, bail */ - if (outpad == NULL) + if (outstream == NULL) return TRUE; /* create the pad and add it if we don't already have one. */ /* this should trigger the NEW_PAD signal, which should be caught by */ /* the app and used to attach to desired streams. */ - if ((*outpad) == NULL) { + if ((*outstream) == NULL) { gchar *name = NULL; /* we have to name the stream approriately */ @@ -811,9 +846,12 @@ gst_mpeg_demux_parse_pes (GstMPEGParse *mpeg_parse, GstBuffer *buffer) } if (newtemp) { + *outstream = gst_mpeg_demux_new_stream (); + outpad = &((*outstream)->pad); + /* create the pad and add it to self */ - (*outpad) = gst_pad_new_from_template (newtemp, name); - gst_pad_try_set_caps ((*outpad), gst_pad_get_pad_template_caps (*outpad)); + *outpad = gst_pad_new_from_template (newtemp, name); + gst_pad_try_set_caps (*outpad, gst_pad_get_pad_template_caps (*outpad)); gst_pad_set_formats_function (*outpad, gst_mpeg_parse_get_src_formats); gst_pad_set_event_mask_function (*outpad, gst_mpeg_parse_get_src_event_masks); @@ -821,7 +859,12 @@ gst_mpeg_demux_parse_pes (GstMPEGParse *mpeg_parse, GstBuffer *buffer) gst_pad_set_query_type_function (*outpad, gst_mpeg_parse_get_src_query_types); gst_pad_set_query_function (*outpad, gst_mpeg_parse_handle_src_query); - gst_element_add_pad(GST_ELEMENT(mpeg_demux),(*outpad)); + gst_element_add_pad(GST_ELEMENT(mpeg_demux), *outpad); + + if (mpeg_demux->cache) { + gst_cache_get_writer_id (mpeg_demux->cache, GST_OBJECT (*outpad), + &(*outstream)->cache_id); + } } else { g_warning ("cannot create pad %s, no template for %02x", name, id); @@ -830,23 +873,39 @@ gst_mpeg_demux_parse_pes (GstMPEGParse *mpeg_parse, GstBuffer *buffer) g_free (name); } - /* create the buffer and send it off to the Other Side */ - if (GST_PAD_IS_USABLE(*outpad)) { - /* if this is part of the buffer, create a subbuffer */ - GST_DEBUG (0,"creating subbuffer len %d", datalen); + if (*outstream) { + gint64 timestamp; - outbuf = gst_buffer_create_sub (buffer, headerlen+4, datalen); + outpad = &((*outstream)->pad); + /* attach pts, if any */ if (pts != -1) { pts += mpeg_parse->adjust; + timestamp = MPEGTIME_TO_GSTTIME (pts); - GST_BUFFER_TIMESTAMP (outbuf) = MPEGTIME_TO_GSTTIME (pts); + if (mpeg_demux->cache) { + gst_cache_add_association (mpeg_demux->cache, + (*outstream)->cache_id, 0, + GST_FORMAT_BYTES, GST_BUFFER_OFFSET (buffer), + GST_FORMAT_TIME, timestamp, + 0); + } } else { - GST_BUFFER_TIMESTAMP (outbuf) = -1LL; + timestamp = GST_CLOCK_TIME_NONE; } - gst_pad_push((*outpad),outbuf); + /* create the buffer and send it off to the Other Side */ + if (*outpad && GST_PAD_IS_USABLE(*outpad)) { + /* if this is part of the buffer, create a subbuffer */ + GST_DEBUG (0,"creating subbuffer len %d", datalen); + + outbuf = gst_buffer_create_sub (buffer, headerlen+4, datalen); + + GST_BUFFER_TIMESTAMP (outbuf) = timestamp; + + gst_pad_push(*outpad,outbuf); + } } return TRUE; @@ -871,6 +930,28 @@ gst_mpeg_demux_change_state (GstElement *element) return GST_ELEMENT_CLASS (parent_class)->change_state (element); } +static void +gst_mpeg_demux_set_cache (GstElement *element, GstCache *cache) +{ + GstMPEGDemux *mpeg_demux; + + GST_ELEMENT_CLASS (parent_class)->set_cache (element, cache); + + mpeg_demux = GST_MPEG_DEMUX (element); + + mpeg_demux->cache = cache; +} + +static GstCache* +gst_mpeg_demux_get_cache (GstElement *element) +{ + GstMPEGDemux *mpeg_demux; + + mpeg_demux = GST_MPEG_DEMUX (element); + + return mpeg_demux->cache; +} + gboolean gst_mpeg_demux_plugin_init (GModule *module, GstPlugin *plugin) diff --git a/gst/mpegstream/gstmpegdemux.h b/gst/mpegstream/gstmpegdemux.h index fdb0f60fe6..eab84e24de 100644 --- a/gst/mpegstream/gstmpegdemux.h +++ b/gst/mpegstream/gstmpegdemux.h @@ -46,41 +46,23 @@ extern "C" { typedef struct _GstMPEGDemux GstMPEGDemux; typedef struct _GstMPEGDemuxClass GstMPEGDemuxClass; -typedef struct _MPEG1Stream MPEG1Stream; +typedef struct _GstMPEGStream GstMPEGStream; -struct _MPEG1Stream { - guchar stream_id; - gint8 STD_buffer_bound_scale; - gint16 STD_buffer_size_bound; -}; - -typedef struct _GstMPEG1StreamContext GstMPEG1StreamContext; - -struct _GstMPEGStreamContext { - GstPad *pad; - guint64 pts; +struct _GstMPEGStream { + gint8 STD_buffer_bound_scale; + gint16 STD_buffer_size_bound; + GstPad *pad; + guint64 pts; + gint cache_id; }; struct _GstMPEGDemux { GstMPEGParse parent; - /* current parse state */ - guchar id; - /* previous partial chunk and bytes remaining in it */ gboolean in_flush; - /* counters */ - gulong packs; - - /* pack header values */ - gboolean have_packhead; - guint64 scr_base; - guint16 scr_extension; - guint32 bit_rate; - /* program stream header values */ - gboolean have_syshead; guint16 header_length; guint32 rate_bound; guint8 audio_bound; @@ -90,19 +72,20 @@ struct _GstMPEGDemux { gboolean video_lock; guint8 video_bound; gboolean packet_rate_restriction; - struct _MPEG1Stream STD_buffer_info[48]; -#define NUM_PRIVATE_1_PADS 8 -#define NUM_SUBTITLE_PADS 16 -#define NUM_VIDEO_PADS 16 -#define NUM_AUDIO_PADS 32 +#define NUM_PRIVATE_1_STREAMS 8 +#define NUM_SUBTITLE_STREAMS 16 +#define NUM_VIDEO_STREAMS 16 +#define NUM_AUDIO_STREAMS 32 - /* stream output pads */ - GstPad *private_1_pad[NUM_PRIVATE_1_PADS]; /* up to 8 ac3 audio tracks */ - GstPad *subtitle_pad[NUM_SUBTITLE_PADS]; - GstPad *private_2_pad; - GstPad *video_pad[NUM_VIDEO_PADS]; - GstPad *audio_pad[NUM_AUDIO_PADS]; + /* stream output */ + GstMPEGStream *private_1_stream[NUM_PRIVATE_1_STREAMS]; /* up to 8 ac3 audio tracks */ + GstMPEGStream *subtitle_stream[NUM_SUBTITLE_STREAMS]; + GstMPEGStream *private_2_stream; + GstMPEGStream *video_stream[NUM_VIDEO_STREAMS]; + GstMPEGStream *audio_stream[NUM_AUDIO_STREAMS]; + + GstCache *cache; }; struct _GstMPEGDemuxClass { diff --git a/gst/mpegstream/gstmpegpacketize.c b/gst/mpegstream/gstmpegpacketize.c index 88ee8751ec..024cd6e8b3 100644 --- a/gst/mpegstream/gstmpegpacketize.c +++ b/gst/mpegstream/gstmpegpacketize.c @@ -250,6 +250,8 @@ gst_mpeg_packetize_read (GstMPEGPacketize *packetize) gst_bytestream_get_status (packetize->bs, &remaining, &event); etype = event? GST_EVENT_TYPE (event) : GST_EVENT_EOS; + g_print ("remaining %d\n", remaining); + switch (etype) { case GST_EVENT_DISCONTINUOUS: GST_DEBUG (GST_CAT_EVENT, "packetize: discont\n"); diff --git a/gst/mpegstream/gstmpegparse.c b/gst/mpegstream/gstmpegparse.c index 8b554f2085..c0e43c1cc6 100644 --- a/gst/mpegstream/gstmpegparse.c +++ b/gst/mpegstream/gstmpegparse.c @@ -22,6 +22,8 @@ #include "gstmpegparse.h" #include "gstmpegclock.h" +static GstFormat scr_format; + /* elementfactory information */ static GstElementDetails mpeg_parse_details = { "MPEG System Parser", @@ -36,6 +38,8 @@ static GstElementDetails mpeg_parse_details = { #define CLASS(o) GST_MPEG_PARSE_CLASS (G_OBJECT_GET_CLASS (o)) +#define DEFAULT_MAX_DISCONT 10000 + /* GstMPEGParse signals and args */ enum { /* FILL ME */ @@ -47,6 +51,7 @@ enum { ARG_BIT_RATE, ARG_MPEG2, ARG_SYNC, + ARG_MAX_DISCONT, /* FILL ME */ }; @@ -94,6 +99,8 @@ static void gst_mpeg_parse_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec); static void gst_mpeg_parse_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec); +static void gst_mpeg_parse_set_cache (GstElement *element, GstCache *tc); +static GstCache* gst_mpeg_parse_get_cache (GstElement *element); static GstElementClass *parent_class = NULL; /*static guint gst_mpeg_parse_signals[LAST_SIGNAL] = { 0 };*/ @@ -139,11 +146,19 @@ gst_mpeg_parse_class_init (GstMPEGParseClass *klass) g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_SYNC, g_param_spec_boolean ("sync", "Sync", "Synchronize on the stream SCR", FALSE, G_PARAM_READWRITE)); + g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_MAX_DISCONT, + g_param_spec_int ("max_discont", "Max Discont", "The maximun allowed SCR discontinuity", + 0, G_MAXINT, DEFAULT_MAX_DISCONT, G_PARAM_READWRITE)); gobject_class->get_property = gst_mpeg_parse_get_property; gobject_class->set_property = gst_mpeg_parse_set_property; gstelement_class->change_state = gst_mpeg_parse_change_state; + gstelement_class->get_clock = gst_mpeg_parse_get_clock; + gstelement_class->set_clock = gst_mpeg_parse_set_clock; + gstelement_class->get_cache = gst_mpeg_parse_get_cache; + gstelement_class->set_cache = gst_mpeg_parse_set_cache; + klass->parse_packhead = gst_mpeg_parse_parse_packhead; klass->parse_syshead = NULL; @@ -182,12 +197,10 @@ gst_mpeg_parse_init (GstMPEGParse *mpeg_parse) mpeg_parse->mux_rate = 0; mpeg_parse->discont_pending = FALSE; mpeg_parse->scr_pending = TRUE; + mpeg_parse->max_discont = DEFAULT_MAX_DISCONT; mpeg_parse->provided_clock = gst_mpeg_clock_new ("MPEGParseClock", gst_mpeg_parse_get_time, mpeg_parse); - GST_ELEMENT (mpeg_parse)->getclockfunc = gst_mpeg_parse_get_clock; - GST_ELEMENT (mpeg_parse)->setclockfunc = gst_mpeg_parse_set_clock; - GST_FLAG_SET (mpeg_parse, GST_ELEMENT_EVENT_AWARE); } @@ -270,7 +283,7 @@ static gboolean gst_mpeg_parse_parse_packhead (GstMPEGParse *mpeg_parse, GstBuffer *buffer) { guint8 *buf; - guint64 scr, scr_adj; + guint64 scr, scr_adj, scr_orig; guint32 scr1, scr2; guint32 new_rate; @@ -299,8 +312,6 @@ gst_mpeg_parse_parse_packhead (GstMPEGParse *mpeg_parse, GstBuffer *buffer) scr, scr_ext, scr1, scr2, mpeg_parse->bytes_since_scr, scr - mpeg_parse->current_scr); - mpeg_parse->bytes_since_scr = 0; - buf += 6; new_rate = (GUINT32_FROM_BE ((*(guint32 *) buf)) & 0xfffffc00) >> 10; } @@ -309,13 +320,13 @@ gst_mpeg_parse_parse_packhead (GstMPEGParse *mpeg_parse, GstBuffer *buffer) scr |= (scr1 & 0x00fffe00) << 6; scr |= (scr1 & 0x000000ff) << 7; scr |= (scr2 & 0xfe000000) >> 25; - - mpeg_parse->bytes_since_scr = 0; buf += 5; new_rate = (GUINT32_FROM_BE ((*(guint32 *) buf)) & 0x7ffffe00) >> 9; } + scr_orig = scr; + mpeg_parse->bytes_since_scr = 0; scr_adj = scr + mpeg_parse->adjust; GST_DEBUG (0, "SCR is %llu (%llu) next: %lld (%lld) diff: %lld (%lld)", @@ -327,7 +338,7 @@ gst_mpeg_parse_parse_packhead (GstMPEGParse *mpeg_parse, GstBuffer *buffer) MPEGTIME_TO_GSTTIME (scr) - MPEGTIME_TO_GSTTIME (mpeg_parse->next_scr)); - if (ABS ((gint64)mpeg_parse->next_scr - (gint64)(scr_adj)) > 10000) { + if (ABS ((gint64)mpeg_parse->next_scr - (gint64)(scr_adj)) > mpeg_parse->max_discont) { GST_DEBUG (0, "discontinuity detected; expected: %llu got: %llu real:%lld adjust:%lld", mpeg_parse->next_scr, scr_adj, scr, mpeg_parse->adjust); @@ -340,8 +351,16 @@ gst_mpeg_parse_parse_packhead (GstMPEGParse *mpeg_parse, GstBuffer *buffer) scr = scr_adj; } + if (mpeg_parse->cache) { + /* update cache if any */ + gst_cache_add_association (mpeg_parse->cache, mpeg_parse->cache_id, + GST_ACCOCIATION_FLAG_KEY_UNIT, + GST_FORMAT_BYTES, GST_BUFFER_OFFSET (buffer), + GST_FORMAT_TIME, MPEGTIME_TO_GSTTIME (scr), + scr_format, scr_orig, 0); + } + mpeg_parse->current_scr = scr; - mpeg_parse->scr_pending = FALSE; if (mpeg_parse->mux_rate != new_rate) { @@ -466,17 +485,23 @@ gst_mpeg_parse_loop (GstElement *element) bss = mpeg_parse->bytes_since_scr; br = mpeg_parse->mux_rate * 50; - if (GST_MPEG_PACKETIZE_IS_MPEG2 (mpeg_parse->packetize)) { - /* - * The mpeg spec says something like this, but that doesn't really work: - * - * mpeg_parse->next_scr = (scr * br + bss * 90000LL) / (90000LL + br); - */ - mpeg_parse->next_scr = scr + (bss * 90000LL) / br; + if (br) { + if (GST_MPEG_PACKETIZE_IS_MPEG2 (mpeg_parse->packetize)) { + /* + * The mpeg spec says something like this, but that doesn't really work: + * + * mpeg_parse->next_scr = (scr * br + bss * 90000LL) / (90000LL + br); + */ + mpeg_parse->next_scr = scr + (bss * 90000LL) / br; + } + else { + /* we are interpolating the scr here */ + mpeg_parse->next_scr = scr + (bss * 90000LL) / br; + } } else { - /* we are interpolating the scr here */ - mpeg_parse->next_scr = scr + (bss * 90000LL) / br; + /* no bitrate known */ + mpeg_parse->next_scr = scr; } GST_DEBUG (0, "size: %lld, total since SCR: %lld, next SCR: %lld", @@ -660,6 +685,9 @@ gst_mpeg_parse_get_property (GObject *object, guint prop_id, GValue *value, GPar case ARG_SYNC: g_value_set_boolean (value, mpeg_parse->sync); break; + case ARG_MAX_DISCONT: + g_value_set_int (value, mpeg_parse->max_discont); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -672,19 +700,44 @@ gst_mpeg_parse_set_property (GObject *object, guint prop_id, { GstMPEGParse *mpeg_parse; - /* it's not null if we got it, but it might not be ours */ - mpeg_parse = GST_MPEG_PARSE(object); + mpeg_parse = GST_MPEG_PARSE (object); switch (prop_id) { case ARG_SYNC: mpeg_parse->sync = g_value_get_boolean (value); break; + case ARG_MAX_DISCONT: + mpeg_parse->max_discont = g_value_get_int (value); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } +static void +gst_mpeg_parse_set_cache (GstElement *element, GstCache *cache) +{ + GstMPEGParse *mpeg_parse; + + mpeg_parse = GST_MPEG_PARSE (element); + + mpeg_parse->cache = cache; + + gst_cache_get_writer_id (cache, GST_OBJECT (mpeg_parse->sinkpad), + &mpeg_parse->cache_id); + gst_cache_add_format (cache, mpeg_parse->cache_id, scr_format); +} + +static GstCache* +gst_mpeg_parse_get_cache (GstElement *element) +{ + GstMPEGParse *mpeg_parse; + + mpeg_parse = GST_MPEG_PARSE (element); + + return mpeg_parse->cache; +} gboolean gst_mpeg_parse_plugin_init (GModule *module, GstPlugin *plugin) @@ -700,6 +753,8 @@ gst_mpeg_parse_plugin_init (GModule *module, GstPlugin *plugin) &mpeg_parse_details); g_return_val_if_fail(factory != NULL, FALSE); + scr_format = gst_format_register ("scr", "The MPEG system clock reference time"); + gst_element_factory_add_pad_template (factory, GST_PAD_TEMPLATE_GET (src_factory)); gst_element_factory_add_pad_template (factory, GST_PAD_TEMPLATE_GET (sink_factory)); diff --git a/gst/mpegstream/gstmpegparse.h b/gst/mpegstream/gstmpegparse.h index a388bec4cc..9abeddf467 100644 --- a/gst/mpegstream/gstmpegparse.h +++ b/gst/mpegstream/gstmpegparse.h @@ -21,13 +21,10 @@ #ifndef __MPEG_PARSE_H__ #define __MPEG_PARSE_H__ - -#include #include #include #include "gstmpegpacketize.h" - #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ @@ -68,10 +65,14 @@ struct _GstMPEGParse { gboolean discont_pending; gboolean scr_pending; + gint max_discont; GstClock *provided_clock; GstClock *clock; gboolean sync; + + GstCache *cache; + gint cache_id; }; struct _GstMPEGParseClass {