From: <wt...@fr...> - 2005-07-21 12:17:54
|
CVS Root: /cvs/gstreamer Module: gst-plugins-base Changes by: wtay Date: Thu Jul 21 2005 05:17:50 PDT Log message: * ext/ogg/gstoggdemux.c: (gst_ogg_pad_init), (gst_ogg_pad_event), (gst_ogg_pad_internal_chain), (gst_ogg_pad_typefind), (gst_ogg_demux_chain_elem_pad), (gst_ogg_demux_queue_data), (gst_ogg_demux_chain_peer), (gst_ogg_pad_submit_packet), (gst_ogg_pad_submit_page), (gst_ogg_chain_new), (gst_ogg_demux_init), (gst_ogg_demux_deactivate_current_chain), (gst_ogg_demux_activate_chain), (gst_ogg_demux_perform_seek), (gst_ogg_demux_read_chain), (gst_ogg_demux_find_pad), (gst_ogg_demux_collect_chain_info), (gst_ogg_demux_collect_info), (gst_ogg_demux_find_chains), (gst_ogg_demux_chain), (gst_ogg_demux_send_event), (gst_ogg_demux_loop), (gst_ogg_demux_change_state), (gst_ogg_print): Reorganize code to send the right disconts when in streaming mode. Modified files: . : ChangeLog ext/ogg : gstoggdemux.c Links: http://freedesktop.org/cgi-bin/viewcvs.cgi/gstreamer/gst-plugins-base/ChangeLog.diff?r1=1.1799&r2=1.1800 http://freedesktop.org/cgi-bin/viewcvs.cgi/gstreamer/gst-plugins-base/ext/ogg/gstoggdemux.c.diff?r1=1.92&r2=1.93 ====Begin Diffs==== Index: ChangeLog =================================================================== RCS file: /cvs/gstreamer/gst-plugins-base/ChangeLog,v retrieving revision 1.1799 retrieving revision 1.1800 diff -u -d -r1.1799 -r1.1800 --- ChangeLog 20 Jul 2005 17:30:45 -0000 1.1799 +++ ChangeLog 21 Jul 2005 12:17:37 -0000 1.1800 @@ -1,3 +1,20 @@ +2005-07-21 Wim Taymans <wi...@fl...> + + * ext/ogg/gstoggdemux.c: (gst_ogg_pad_init), (gst_ogg_pad_event), + (gst_ogg_pad_internal_chain), (gst_ogg_pad_typefind), + (gst_ogg_demux_chain_elem_pad), (gst_ogg_demux_queue_data), + (gst_ogg_demux_chain_peer), (gst_ogg_pad_submit_packet), + (gst_ogg_pad_submit_page), (gst_ogg_chain_new), + (gst_ogg_demux_init), (gst_ogg_demux_deactivate_current_chain), + (gst_ogg_demux_activate_chain), (gst_ogg_demux_perform_seek), + (gst_ogg_demux_read_chain), (gst_ogg_demux_find_pad), + (gst_ogg_demux_collect_chain_info), (gst_ogg_demux_collect_info), + (gst_ogg_demux_find_chains), (gst_ogg_demux_chain), + (gst_ogg_demux_send_event), (gst_ogg_demux_loop), + (gst_ogg_demux_change_state), (gst_ogg_print): + Reorganize code to send the right disconts when in streaming + mode. 2005-07-20 Andy Wingo <wi...@po...> * gst/videoscale/vs_image.c (vs_image_scale_nearest_YUYV): Typo Index: gstoggdemux.c RCS file: /cvs/gstreamer/gst-plugins-base/ext/ogg/gstoggdemux.c,v retrieving revision 1.92 retrieving revision 1.93 diff -u -d -r1.92 -r1.93 --- gstoggdemux.c 16 Jul 2005 14:47:26 -0000 1.92 +++ gstoggdemux.c 21 Jul 2005 12:17:37 -0000 1.93 @@ -75,11 +75,11 @@ GstClockTime total_time; /* the total time of this chain, this is the MAX of the totals of all streams */ - GstClockTime start_time; /* the timestamp of the first sample */ - GstClockTime last_time; /* the timestamp of the last page == last sample */ - + GstClockTime start_time; /* the timestamp of the first sample, this is the MIN of + the start times of all streams. */ + GstClockTime last_time; /* the timestamp of the last page, this is the MAX of the + streams. */ GstClockTime begin_time; /* when this chain starts in the stream */ } GstOggChain; /* different modes for the pad */ @@ -97,6 +97,7 @@ { PARENT pad; /* subclass GstPad */ + gboolean have_type; GstOggPadMode mode; GstPad *elem_pad; /* sinkpad of internal element */ @@ -110,11 +111,6 @@ gint serialno; gint64 packetno; - gint64 offset; - gint64 start; - gint64 stop; gint64 current_granule; GstClockTime start_time; /* the timestamp of the first sample */ @@ -155,18 +151,24 @@ OggState state; gboolean seekable; + gboolean running; gboolean need_chains; /* state */ GMutex *chain_lock; /* we need the lock to protect the chains */ GArray *chains; /* list of chains we know */ + GstClockTime start_time; /* the start time of the first chain */ GstClockTime total_time; /* the total time of this ogg, this is the sum of the totals of all chains */ GstOggChain *current_chain; GstOggChain *building_chain; + /* playback start/stop positions */ + GstClockTime segment_start; + GstClockTime segment_stop; + gboolean segment_play; /* ogg stuff */ ogg_sync_state sync; }; @@ -182,7 +184,12 @@ GST_PAD_ALWAYS, GST_STATIC_CAPS_ANY); -static gboolean gst_ogg_demux_perform_seek (GstOggDemux * ogg, gint64 pos); +static gboolean gst_ogg_demux_collect_chain_info (GstOggDemux * ogg, + GstOggChain * chain); +static gboolean gst_ogg_demux_activate_chain (GstOggDemux * ogg, + GstOggChain * chain, GstEvent * event); +static gboolean gst_ogg_demux_perform_seek (GstOggDemux * ogg, gboolean flush); static void gst_ogg_pad_class_init (GstOggPadClass * klass); static void gst_ogg_pad_init (GstOggPad * pad); @@ -256,10 +263,12 @@ pad->last_granule = -1; pad->current_granule = -1; - pad->start_time = -1; - pad->first_time = -1; - pad->last_time = -1; + pad->start_time = GST_CLOCK_TIME_NONE; + pad->first_time = GST_CLOCK_TIME_NONE; + pad->last_time = GST_CLOCK_TIME_NONE; + pad->total_time = GST_CLOCK_TIME_NONE; + pad->have_type = FALSE; pad->headers = NULL; } @@ -382,23 +391,44 @@ switch (GST_EVENT_TYPE (event)) { case GST_EVENT_SEEK: { - gint64 offset; + gboolean running; + gboolean flush; - /* can't seek if we are not seekable */ + /* can't seek if we are not seekable, FIXME could pass the + * seek query upstream after converting it to bytes using + * the average bitrate of the stream. */ if (!ogg->seekable) { res = FALSE; + GST_DEBUG ("seek on non seekable stream"); goto done_unref; } /* we can only seek on time */ if (GST_EVENT_SEEK_FORMAT (event) != GST_FORMAT_TIME) { + GST_DEBUG ("can only seek on TIME"); - offset = GST_EVENT_SEEK_OFFSET (event); + ogg->segment_start = GST_EVENT_SEEK_OFFSET (event); + ogg->segment_stop = GST_EVENT_SEEK_ENDOFFSET (event); + ogg->segment_play = + !!(GST_EVENT_SEEK_TYPE (event) & GST_SEEK_FLAG_SEGMENT_LOOP); + flush = !!(GST_EVENT_SEEK_TYPE (event) & GST_SEEK_FLAG_FLUSH); gst_event_unref (event); + GST_DEBUG ("segment positions set to %" GST_TIME_FORMAT "-%" + GST_TIME_FORMAT, GST_TIME_ARGS (ogg->segment_start), + GST_TIME_ARGS (ogg->segment_stop)); + /* check if we can do the seek now */ + GST_LOCK (ogg); + running = ogg->running; + GST_UNLOCK (ogg); /* now do the seek */ - res = gst_ogg_demux_perform_seek (ogg, offset); + if (running) { + res = gst_ogg_demux_perform_seek (ogg, flush); + } else + res = TRUE; break; } default: @@ -409,6 +439,7 @@ return res; done_unref: + GST_DEBUG ("error handling event"); gst_event_unref (event); @@ -506,7 +537,7 @@ GST_DEBUG_OBJECT (oggpad, "received buffer from iternal pad, TS=%lld", timestamp); - if (oggpad->start_time == -1) + if (oggpad->start_time == GST_CLOCK_TIME_NONE) oggpad->start_time = timestamp; gst_buffer_unref (buffer); @@ -539,53 +570,48 @@ caps = gst_caps_new_simple ("application/octet-stream", NULL); } else { /* ogg requires you to use a decoder element to define the - * meaning of granulepos etc so we make one. We only do this if - * we are in the seeking mode. */ - if (ogg->seekable) { - GList *factories; + * meaning of granulepos etc so we make one. We also do this if + * we are in the streaming mode to calculate the first timestamp. */ + GList *factories; - /* first filter out the interesting element factories */ - factories = gst_registry_pool_feature_filter ( - (GstPluginFeatureFilter) gst_ogg_demux_factory_filter, FALSE, caps); + /* first filter out the interesting element factories */ + factories = gst_registry_pool_feature_filter ( + (GstPluginFeatureFilter) gst_ogg_demux_factory_filter, FALSE, caps); - /* sort them according to their ranks */ - factories = g_list_sort (factories, (GCompareFunc) compare_ranks); + /* sort them according to their ranks */ + factories = g_list_sort (factories, (GCompareFunc) compare_ranks); - /* then pick the first factory to create an element */ - if (factories) { - element = - gst_element_factory_create (GST_ELEMENT_FACTORY (factories->data), - NULL); - if (element) { - /* this is ours */ - gst_object_ref (element); - gst_object_sink (GST_OBJECT (element)); + /* then pick the first factory to create an element */ + if (factories) { + element = + gst_element_factory_create (GST_ELEMENT_FACTORY (factories->data), + NULL); + if (element) { + /* this is ours */ + gst_object_ref (element); + gst_object_sink (GST_OBJECT (element)); - /* FIXME, it might not be named "sink" */ - pad->elem_pad = gst_element_get_pad (element, "sink"); - gst_element_set_state (element, GST_STATE_PAUSED); - pad->elem_out = - gst_pad_new_from_template (gst_static_pad_template_get - (&internaltemplate), "internal"); - gst_pad_set_chain_function (pad->elem_out, - gst_ogg_pad_internal_chain); - gst_pad_set_element_private (pad->elem_out, pad); - gst_pad_set_active (pad->elem_out, TRUE); + /* FIXME, it might not be named "sink" */ + pad->elem_pad = gst_element_get_pad (element, "sink"); + gst_element_set_state (element, GST_STATE_PAUSED); + pad->elem_out = + gst_pad_new_from_template (gst_static_pad_template_get + (&internaltemplate), "internal"); + gst_pad_set_chain_function (pad->elem_out, gst_ogg_pad_internal_chain); + gst_pad_set_element_private (pad->elem_out, pad); + gst_pad_set_active (pad->elem_out, TRUE); - /* and this pad may not be named src.. */ - { - GstPad *p; + /* and this pad may not be named src.. */ + { + GstPad *p; - p = gst_element_get_pad (element, "src"); - gst_pad_link (p, pad->elem_out); - gst_object_unref (p); - } + p = gst_element_get_pad (element, "src"); + gst_pad_link (p, pad->elem_out); + gst_object_unref (p); } - g_list_free (factories); - } else { - pad->mode = GST_OGG_PAD_MODE_STREAMING; + g_list_free (factories); } pad->element = element; @@ -595,6 +621,96 @@ return TRUE; +/* send packet to internal element */ +static GstFlowReturn +gst_ogg_demux_chain_elem_pad (GstOggPad * pad, ogg_packet * packet) +{ + GstBuffer *buf; + GstFlowReturn ret; + GstOggDemux *ogg = pad->ogg; + /* initialize our internal decoder with packets */ + if (!pad->elem_pad) + goto no_decoder; + GST_DEBUG_OBJECT (ogg, "%p init decoder serial %08lx", pad, pad->serialno); + buf = gst_buffer_new_and_alloc (packet->bytes); + memcpy (GST_BUFFER_DATA (buf), packet->packet, packet->bytes); + gst_buffer_set_caps (buf, GST_PAD_CAPS (pad)); + GST_BUFFER_OFFSET (buf) = -1; + GST_BUFFER_OFFSET_END (buf) = packet->granulepos; + ret = gst_pad_chain (pad->elem_pad, buf); + if (GST_FLOW_IS_FATAL (ret)) + goto decoder_error; + return ret; +no_decoder: + { + GST_WARNING_OBJECT (ogg, + "pad %08lx does not have elem_pad, no decoder ?", pad); + return GST_FLOW_ERROR; + } +decoder_error: + GST_WARNING_OBJECT (ogg, "internal decoder error"); +} +/* queue data */ +gst_ogg_demux_queue_data (GstOggPad * pad, ogg_packet * packet) + GST_DEBUG_OBJECT (ogg, "%p queueing data serial %08lx", pad, pad->serialno); + memcpy (buf->data, packet->packet, packet->bytes); + pad->headers = g_list_append (pad->headers, buf); + /* we are ok now */ + return GST_FLOW_OK; +gst_ogg_demux_chain_peer (GstOggPad * pad, ogg_packet * packet) + ret = gst_pad_alloc_buffer (GST_PAD (pad), GST_BUFFER_OFFSET_NONE, + packet->bytes, GST_PAD_CAPS (pad), &buf); + GST_DEBUG_OBJECT (ogg, + "%p streaming to peer serial %08lx", pad, pad->serialno); + if (ret == GST_FLOW_OK) { + memcpy (buf->data, packet->packet, packet->bytes); + GST_BUFFER_OFFSET (buf) = -1; + GST_BUFFER_OFFSET_END (buf) = packet->granulepos; + ret = gst_pad_push (GST_PAD (pad), buf); + } else { + GST_DEBUG_OBJECT (ogg, + "%p could not get buffer from peer %08lx", pad, pad->serialno); + if (ret == GST_FLOW_NOT_LINKED) + ret = GST_FLOW_OK; /* submit a packet to the oggpad, this function will run the * typefind code for the pad if this is the first packet for this * stream @@ -602,15 +718,12 @@ static GstFlowReturn gst_ogg_pad_submit_packet (GstOggPad * pad, ogg_packet * packet) - GstBuffer *buf; gint64 granule; - GstFlowReturn ret = GST_FLOW_OK; GstOggDemux *ogg = pad->ogg; - GST_DEBUG_OBJECT (ogg, - "%p submit packet serial %08lx, packetno %lld", pad, pad->serialno, - pad->packetno); + GST_DEBUG_OBJECT (ogg, "%p submit packet serial %08lx", pad, pad->serialno); granule = packet->granulepos; if (granule != -1) { @@ -619,84 +732,48 @@ pad->first_granule = granule; - /* first packet, FIXME, do this in chain activation */ - if (pad->packetno == 0) { + /* first packet */ + if (!pad->have_type) { gst_ogg_pad_typefind (pad, packet); + pad->have_type = TRUE; - /* stream packet to peer plugin */ - if (pad->mode == GST_OGG_PAD_MODE_STREAMING) { - ret = - gst_pad_alloc_buffer (GST_PAD (pad), GST_BUFFER_OFFSET_NONE, - packet->bytes, GST_PAD_CAPS (pad), &buf); - GST_DEBUG_OBJECT (ogg, - "%p streaming to peer serial %08lx, packetno %lld", pad, pad->serialno, - pad->packetno); - if (ret == GST_FLOW_OK) { - memcpy (buf->data, packet->packet, packet->bytes); + /* no start time known, stream to internal plugin to + * get time */ + if (pad->start_time == GST_CLOCK_TIME_NONE) { + ret = gst_ogg_demux_chain_elem_pad (pad, packet); + /* we know the start_time of the pad data, see if we + * can activate the complete chain if this is a dynamic + * chain. */ + if (pad->start_time != GST_CLOCK_TIME_NONE) { + /* check if complete chain has start time */ + if (pad->chain == ogg->building_chain) { + if (gst_ogg_demux_collect_chain_info (ogg, pad->chain)) { + GstEvent *event; - pad->offset = packet->granulepos; - GST_BUFFER_OFFSET (buf) = -1; - GST_BUFFER_OFFSET_END (buf) = packet->granulepos; + /* create the discont event we are going to send out */ + event = gst_event_new_discontinuous (1.0, + GST_FORMAT_TIME, (gint64) pad->chain->start_time, + (gint64) pad->chain->last_time, NULL); - ret = gst_pad_push (GST_PAD (pad), buf); - GST_DEBUG_OBJECT (ogg, - "%p could not get buffer from peer %08lx, packetno %lld", pad, - pad->serialno, pad->packetno); + gst_ogg_demux_activate_chain (ogg, pad->chain, event); - /* if we are still building a chain, we have to queue this buffer and - * push it when we activate the chain */ - if (ogg->building_chain) { - buf = gst_buffer_new_and_alloc (packet->bytes); - memcpy (buf->data, packet->packet, packet->bytes); - pad->offset = packet->granulepos; - GST_BUFFER_OFFSET (buf) = -1; - GST_BUFFER_OFFSET_END (buf) = packet->granulepos; - pad->headers = g_list_append (pad->headers, buf); - /* we are ok now */ - ret = GST_FLOW_OK; + ogg->building_chain = NULL; - /* we just ignore unlinked pads */ - if (ret == GST_FLOW_NOT_LINKED) - ret = GST_FLOW_OK; - } else { - /* initialize our internal decoder with packets */ - if (!pad->elem_pad) - goto no_decoder; - "%p init decoder serial %08lx, packetno %lld", pad, pad->serialno, - buf = gst_buffer_new_and_alloc (packet->bytes); - memcpy (GST_BUFFER_DATA (buf), packet->packet, packet->bytes); - gst_buffer_set_caps (buf, GST_PAD_CAPS (pad)); - GST_BUFFER_OFFSET (buf) = -1; - GST_BUFFER_OFFSET_END (buf) = packet->granulepos; - ret = gst_pad_chain (pad->elem_pad, buf); - if (GST_FLOW_IS_FATAL (ret)) - goto decoder_error; - pad->packetno++; - return ret; -no_decoder: - { - GST_WARNING_OBJECT (ogg, - "pad %08lx does not have elem_pad, no decoder ?", pad); - return GST_FLOW_ERROR; + /* if we are building a chain, store buffer for when we activate + * it. This path is taken if we operate in streaming mode. */ + if (ogg->building_chain) { + ret = gst_ogg_demux_queue_data (pad, packet); -decoder_error: - GST_WARNING_OBJECT (ogg, "internal decoder error"); + /* else we are completely streaming to the peer */ + else { + ret = gst_ogg_demux_chain_peer (pad, packet); /* submit a page to an oggpad, this function will then submit all @@ -771,6 +848,8 @@ chain->bytes = -1; chain->have_bos = FALSE; chain->streams = g_array_new (FALSE, TRUE, sizeof (GstOggPad *)); + chain->start_time = GST_CLOCK_TIME_NONE; + chain->total_time = GST_CLOCK_TIME_NONE; return chain; @@ -951,6 +1030,12 @@ ogg->chain_lock = g_mutex_new (); ogg->chains = g_array_new (FALSE, TRUE, sizeof (GstOggChain *)); ogg->state = OGG_STATE_NEW_CHAIN; + ogg->segment_start = GST_CLOCK_TIME_NONE; + ogg->segment_stop = GST_CLOCK_TIME_NONE; + ogg->segment_play = FALSE; + ogg->running = FALSE; static void @@ -1153,13 +1238,15 @@ if (chain == NULL) return TRUE; + /* send EOS on all the pads */ for (i = 0; i < chain->streams->len; i++) { GstOggPad *pad = g_array_index (chain->streams, GstOggPad *, i); gst_pad_push_event (GST_PAD (pad), gst_event_new (GST_EVENT_EOS)); gst_element_remove_pad (GST_ELEMENT (ogg), GST_PAD (pad)); - /* if we cannot seek, we can destroy the chain completely */ + /* if we cannot seek back to the chain, we can destroy the chain + * completely */ if (!ogg->seekable) { gst_ogg_chain_free (chain); @@ -1169,20 +1256,25 @@ static gboolean -gst_ogg_demux_activate_chain (GstOggDemux * ogg, GstOggChain * chain) +gst_ogg_demux_activate_chain (GstOggDemux * ogg, GstOggChain * chain, + GstEvent * event) gint i; - GList *headers; - GstOggPad *pad; - GstEvent *event; - if (chain == ogg->current_chain) + if (chain == ogg->current_chain) { + if (event) + gst_event_unref (event); gst_ogg_demux_deactivate_current_chain (ogg); + GST_DEBUG ("activating chain"); /* first add the pads */ + GstOggPad *pad; pad = g_array_index (chain->streams, GstOggPad *, i); gst_element_add_pad (GST_ELEMENT (ogg), GST_PAD (pad)); @@ -1190,15 +1282,19 @@ gst_element_no_more_pads (GST_ELEMENT (ogg)); ogg->current_chain = chain; - /* send the base time */ - event = gst_event_new_discontinuous (1.0, - GST_FORMAT_TIME, (gint64) chain->start_time, (gint64) chain->total_time, - NULL); + if (event) + gst_ogg_demux_send_event (ogg, event); - gst_ogg_demux_send_event (ogg, event); + GST_DEBUG ("starting chain"); - /* then send out the buffers */ + /* we are streaming now */ + ogg->state = OGG_STATE_STREAMING; + /* then send out any queued buffers */ + GList *headers; for (headers = pad->headers; headers; headers = g_list_next (headers)) { @@ -1215,7 +1311,7 @@ -gst_ogg_demux_perform_seek (GstOggDemux * ogg, gint64 pos) +gst_ogg_demux_perform_seek (GstOggDemux * ogg, gboolean flush) GstOggChain *chain = NULL; gint64 begin, end; @@ -1226,18 +1322,22 @@ gint64 result = 0; - total = ogg->total_time; + /* nothing configured, play complete file */ + if (ogg->segment_start == GST_CLOCK_TIME_NONE) + ogg->segment_start = ogg->start_time; + if (ogg->segment_stop == GST_CLOCK_TIME_NONE) + ogg->segment_stop = ogg->total_time; - /* can't seek past start or end */ - if (pos < 0 || pos > total) { - return FALSE; - } + ogg->segment_start = + CLAMP (ogg->segment_start, ogg->start_time, ogg->total_time); + ogg->segment_stop = + CLAMP (ogg->segment_stop, ogg->start_time, ogg->total_time); /* first step is to unlock the streaming thread if it is * blocked in a chain call, we do this by starting the flush. because * we cannot yet hold any streaming lock, we have to protect the chains * with their own lock. */ + if (flush) { gint i; gst_pad_push_event (ogg->sinkpad, gst_event_new_flush (FALSE)); @@ -1247,7 +1347,6 @@ GstOggChain *chain = g_array_index (ogg->chains, GstOggChain *, i); gint j; for (j = 0; j < chain->streams->len; j++) { GstOggPad *pad = g_array_index (chain->streams, GstOggPad *, j); @@ -1255,16 +1354,19 @@ GST_CHAIN_UNLOCK (ogg); + gst_pad_pause_task (ogg->sinkpad); - /* now grab the stream lock so that streaming cannot continue */ + /* now grab the stream lock so that streaming cannot continue, for + * non flushing seeks when the element is in PAUSED this could block + * forever. */ GST_STREAM_LOCK (ogg->sinkpad); - /* we need to stop flushing on the srcpad as w're going to use it + /* we need to stop flushing on the srcpad as we're going to use it * next. We can do this as we have the STREAM lock now. */ gst_pad_push_event (ogg->sinkpad, gst_event_new_flush (TRUE)); { @@ -1283,10 +1385,11 @@ /* first find the chain to search in */ + total = ogg->total_time; for (i = ogg->chains->len - 1; i >= 0; i--) { chain = g_array_index (ogg->chains, GstOggChain *, i); total -= chain->total_time; - if (pos >= total) + if (ogg->segment_start >= total) @@ -1294,11 +1397,13 @@ end = chain->end_offset; begintime = chain->begin_time; endtime = chain->begin_time + chain->total_time; - target = pos - total + begintime; + target = ogg->segment_start - total + begintime; best = begin; - GST_DEBUG_OBJECT (ogg, "seeking to %" GST_TIME_FORMAT " in chain %p", - GST_TIME_ARGS (pos), chain); + "seeking to %" GST_TIME_FORMAT "-%" GST_TIME_FORMAT " in chain %p", + GST_TIME_ARGS (ogg->segment_start), GST_TIME_ARGS (ogg->segment_stop), + chain); GST_DEBUG_OBJECT (ogg, "chain offset %" G_GINT64_FORMAT ", end offset %" G_GINT64_FORMAT, begin, end); @@ -1407,6 +1512,10 @@ ogg->offset = best; + /* switch to different chain */ + if (chain != ogg->current_chain) { + gst_ogg_demux_activate_chain (ogg, chain, NULL); /* now we have a new position, prepare for streaming again */ @@ -1414,7 +1523,8 @@ /* create the discont event we are going to send out */ event = gst_event_new_discontinuous (1.0, - GST_FORMAT_TIME, (gint64) pos, (gint64) ogg->total_time, NULL); + GST_FORMAT_TIME, (gint64) ogg->segment_start, + (gint64) ogg->segment_stop, NULL); for (i = 0; i < ogg->chains->len; i++) { @@ -1423,7 +1533,8 @@ - gst_pad_push_event (GST_PAD (pad), gst_event_new_flush (TRUE)); + if (flush) + gst_pad_push_event (GST_PAD (pad), gst_event_new_flush (TRUE)); /* and the discont */ gst_event_ref (event); @@ -1431,17 +1542,18 @@ gst_event_unref (event); + /* notify start of new segment */ + if (ogg->segment_play) { + gst_element_post_message (GST_ELEMENT (ogg), + gst_message_new_segment_start (GST_OBJECT (ogg), ogg->segment_start)); + } /* restart our task since it might have been stopped when we did the * flush. */ gst_pad_start_task (ogg->sinkpad, (GstTaskFunction) gst_ogg_demux_loop, ogg->sinkpad); - /* switch to different chain */ - if (chain != ogg->current_chain) { - gst_ogg_demux_activate_chain (ogg, chain); /* streaming can continue now */ GST_STREAM_UNLOCK (ogg->sinkpad); @@ -1593,7 +1705,7 @@ gst_ogg_pad_submit_page (pad, &op); /* the timestamp will be filled in when we submit the pages */ - done &= (pad->start_time != -1); + done &= (pad->start_time != GST_CLOCK_TIME_NONE); GST_LOG_OBJECT (ogg, "done %08lx now %d", serial, done); @@ -1617,7 +1729,6 @@ pad->mode = GST_OGG_PAD_MODE_STREAMING; - pad->packetno = 0; @@ -1692,7 +1803,14 @@ GstOggPad *pad; - /* first look in current chain if any */ + /* first look in building chain if any */ + pad = gst_ogg_chain_get_stream (ogg->building_chain, serialno); + if (pad) + return pad; + /* then look in current chain if any */ if (ogg->current_chain) { pad = gst_ogg_chain_get_stream (ogg->current_chain, serialno); if (pad) @@ -1723,6 +1841,67 @@ return NULL; +static gboolean +gst_ogg_demux_collect_chain_info (GstOggDemux * ogg, GstOggChain * chain) + gint i; + chain->total_time = 0; + chain->start_time = G_MAXINT64; + chain->last_time = 0; + for (i = 0; i < chain->streams->len; i++) { + GstOggPad *pad = g_array_index (chain->streams, GstOggPad *, i); + /* can do this if the pad start time is not defined */ + if (pad->start_time == GST_CLOCK_TIME_NONE) + goto no_start_time; + if (pad->last_time != GST_CLOCK_TIME_NONE) { + pad->total_time = pad->last_time - pad->start_time; + chain->total_time = MAX (chain->total_time, pad->total_time); + chain->last_time = MAX (chain->last_time, pad->last_time); + } else { + pad->total_time = GST_CLOCK_TIME_NONE; + chain->total_time = GST_CLOCK_TIME_NONE; + chain->last_time = GST_CLOCK_TIME_NONE; + chain->start_time = MIN (chain->start_time, pad->start_time); + return TRUE; + /* ERROR */ +no_start_time: + chain->total_time = GST_CLOCK_TIME_NONE; + chain->start_time = GST_CLOCK_TIME_NONE; + chain->last_time = GST_CLOCK_TIME_NONE; + chain->begin_time = GST_CLOCK_TIME_NONE; + return FALSE; +static void +gst_ogg_demux_collect_info (GstOggDemux * ogg) + /* collect all info */ + ogg->start_time = G_MAXINT64; + ogg->total_time = 0; + for (i = 0; i < ogg->chains->len; i++) { + GstOggChain *chain = g_array_index (ogg->chains, GstOggChain *, i); + chain->begin_time = ogg->total_time; + gst_ogg_demux_collect_chain_info (ogg, chain); + ogg->start_time = MIN (ogg->start_time, chain->start_time); + ogg->total_time += chain->total_time; /* find all the chains in the ogg file, this reads the first and * last page of the ogg stream, if they match then the ogg file has * just one chain, else we do a binary search for all chains. @@ -1774,44 +1953,11 @@ gst_ogg_demux_bisect_forward_serialno (ogg, 0, ogg->length, ogg->length, chain, 0); - /* collect all info */ - gint i, j; - ogg->total_time = 0; - for (i = 0; i < ogg->chains->len; i++) { - GstOggChain *chain = g_array_index (ogg->chains, GstOggChain *, i); - chain->total_time = 0; - chain->start_time = G_MAXINT64; - chain->last_time = 0; - chain->begin_time = ogg->total_time; - for (j = 0; j < chain->streams->len; j++) { - GstOggPad *pad = g_array_index (chain->streams, GstOggPad *, j); - pad->total_time = pad->last_time - pad->start_time; - chain->total_time = MAX (chain->total_time, pad->total_time); - chain->start_time = MIN (chain->start_time, pad->start_time); - chain->last_time = MAX (chain->last_time, pad->last_time); - } - ogg->total_time += chain->total_time; - } + gst_ogg_demux_collect_info (ogg); /* dump our chains and streams */ gst_ogg_print (ogg); - /* activate first chain */ - if (ogg->chains->len > 0) { - GstOggChain *chain = g_array_index (ogg->chains, GstOggChain *, 0); - /* and we are streaming now */ - ogg->state = OGG_STATE_STREAMING; /*** error cases ***/ @@ -1875,7 +2021,7 @@ chain = gst_ogg_demux_find_chain (ogg, serialno); if (chain) { /* we do, activate it as it means we have a non-header */ - gst_ogg_demux_activate_chain (ogg, chain); + gst_ogg_demux_activate_chain (ogg, chain, NULL); pad = gst_ogg_demux_find_pad (ogg, serialno); } else { /* chain is unknown */ @@ -1892,13 +2038,6 @@ pad = gst_ogg_chain_new_stream (ogg->building_chain, serialno); } else { - /* no more bos pages, see if we need to activate the chain we were - * building */ - if (ogg->building_chain) { - gst_ogg_demux_activate_chain (ogg, ogg->building_chain); - ogg->building_chain = NULL; - ogg->state = OGG_STATE_STREAMING; - } pad = gst_ogg_demux_find_pad (ogg, serialno); if (pad) { @@ -1959,13 +2098,28 @@ goto chain_read_failed; ogg->need_chains = FALSE; - ogg->offset = 0; + GST_LOCK (ogg); + ogg->running = TRUE; + GST_UNLOCK (ogg); + /* and seek to configured positions without FLUSH */ + gst_ogg_demux_perform_seek (ogg, FALSE); GST_LOG_OBJECT (ogg, "pull data %lld", ogg->offset); if (ogg->offset == ogg->length) { ret = GST_FLOW_OK; - gst_ogg_demux_send_event (ogg, gst_event_new (GST_EVENT_EOS)); + /* segment playback just posts a segment end message instead of + * pushing out EOS. */ + /* FIXME, need to be done somewhere else where we + * can check against segment_stop time. */ + gst_message_new_segment_done (GST_OBJECT (ogg), ogg->total_time)); + gst_ogg_demux_send_event (ogg, gst_event_new (GST_EVENT_EOS)); goto pause; @@ -2020,6 +2174,12 @@ GST_CHAIN_UNLOCK (ogg); +/* this function is called when the pad is activated and should start + * processing data. + * + * We check if we can do random access to decide if we work push or + * pull based. + */ gst_ogg_demux_sink_activate (GstPad * sinkpad) @@ -2030,6 +2190,8 @@ +/* this function gets called when we activate ourselves in push mode. + * We cannot seek (ourselves) in the stream */ gst_ogg_demux_sink_activate_push (GstPad * sinkpad, gboolean active) @@ -2042,6 +2204,9 @@ +/* this function gets called when we activate ourselves in pull mode. + * We can perform random access to the resource and we start a task + * to start reading */ gst_ogg_demux_sink_activate_pull (GstPad * sinkpad, gboolean active) @@ -2086,6 +2251,9 @@ case GST_STATE_PAUSED_TO_READY: gst_ogg_demux_clear_chains (ogg); + ogg->running = FALSE; case GST_STATE_READY_TO_NULL: ogg_sync_clear (&ogg->sync); @@ -2192,7 +2360,9 @@ guint j, i; - GST_INFO_OBJECT (ogg, "%u chains, total time: %" GST_TIME_FORMAT, + GST_INFO_OBJECT (ogg, "%u chains, start time: %" GST_TIME_FORMAT, + ogg->chains->len, GST_TIME_ARGS (ogg->start_time)); + GST_INFO_OBJECT (ogg, " total time: %" GST_TIME_FORMAT, ogg->chains->len, GST_TIME_ARGS (ogg->total_time)); for (i = 0; i < ogg->chains->len; i++) { @@ -2201,8 +2371,12 @@ GST_INFO_OBJECT (ogg, " chain %d (%u streams):", i, chain->streams->len); GST_INFO_OBJECT (ogg, " offset: %" G_GINT64_FORMAT " - %" G_GINT64_FORMAT, chain->offset, chain->end_offset); + GST_INFO_OBJECT (ogg, " start time: %" GST_TIME_FORMAT, + GST_TIME_ARGS (chain->start_time)); GST_INFO_OBJECT (ogg, " total time: %" GST_TIME_FORMAT, GST_TIME_ARGS (chain->total_time)); + GST_INFO_OBJECT (ogg, " begin time: %" GST_TIME_FORMAT, + GST_TIME_ARGS (chain->begin_time)); for (j = 0; j < chain->streams->len; j++) { GstOggPad *stream = g_array_index (chain->streams, GstOggPad *, j); |