Use g_memdup2() where available and add fallback for older GLib versions
[platform/upstream/gstreamer.git] / ext / ogg / gstoggdemux.c
1 /* GStreamer
2  * Copyright (C) 2004 Wim Taymans <wim@fluendo.com>
3  *
4  * gstoggdemux.c: ogg stream demuxer
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public
17  * License along with this library; if not, write to the
18  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
19  * Boston, MA 02110-1301, USA.
20  */
21
22 /**
23  * SECTION:element-oggdemux
24  * @title: oggdemux
25  * @see_also: <link linkend="gst-plugins-base-plugins-oggmux">oggmux</link>
26  *
27  * This element demuxes ogg files into their encoded audio and video components.
28  *
29  * ## Example pipelines
30  * |[
31  * gst-launch-1.0 -v filesrc location=test.ogg ! oggdemux ! vorbisdec ! audioconvert ! audioresample ! autoaudiosink
32  * ]|
33  *  Decodes a vorbis audio stream stored inside an ogg container and plays it.
34  *
35  */
36
37
38 #ifdef HAVE_CONFIG_H
39 #include "config.h"
40 #endif
41
42 #include <string.h>
43 #include <gst/gst-i18n-plugin.h>
44 #include <gst/tag/tag.h>
45 #include <gst/audio/audio.h>
46
47 #include "gstoggelements.h"
48 #include "gstoggdemux.h"
49
50 #define CHUNKSIZE (8500)        /* this is out of vorbisfile */
51
52 /* we hope we get a granpos within this many bytes off the end */
53 #define DURATION_CHUNK_OFFSET (128*1024)
54
55 /* An Ogg page can not be larger than 255 segments of 255 bytes, plus
56    26 bytes of header */
57 #define MAX_OGG_PAGE_SIZE (255 * 255 + 26)
58
59 #define GST_FLOW_LIMIT GST_FLOW_CUSTOM_ERROR
60 #define GST_FLOW_SKIP_PUSH GST_FLOW_CUSTOM_SUCCESS_1
61
62 #define SEEK_GIVE_UP_THRESHOLD (3*GST_SECOND)
63
64 #define GST_CHAIN_LOCK(ogg)     g_mutex_lock(&(ogg)->chain_lock)
65 #define GST_CHAIN_UNLOCK(ogg)   g_mutex_unlock(&(ogg)->chain_lock)
66
67 #define GST_PUSH_LOCK(ogg)                  \
68   do {                                      \
69     GST_TRACE_OBJECT(ogg, "Push lock");     \
70     g_mutex_lock(&(ogg)->push_lock);        \
71   } while(0)
72
73 #define GST_PUSH_UNLOCK(ogg)                \
74   do {                                      \
75     GST_TRACE_OBJECT(ogg, "Push unlock");   \
76     g_mutex_unlock(&(ogg)->push_lock);      \
77   } while(0)
78
79 GST_DEBUG_CATEGORY (gst_ogg_demux_debug);
80 GST_DEBUG_CATEGORY (gst_ogg_demux_setup_debug);
81 #define GST_CAT_DEFAULT gst_ogg_demux_debug
82
83
84 static ogg_packet *
85 _ogg_packet_copy (const ogg_packet * packet)
86 {
87   ogg_packet *ret = g_slice_new (ogg_packet);
88
89   *ret = *packet;
90   ret->packet = g_memdup2 (packet->packet, packet->bytes);
91
92   return ret;
93 }
94
95 static void
96 _ogg_packet_free (ogg_packet * packet)
97 {
98   g_free (packet->packet);
99   g_slice_free (ogg_packet, packet);
100 }
101
102 static ogg_page *
103 gst_ogg_page_copy (ogg_page * page)
104 {
105   ogg_page *p = g_slice_new (ogg_page);
106
107   /* make a copy of the page */
108   p->header = g_memdup2 (page->header, page->header_len);
109   p->header_len = page->header_len;
110   p->body = g_memdup2 (page->body, page->body_len);
111   p->body_len = page->body_len;
112
113   return p;
114 }
115
116 static void
117 gst_ogg_page_free (ogg_page * page)
118 {
119   g_free (page->header);
120   g_free (page->body);
121   g_slice_free (ogg_page, page);
122 }
123
124 static gboolean gst_ogg_demux_collect_chain_info (GstOggDemux * ogg,
125     GstOggChain * chain);
126 static gboolean gst_ogg_demux_activate_chain (GstOggDemux * ogg,
127     GstOggChain * chain, GstEvent * event);
128 static void gst_ogg_pad_mark_discont (GstOggPad * pad);
129 static void gst_ogg_chain_mark_discont (GstOggChain * chain);
130
131 static gboolean gst_ogg_demux_perform_seek (GstOggDemux * ogg,
132     GstEvent * event);
133 static gboolean gst_ogg_demux_receive_event (GstElement * element,
134     GstEvent * event);
135
136 static void gst_ogg_pad_dispose (GObject * object);
137 static void gst_ogg_pad_finalize (GObject * object);
138
139 static gboolean gst_ogg_pad_src_query (GstPad * pad, GstObject * parent,
140     GstQuery * query);
141 static gboolean gst_ogg_pad_event (GstPad * pad, GstObject * parent,
142     GstEvent * event);
143 static GstOggPad *gst_ogg_chain_get_stream (GstOggChain * chain,
144     guint32 serialno);
145
146 static GstFlowReturn gst_ogg_demux_combine_flows (GstOggDemux * ogg,
147     GstOggPad * pad, GstFlowReturn ret);
148 static void gst_ogg_demux_sync_streams (GstOggDemux * ogg);
149
150 static GstCaps *gst_ogg_demux_set_header_on_caps (GstOggDemux * ogg,
151     GstCaps * caps, GList * headers);
152 static gboolean gst_ogg_demux_send_event (GstOggDemux * ogg, GstEvent * event);
153 static gboolean gst_ogg_demux_perform_seek_push (GstOggDemux * ogg,
154     GstEvent * event);
155 static gboolean gst_ogg_demux_check_duration_push (GstOggDemux * ogg,
156     GstSeekFlags flags, GstEvent * event);
157
158 GType gst_ogg_pad_get_type (void);
159 G_DEFINE_TYPE (GstOggPad, gst_ogg_pad, GST_TYPE_PAD);
160
161 static void
162 gst_ogg_pad_class_init (GstOggPadClass * klass)
163 {
164   GObjectClass *gobject_class;
165
166   gobject_class = (GObjectClass *) klass;
167
168   gobject_class->dispose = gst_ogg_pad_dispose;
169   gobject_class->finalize = gst_ogg_pad_finalize;
170 }
171
172 static void
173 gst_ogg_pad_init (GstOggPad * pad)
174 {
175   gst_pad_set_event_function (GST_PAD (pad),
176       GST_DEBUG_FUNCPTR (gst_ogg_pad_event));
177   gst_pad_set_query_function (GST_PAD (pad),
178       GST_DEBUG_FUNCPTR (gst_ogg_pad_src_query));
179   gst_pad_use_fixed_caps (GST_PAD (pad));
180
181   pad->current_granule = -1;
182   pad->prev_granule = -1;
183   pad->keyframe_granule = -1;
184
185   pad->start_time = GST_CLOCK_TIME_NONE;
186
187   pad->position = GST_CLOCK_TIME_NONE;
188
189   pad->have_type = FALSE;
190   pad->continued = NULL;
191   pad->map.headers = NULL;
192   pad->map.queued = NULL;
193
194   pad->map.granulerate_n = 0;
195   pad->map.granulerate_d = 0;
196   pad->map.granuleshift = -1;
197 }
198
199 static void
200 gst_ogg_pad_dispose (GObject * object)
201 {
202   GstOggPad *pad = GST_OGG_PAD (object);
203
204   pad->chain = NULL;
205   pad->ogg = NULL;
206
207   g_list_foreach (pad->map.headers, (GFunc) _ogg_packet_free, NULL);
208   g_list_free (pad->map.headers);
209   pad->map.headers = NULL;
210   g_list_foreach (pad->map.queued, (GFunc) _ogg_packet_free, NULL);
211   g_list_free (pad->map.queued);
212   pad->map.queued = NULL;
213
214   g_free (pad->map.index);
215   pad->map.index = NULL;
216
217   /* clear continued pages */
218   g_list_foreach (pad->continued, (GFunc) gst_ogg_page_free, NULL);
219   g_list_free (pad->continued);
220   pad->continued = NULL;
221
222   if (pad->map.caps) {
223     gst_caps_unref (pad->map.caps);
224     pad->map.caps = NULL;
225   }
226
227   if (pad->map.taglist) {
228     gst_tag_list_unref (pad->map.taglist);
229     pad->map.taglist = NULL;
230   }
231
232   ogg_stream_reset (&pad->map.stream);
233
234   G_OBJECT_CLASS (gst_ogg_pad_parent_class)->dispose (object);
235 }
236
237 static void
238 gst_ogg_pad_finalize (GObject * object)
239 {
240   GstOggPad *pad = GST_OGG_PAD (object);
241
242   ogg_stream_clear (&pad->map.stream);
243
244   G_OBJECT_CLASS (gst_ogg_pad_parent_class)->finalize (object);
245 }
246
247 static gboolean
248 gst_ogg_pad_src_query (GstPad * pad, GstObject * parent, GstQuery * query)
249 {
250   gboolean res = TRUE;
251   GstOggDemux *ogg;
252
253   ogg = GST_OGG_DEMUX (parent);
254
255   switch (GST_QUERY_TYPE (query)) {
256     case GST_QUERY_POSITION:
257     {
258       GstFormat format;
259       GstOggPad *ogg_pad = GST_OGG_PAD (pad);
260
261       gst_query_parse_position (query, &format, NULL);
262       /* can only get position in time */
263       if (format != GST_FORMAT_TIME)
264         goto wrong_format;
265
266       gst_query_set_position (query, format, ogg_pad->position);
267       break;
268     }
269     case GST_QUERY_DURATION:
270     {
271       GstFormat format;
272       gint64 total_time = -1;
273
274       gst_query_parse_duration (query, &format, NULL);
275       /* can only get duration in time */
276       if (format != GST_FORMAT_TIME)
277         goto wrong_format;
278
279       if (ogg->total_time != -1) {
280         /* we can return the total length */
281         total_time = ogg->total_time;
282       } else {
283         gint bitrate = ogg->bitrate;
284
285         /* try with length and bitrate */
286         if (bitrate > 0) {
287           GstQuery *uquery;
288
289           /* ask upstream for total length in bytes */
290           uquery = gst_query_new_duration (GST_FORMAT_BYTES);
291           if (gst_pad_peer_query (ogg->sinkpad, uquery)) {
292             gint64 length;
293
294             gst_query_parse_duration (uquery, NULL, &length);
295
296             /* estimate using the bitrate */
297             total_time =
298                 gst_util_uint64_scale (length, 8 * GST_SECOND, bitrate);
299
300             GST_LOG_OBJECT (ogg,
301                 "length: %" G_GINT64_FORMAT ", bitrate %d, total_time %"
302                 GST_TIME_FORMAT, length, bitrate, GST_TIME_ARGS (total_time));
303           }
304           gst_query_unref (uquery);
305         }
306       }
307
308       gst_query_set_duration (query, GST_FORMAT_TIME, total_time);
309       break;
310     }
311     case GST_QUERY_SEEKING:
312     {
313       GstFormat format;
314
315       gst_query_parse_seeking (query, &format, NULL, NULL, NULL);
316       if (format == GST_FORMAT_TIME) {
317         gboolean seekable = FALSE;
318         gint64 stop = -1;
319
320         GST_CHAIN_LOCK (ogg);
321         if (ogg->pullmode) {
322           seekable = TRUE;
323           stop = ogg->total_time;
324         } else if (ogg->push_disable_seeking) {
325           seekable = FALSE;
326         } else if (ogg->current_chain == NULL) {
327           GstQuery *squery;
328
329           /* assume we can seek if upstream is seekable in BYTES format */
330           GST_LOG_OBJECT (ogg, "no current chain, check upstream seekability");
331           squery = gst_query_new_seeking (GST_FORMAT_BYTES);
332           if (gst_pad_peer_query (ogg->sinkpad, squery))
333             gst_query_parse_seeking (squery, NULL, &seekable, NULL, NULL);
334           else
335             seekable = FALSE;
336           gst_query_unref (squery);
337         } else if (ogg->current_chain->streams->len) {
338           gint i;
339
340           seekable = FALSE;
341           for (i = 0; i < ogg->current_chain->streams->len; i++) {
342             GstOggPad *pad =
343                 g_array_index (ogg->current_chain->streams, GstOggPad *, i);
344
345             seekable = TRUE;
346             if (pad->map.index != NULL && pad->map.n_index != 0) {
347               GstOggIndex *idx;
348               GstClockTime idx_time;
349
350               idx = &pad->map.index[pad->map.n_index - 1];
351               idx_time =
352                   gst_util_uint64_scale (idx->timestamp, GST_SECOND,
353                   pad->map.kp_denom);
354               if (stop == -1)
355                 stop = idx_time;
356               else
357                 stop = MAX (idx_time, stop);
358             } else {
359               stop = ogg->push_time_length;
360               if (stop == -1)
361                 stop = ogg->total_time;
362             }
363           }
364         }
365
366         gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0, stop);
367         GST_CHAIN_UNLOCK (ogg);
368       } else {
369         res = FALSE;
370       }
371       break;
372     }
373     case GST_QUERY_SEGMENT:{
374       GstFormat format;
375       gint64 start, stop;
376
377       format = ogg->segment.format;
378
379       start =
380           gst_segment_to_stream_time (&ogg->segment, format,
381           ogg->segment.start);
382       if ((stop = ogg->segment.stop) == -1)
383         stop = ogg->segment.duration;
384       else
385         stop = gst_segment_to_stream_time (&ogg->segment, format, stop);
386
387       gst_query_set_segment (query, ogg->segment.rate, format, start, stop);
388       res = TRUE;
389       break;
390     }
391     default:
392       res = gst_pad_query_default (pad, parent, query);
393       break;
394   }
395 done:
396
397   return res;
398
399   /* ERRORS */
400 wrong_format:
401   {
402     GST_DEBUG_OBJECT (ogg, "only query position/duration on TIME is supported");
403     res = FALSE;
404     goto done;
405   }
406 }
407
408 static gboolean
409 gst_ogg_demux_receive_event (GstElement * element, GstEvent * event)
410 {
411   gboolean res;
412   GstOggDemux *ogg;
413
414   ogg = GST_OGG_DEMUX (element);
415
416   switch (GST_EVENT_TYPE (event)) {
417     case GST_EVENT_SEEK:
418       /* now do the seek */
419       res = gst_ogg_demux_perform_seek (ogg, event);
420       gst_event_unref (event);
421       break;
422     default:
423       GST_DEBUG_OBJECT (ogg, "We only handle seek events here");
424       goto error;
425   }
426
427   return res;
428
429   /* ERRORS */
430 error:
431   {
432     GST_DEBUG_OBJECT (ogg, "error handling event");
433     gst_event_unref (event);
434     return FALSE;
435   }
436 }
437
438 static gboolean
439 gst_ogg_pad_event (GstPad * pad, GstObject * parent, GstEvent * event)
440 {
441   gboolean res;
442   GstOggDemux *ogg;
443
444   ogg = GST_OGG_DEMUX (parent);
445
446   switch (GST_EVENT_TYPE (event)) {
447     case GST_EVENT_SEEK:
448       /* now do the seek */
449       res = gst_ogg_demux_perform_seek (ogg, event);
450       gst_event_unref (event);
451       break;
452     case GST_EVENT_RECONFIGURE:
453       GST_OGG_PAD (pad)->last_ret = GST_FLOW_OK;
454       res = gst_pad_event_default (pad, parent, event);
455       break;
456     default:
457       res = gst_pad_event_default (pad, parent, event);
458       break;
459   }
460
461   return res;
462 }
463
464 static void
465 gst_ogg_pad_reset (GstOggPad * pad)
466 {
467   ogg_stream_reset (&pad->map.stream);
468
469   GST_DEBUG_OBJECT (pad, "doing reset");
470
471   /* clear continued pages */
472   g_list_foreach (pad->continued, (GFunc) gst_ogg_page_free, NULL);
473   g_list_free (pad->continued);
474   pad->continued = NULL;
475
476   pad->last_ret = GST_FLOW_OK;
477   pad->position = GST_CLOCK_TIME_NONE;
478   pad->current_granule = -1;
479   pad->prev_granule = -1;
480   pad->keyframe_granule = -1;
481   pad->is_eos = FALSE;
482 }
483
484 /* queue data, basically takes the packet, puts it in a buffer and store the
485  * buffer in the queued list.  */
486 static GstFlowReturn
487 gst_ogg_demux_queue_data (GstOggPad * pad, ogg_packet * packet)
488 {
489 #ifndef GST_DISABLE_GST_DEBUG
490   GstOggDemux *ogg = pad->ogg;
491 #endif
492
493   GST_DEBUG_OBJECT (ogg, "%p queueing data serial %08x",
494       pad, pad->map.serialno);
495
496   pad->map.queued = g_list_append (pad->map.queued, _ogg_packet_copy (packet));
497
498   /* we are ok now */
499   return GST_FLOW_OK;
500 }
501
502 static GstFlowReturn
503 gst_ogg_demux_chain_peer (GstOggPad * pad, ogg_packet * packet,
504     gboolean push_headers)
505 {
506   GstBuffer *buf = NULL;
507   GstFlowReturn ret, cret;
508   GstOggDemux *ogg = pad->ogg;
509   gint64 current_time;
510   GstOggChain *chain;
511   gint64 duration;
512   gint offset;
513   gint trim;
514   GstClockTime out_timestamp, out_duration;
515   guint64 out_offset, out_offset_end;
516   gboolean delta_unit = FALSE;
517   gboolean is_header;
518   guint64 clip_start = 0, clip_end = 0;
519
520   ret = cret = GST_FLOW_OK;
521   GST_DEBUG_OBJECT (pad, "Chaining %d %d %" GST_TIME_FORMAT " %d %p",
522       ogg->pullmode, ogg->push_state, GST_TIME_ARGS (ogg->push_time_length),
523       ogg->push_disable_seeking, ogg->building_chain);
524
525   if (G_UNLIKELY (pad->is_eos)) {
526     GST_DEBUG_OBJECT (pad, "Skipping packet on pad that is eos");
527     ret = GST_FLOW_EOS;
528     goto combine;
529   }
530
531   GST_PUSH_LOCK (ogg);
532   if (!ogg->pullmode && ogg->push_state == PUSH_PLAYING
533       && ogg->push_time_length == GST_CLOCK_TIME_NONE
534       && !ogg->push_disable_seeking) {
535     if (!ogg->building_chain) {
536       /* we got all headers, now try to get duration */
537       if (!gst_ogg_demux_check_duration_push (ogg, GST_SEEK_FLAG_FLUSH, NULL)) {
538         GST_PUSH_UNLOCK (ogg);
539         return GST_FLOW_OK;
540       }
541     }
542     GST_PUSH_UNLOCK (ogg);
543     return GST_FLOW_OK;
544   }
545   GST_PUSH_UNLOCK (ogg);
546
547   GST_DEBUG_OBJECT (ogg,
548       "%p streaming to peer serial %08x", pad, pad->map.serialno);
549
550   gst_ogg_stream_update_stats (&pad->map, packet);
551
552   if (pad->map.is_ogm) {
553     const guint8 *data;
554     long bytes;
555
556     data = packet->packet;
557     bytes = packet->bytes;
558
559     if (bytes < 1)
560       goto empty_packet;
561
562     if ((data[0] & 1) || (data[0] & 3 && pad->map.is_ogm_text)) {
563       /* We don't push header packets for OGM */
564       goto done;
565     }
566
567     offset = 1 + (((data[0] & 0xc0) >> 6) | ((data[0] & 0x02) << 1));
568     delta_unit = (((data[0] & 0x08) >> 3) == 0);
569
570     trim = 0;
571
572     /* Strip trailing \0 for subtitles */
573     if (pad->map.is_ogm_text) {
574       while (bytes && data[bytes - 1] == 0) {
575         trim++;
576         bytes--;
577       }
578     }
579   } else if (pad->map.is_vp8) {
580     if ((packet->bytes >= 7 && memcmp (packet->packet, "OVP80\2 ", 7) == 0) ||
581         packet->b_o_s ||
582         (packet->bytes >= 5 && memcmp (packet->packet, "OVP80", 5) == 0)) {
583       /* We don't push header packets for VP8 */
584       goto done;
585     }
586     offset = 0;
587     trim = 0;
588     delta_unit = !gst_ogg_stream_packet_is_key_frame (&pad->map, packet);
589   } else {
590     offset = 0;
591     trim = 0;
592     delta_unit = !gst_ogg_stream_packet_is_key_frame (&pad->map, packet);
593   }
594
595   /* get timing info for the packet */
596   is_header = gst_ogg_stream_packet_is_header (&pad->map, packet);
597   if (is_header) {
598     duration = 0;
599     GST_DEBUG_OBJECT (ogg, "packet is header");
600   } else {
601     duration = gst_ogg_stream_get_packet_duration (&pad->map, packet);
602     GST_DEBUG_OBJECT (ogg, "packet duration %" G_GUINT64_FORMAT, duration);
603   }
604
605
606   /* If we get a hole at start, it might be we're catching a stream
607    * partway through. In that case, if the stream has an index, the
608    * index might be mooted. However, as it's totally valid to index
609    * a stream with a hole at start (ie, capturing a live stream and
610    * then index it), we now check whether the index references some
611    * offset beyond the byte length (if known). If this is the case,
612    * we can be reasonably sure we're getting a stream partway, with
613    * its index being now useless since we don't know how many bytes
614    * were skipped, preventing us from patching the index offsets to
615    * match the hole size. */
616   if (!is_header && ogg->check_index_overflow) {
617     GstQuery *query;
618     GstFormat format;
619     int i;
620     gint64 length;
621     gboolean beyond;
622
623     if (ogg->current_chain) {
624       query = gst_query_new_duration (GST_FORMAT_BYTES);
625       if (gst_pad_peer_query (ogg->sinkpad, query)) {
626         gst_query_parse_duration (query, &format, &length);
627         if (format == GST_FORMAT_BYTES && length >= 0) {
628           for (i = 0; i < ogg->current_chain->streams->len; i++) {
629             GstOggPad *ipad =
630                 g_array_index (ogg->current_chain->streams, GstOggPad *, i);
631             if (!ipad->map.index)
632               continue;
633             beyond = ipad->map.n_index
634                 && ipad->map.index[ipad->map.n_index - 1].offset >= length;
635             if (beyond) {
636               GST_WARNING_OBJECT (pad, "Index offsets beyond byte length");
637               if (ipad->discont) {
638                 /* hole - the index is most likely screwed up */
639                 GST_WARNING_OBJECT (ogg, "Discarding entire index");
640                 g_free (ipad->map.index);
641                 ipad->map.index = NULL;
642                 ipad->map.n_index = 0;
643               } else {
644                 /* no hole - we can just clip the index if needed */
645                 GST_WARNING_OBJECT (ogg, "Clipping index");
646                 while (ipad->map.n_index > 0
647                     && ipad->map.index[ipad->map.n_index - 1].offset >= length)
648                   ipad->map.n_index--;
649                 if (ipad->map.n_index == 0) {
650                   GST_WARNING_OBJECT (ogg, "The entire index was clipped");
651                   g_free (ipad->map.index);
652                   ipad->map.index = NULL;
653                 }
654               }
655               /* We can't trust the total time if the index goes beyond */
656               ipad->map.total_time = -1;
657             } else {
658               /* use total time to update the total ogg time */
659               if (ogg->total_time == -1) {
660                 ogg->total_time = ipad->map.total_time;
661               } else if (ipad->map.total_time > 0) {
662                 ogg->total_time = MAX (ogg->total_time, ipad->map.total_time);
663               }
664             }
665           }
666         }
667       }
668       gst_query_unref (query);
669     }
670     ogg->check_index_overflow = FALSE;
671   }
672
673   if (packet->b_o_s) {
674     out_timestamp = GST_CLOCK_TIME_NONE;
675     out_duration = GST_CLOCK_TIME_NONE;
676     out_offset = 0;
677     out_offset_end = -1;
678   } else {
679     if (packet->granulepos > -1) {
680       gint64 granule = gst_ogg_stream_granulepos_to_granule (&pad->map,
681           packet->granulepos);
682       if (granule < 0) {
683         GST_ERROR_OBJECT (ogg,
684             "granulepos %" G_GINT64_FORMAT " yielded granule %" G_GINT64_FORMAT,
685             (gint64) packet->granulepos, (gint64) granule);
686         return GST_FLOW_ERROR;
687       }
688       pad->current_granule = granule;
689       pad->keyframe_granule =
690           gst_ogg_stream_granulepos_to_key_granule (&pad->map,
691           packet->granulepos);
692       GST_DEBUG_OBJECT (ogg, "new granule %" G_GUINT64_FORMAT,
693           pad->current_granule);
694     } else if (pad->current_granule != -1) {
695       pad->current_granule += duration;
696       if (!delta_unit) {
697         pad->keyframe_granule = pad->current_granule;
698       }
699       GST_DEBUG_OBJECT (ogg, "interpolating granule %" G_GUINT64_FORMAT,
700           pad->current_granule);
701     }
702
703     if (ogg->segment.rate < 0.0 && pad->current_granule == -1) {
704       /* negative rates, allow output of packets with no timestamp, let downstream reconstruct */
705       out_timestamp = -1;
706       out_duration = -1;
707       out_offset = -1;
708       out_offset_end = -1;
709       pad->prev_granule = -1;
710     } else {
711       /* we only push buffers after we have a valid granule. This is done so that
712        * we nicely skip packets without a timestamp after a seek. This is ok
713        * because we base our seek on the packet after the page with the smaller
714        * timestamp. */
715       if (pad->current_granule == -1) {
716         pad->prev_granule = -1;
717         goto no_timestamp;
718       }
719
720       if (pad->map.is_ogm) {
721         out_timestamp = gst_ogg_stream_granule_to_time (&pad->map,
722             pad->current_granule);
723         out_duration = gst_util_uint64_scale (duration,
724             GST_SECOND * pad->map.granulerate_d, pad->map.granulerate_n);
725       } else if (pad->map.is_sparse) {
726         out_timestamp = gst_ogg_stream_granule_to_time (&pad->map,
727             pad->current_granule);
728         if (duration == GST_CLOCK_TIME_NONE) {
729           out_duration = GST_CLOCK_TIME_NONE;
730         } else {
731           out_duration = gst_util_uint64_scale (duration,
732               GST_SECOND * pad->map.granulerate_d, pad->map.granulerate_n);
733         }
734       } else {
735         /* The last packet may be clipped. This will be represented
736            by the last granule being smaller than what it would otherwise
737            have been, had no content been clipped. In that case, we
738            cannot calculate the PTS of the audio from the packet length
739            and granule. */
740         if (packet->e_o_s) {
741           if (pad->prev_granule >= 0)
742             out_timestamp = gst_ogg_stream_granule_to_time (&pad->map,
743                 pad->prev_granule);
744           else
745             out_timestamp = GST_CLOCK_TIME_NONE;
746
747           if (pad->map.audio_clipping
748               && pad->current_granule < pad->prev_granule + duration) {
749             clip_end = pad->prev_granule + duration - pad->current_granule;
750           }
751           if (pad->map.audio_clipping
752               && pad->current_granule - duration < -pad->map.granule_offset) {
753             if (pad->current_granule >= -pad->map.granule_offset) {
754               guint64 already_removed =
755                   pad->current_granule >
756                   duration ? pad->current_granule - duration : 0;
757               clip_start =
758                   already_removed >
759                   -pad->map.granule_offset ? 0 : -pad->map.granule_offset -
760                   already_removed;
761             } else
762               clip_start = pad->current_granule;
763           }
764         } else {
765           out_timestamp = gst_ogg_stream_granule_to_time (&pad->map,
766               pad->current_granule - duration);
767
768           if (pad->map.audio_clipping
769               && pad->current_granule - duration < -pad->map.granule_offset) {
770             if (pad->current_granule >= -pad->map.granule_offset) {
771               guint64 already_removed =
772                   pad->current_granule >
773                   duration ? pad->current_granule - duration : 0;
774               clip_start =
775                   already_removed >
776                   -pad->map.granule_offset ? 0 : -pad->map.granule_offset -
777                   already_removed;
778             } else
779               clip_start = pad->current_granule;
780           }
781         }
782         out_duration =
783             gst_ogg_stream_granule_to_time (&pad->map,
784             pad->current_granule) - out_timestamp;
785       }
786       out_offset_end =
787           gst_ogg_stream_granule_to_granulepos (&pad->map,
788           pad->current_granule, pad->keyframe_granule);
789       out_offset =
790           gst_ogg_stream_granule_to_time (&pad->map, pad->current_granule);
791     }
792     pad->prev_granule = pad->current_granule;
793   }
794
795   if (G_UNLIKELY (offset + trim > packet->bytes))
796     goto invalid_packet;
797   else if (pad->map.is_ogm_text) {
798     /* check for invalid buffer sizes */
799     if (G_UNLIKELY (offset + trim >= packet->bytes))
800       goto empty_packet;
801   }
802
803   if (!pad->added)
804     goto not_added;
805
806   buf = gst_buffer_new_and_alloc (packet->bytes - offset - trim);
807
808   if (pad->map.audio_clipping && (clip_start || clip_end)) {
809     GST_DEBUG_OBJECT (pad,
810         "Clipping %" G_GUINT64_FORMAT " %" G_GUINT64_FORMAT " (%"
811         G_GUINT64_FORMAT " / %" G_GUINT64_FORMAT ")", clip_start, clip_end,
812         clip_start + clip_end, duration);
813     gst_buffer_add_audio_clipping_meta (buf, GST_FORMAT_DEFAULT, clip_start,
814         clip_end);
815   }
816
817   /* set delta flag for OGM content */
818   if (delta_unit)
819     GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
820
821   /* set header flag for buffers that are also in the streamheaders */
822   if (is_header)
823     GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_HEADER);
824
825   if (packet->packet != NULL) {
826     /* copy packet in buffer */
827     gst_buffer_fill (buf, 0, packet->packet + offset,
828         packet->bytes - offset - trim);
829   }
830
831   GST_BUFFER_TIMESTAMP (buf) = out_timestamp;
832   GST_BUFFER_DURATION (buf) = out_duration;
833   GST_BUFFER_OFFSET (buf) = out_offset;
834   GST_BUFFER_OFFSET_END (buf) = out_offset_end;
835
836   /* Mark discont on the buffer */
837   if (pad->discont) {
838     GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
839     if (ogg->segment.rate < 0.0 || GST_BUFFER_TIMESTAMP_IS_VALID (buf))
840       pad->discont = FALSE;
841   }
842
843   /* don't push the header packets when we are asked to skip them */
844   if (!packet->b_o_s || push_headers) {
845     if (pad->last_ret == GST_FLOW_OK) {
846       GST_LOG_OBJECT (ogg, "Pushing buf %" GST_PTR_FORMAT, buf);
847       ret = gst_pad_push (GST_PAD_CAST (pad), buf);
848     } else {
849       GST_DEBUG_OBJECT (ogg, "not pushing buffer on error pad");
850       ret = pad->last_ret;
851       gst_buffer_unref (buf);
852     }
853     buf = NULL;
854   }
855
856   /* we're done with skeleton stuff */
857   if (pad->map.is_skeleton)
858     goto combine;
859
860   /* check if valid granulepos, then we can calculate the current
861    * position. We know the granule for each packet but we only want to update
862    * the position when we have a valid granulepos on the packet because else
863    * our time jumps around for the different streams. */
864   if (packet->granulepos < 0)
865     goto combine;
866
867   /* convert to time */
868   current_time = gst_ogg_stream_get_end_time_for_granulepos (&pad->map,
869       packet->granulepos);
870
871   /* convert to stream time */
872   if ((chain = pad->chain)) {
873     gint64 chain_start = 0;
874
875     if (chain->segment_start != GST_CLOCK_TIME_NONE)
876       chain_start = chain->segment_start;
877
878     current_time = current_time - chain_start + chain->begin_time;
879   }
880
881   /* and store as the current position */
882   ogg->segment.position = current_time;
883
884   GST_DEBUG_OBJECT (ogg, "ogg current time %" GST_TIME_FORMAT
885       " (%" G_GINT64_FORMAT ")", GST_TIME_ARGS (current_time), current_time);
886
887   pad->position = ogg->segment.position;
888
889   /* check stream eos */
890   if (!pad->is_eos && !delta_unit &&
891       ((ogg->segment.rate > 0.0 &&
892               ogg->segment.stop != GST_CLOCK_TIME_NONE &&
893               current_time >= ogg->segment.stop) ||
894           (ogg->segment.rate < 0.0 && current_time <= ogg->segment.start))) {
895     GST_DEBUG_OBJECT (ogg, "marking pad %p EOS", pad);
896     pad->is_eos = TRUE;
897
898     if (ret == GST_FLOW_OK) {
899       ret = GST_FLOW_EOS;
900     }
901   }
902
903 combine:
904   /* combine flows */
905   cret = gst_ogg_demux_combine_flows (ogg, pad, ret);
906
907 done:
908   if (buf)
909     gst_buffer_unref (buf);
910   /* return combined flow result */
911   return cret;
912
913   /* special cases */
914 empty_packet:
915   {
916     GST_DEBUG_OBJECT (ogg, "Skipping empty packet");
917     goto done;
918   }
919
920 invalid_packet:
921   {
922     GST_DEBUG_OBJECT (ogg, "Skipping invalid packet");
923     goto done;
924   }
925
926 no_timestamp:
927   {
928     GST_DEBUG_OBJECT (ogg, "skipping packet: no valid granule found yet");
929     goto done;
930   }
931 not_added:
932   {
933     GST_DEBUG_OBJECT (ogg, "pad not added yet");
934     goto done;
935   }
936 }
937
938 static guint64
939 gst_ogg_demux_collect_start_time (GstOggDemux * ogg, GstOggChain * chain)
940 {
941   gint i;
942   guint64 start_time = G_MAXUINT64;
943
944   for (i = 0; i < chain->streams->len; i++) {
945     GstOggPad *pad = g_array_index (chain->streams, GstOggPad *, i);
946
947     if (pad->map.is_skeleton)
948       continue;
949
950     /*  can do this if the pad start time is not defined */
951     GST_DEBUG_OBJECT (ogg, "Pad %08x (%s) start time is %" GST_TIME_FORMAT,
952         pad->map.serialno, gst_ogg_stream_get_media_type (&pad->map),
953         GST_TIME_ARGS (pad->start_time));
954     if (pad->start_time == GST_CLOCK_TIME_NONE) {
955       if (!pad->map.is_sparse) {
956         start_time = G_MAXUINT64;
957         break;
958       }
959     } else {
960       start_time = MIN (start_time, pad->start_time);
961     }
962   }
963   return start_time;
964 }
965
966 static GstClockTime
967 gst_ogg_demux_collect_sync_time (GstOggDemux * ogg, GstOggChain * chain)
968 {
969   gint i;
970   GstClockTime sync_time = GST_CLOCK_TIME_NONE;
971
972   if (!chain) {
973     GST_WARNING_OBJECT (ogg, "No chain!");
974     return GST_CLOCK_TIME_NONE;
975   }
976
977   for (i = 0; i < chain->streams->len; i++) {
978     GstOggPad *pad = g_array_index (chain->streams, GstOggPad *, i);
979
980     if (pad->map.is_sparse)
981       continue;
982
983     if (pad->push_sync_time == GST_CLOCK_TIME_NONE) {
984       sync_time = GST_CLOCK_TIME_NONE;
985       break;
986     } else {
987       if (sync_time == GST_CLOCK_TIME_NONE)
988         sync_time = pad->push_sync_time;
989       else
990         sync_time = MAX (sync_time, pad->push_sync_time);
991     }
992   }
993   return sync_time;
994 }
995
996 /* submit a packet to the oggpad, this function will run the type detection
997  * code for the pad if this is the first packet for this stream
998  */
999 static GstFlowReturn
1000 gst_ogg_pad_submit_packet (GstOggPad * pad, ogg_packet * packet)
1001 {
1002   gint64 granule;
1003   GstFlowReturn ret = GST_FLOW_OK;
1004
1005   GstOggDemux *ogg = pad->ogg;
1006
1007   GST_DEBUG_OBJECT (ogg, "%p submit packet serial %08x",
1008       pad, pad->map.serialno);
1009
1010   if (!pad->have_type) {
1011     pad->have_type = gst_ogg_stream_setup_map (&pad->map, packet);
1012     if (!pad->have_type && !pad->map.caps) {
1013       pad->map.caps = gst_caps_new_empty_simple ("application/x-unknown");
1014     }
1015     if (pad->map.is_skeleton) {
1016       GST_DEBUG_OBJECT (ogg, "we have a fishead");
1017       /* copy values over to global ogg level */
1018       ogg->basetime = pad->map.basetime;
1019       ogg->prestime = pad->map.prestime;
1020
1021       /* use total time to update the total ogg time */
1022       if (ogg->total_time == -1) {
1023         ogg->total_time = pad->map.total_time;
1024       } else if (pad->map.total_time > 0) {
1025         ogg->total_time = MAX (ogg->total_time, pad->map.total_time);
1026       }
1027     }
1028     if (!pad->map.caps) {
1029       GST_WARNING_OBJECT (ogg, "stream parser didn't create src pad caps");
1030     }
1031   }
1032
1033   if (pad->map.is_skeleton) {
1034     guint32 serialno;
1035     GstOggPad *skel_pad;
1036     GstOggSkeleton type;
1037
1038     /* try to parse the serialno first */
1039     if (gst_ogg_map_parse_fisbone (&pad->map, packet->packet, packet->bytes,
1040             &serialno, &type)) {
1041
1042       GST_DEBUG_OBJECT (pad->ogg,
1043           "got skeleton packet for stream 0x%08x", serialno);
1044
1045       skel_pad = gst_ogg_chain_get_stream (pad->chain, serialno);
1046       if (skel_pad) {
1047         switch (type) {
1048           case GST_OGG_SKELETON_FISBONE:
1049             /* parse the remainder of the fisbone in the pad with the serialno,
1050              * note that we ignore the start_time as this is usually wrong for
1051              * live streams */
1052             gst_ogg_map_add_fisbone (&skel_pad->map, &pad->map, packet->packet,
1053                 packet->bytes, NULL);
1054             break;
1055           case GST_OGG_SKELETON_INDEX:
1056             gst_ogg_map_add_index (&skel_pad->map, &pad->map, packet->packet,
1057                 packet->bytes);
1058             ogg->check_index_overflow = TRUE;
1059             break;
1060           default:
1061             break;
1062         }
1063
1064       } else {
1065         GST_WARNING_OBJECT (pad->ogg,
1066             "found skeleton fisbone for an unknown stream 0x%08x", serialno);
1067       }
1068     }
1069   }
1070
1071   GST_DEBUG_OBJECT (ogg, "%p packet has granulepos %" G_GINT64_FORMAT, pad,
1072       (gint64) packet->granulepos);
1073   granule =
1074       gst_ogg_stream_granulepos_to_granule (&pad->map, packet->granulepos);
1075   if (granule > 0) {
1076     GST_DEBUG_OBJECT (ogg, "%p has granule %" G_GINT64_FORMAT, pad, granule);
1077     pad->current_granule = granule;
1078   } else if (granule == 0) {
1079     /* headers */
1080   } else if (granule != -1) {
1081     GST_ERROR_OBJECT (ogg,
1082         "granulepos %" G_GINT64_FORMAT " yielded granule %" G_GINT64_FORMAT,
1083         (gint64) packet->granulepos, (gint64) granule);
1084     return GST_FLOW_ERROR;
1085   }
1086
1087   /* restart header packet count when seeing a b_o_s page;
1088    * particularly useful following a seek or even following chain finding */
1089   if (packet->b_o_s) {
1090     GST_DEBUG_OBJECT (ogg, "b_o_s packet, resetting header packet count");
1091     pad->map.n_header_packets_seen = 0;
1092     if (!pad->map.have_headers) {
1093       GST_DEBUG_OBJECT (ogg, "clearing header packets");
1094       g_list_foreach (pad->map.headers, (GFunc) _ogg_packet_free, NULL);
1095       g_list_free (pad->map.headers);
1096       pad->map.headers = NULL;
1097     }
1098   }
1099
1100   /* Overload the value of b_o_s in ogg_packet with a flag whether or
1101    * not this is a header packet.  Maybe some day this could be cleaned
1102    * up.  */
1103   packet->b_o_s = gst_ogg_stream_packet_is_header (&pad->map, packet);
1104   if (!packet->b_o_s) {
1105     GST_DEBUG ("found non-header packet");
1106     pad->map.have_headers = TRUE;
1107     if (pad->start_time == GST_CLOCK_TIME_NONE) {
1108       gint64 duration = gst_ogg_stream_get_packet_duration (&pad->map, packet);
1109       GST_DEBUG ("duration %" G_GINT64_FORMAT, duration);
1110       if (duration != -1) {
1111         pad->map.accumulated_granule += duration;
1112         GST_DEBUG ("accumulated granule %" G_GINT64_FORMAT,
1113             pad->map.accumulated_granule);
1114       }
1115
1116       if (packet->granulepos != -1) {
1117         ogg_int64_t start_granule;
1118         gint64 granule;
1119
1120         granule = gst_ogg_stream_granulepos_to_granule (&pad->map,
1121             packet->granulepos);
1122         if (granule < 0) {
1123           GST_ERROR_OBJECT (ogg,
1124               "granulepos %" G_GINT64_FORMAT " yielded granule %"
1125               G_GINT64_FORMAT, (gint64) packet->granulepos, (gint64) granule);
1126           return GST_FLOW_ERROR;
1127         }
1128
1129         if (granule >= pad->map.accumulated_granule)
1130           start_granule = granule - pad->map.accumulated_granule;
1131         else
1132           start_granule = 0;
1133
1134         pad->start_time = gst_ogg_stream_granule_to_time (&pad->map,
1135             start_granule);
1136         GST_DEBUG_OBJECT (ogg,
1137             "start time %" GST_TIME_FORMAT " (%" GST_TIME_FORMAT ") for %s "
1138             "from granpos %" G_GINT64_FORMAT " (granule %" G_GINT64_FORMAT ", "
1139             "accumulated granule %" G_GINT64_FORMAT,
1140             GST_TIME_ARGS (pad->start_time), GST_TIME_ARGS (pad->start_time),
1141             gst_ogg_stream_get_media_type (&pad->map),
1142             (gint64) packet->granulepos, granule, pad->map.accumulated_granule);
1143       } else {
1144         packet->granulepos = gst_ogg_stream_granule_to_granulepos (&pad->map,
1145             pad->map.accumulated_granule + pad->current_granule,
1146             pad->keyframe_granule);
1147       }
1148     }
1149   } else {
1150     /* look for tags in header packet (before inc header count) */
1151     gst_ogg_stream_extract_tags (&pad->map, packet);
1152     pad->map.n_header_packets_seen++;
1153     if (!pad->map.have_headers) {
1154       pad->map.headers =
1155           g_list_append (pad->map.headers, _ogg_packet_copy (packet));
1156       GST_DEBUG ("keeping header packet %d", pad->map.n_header_packets_seen);
1157     }
1158   }
1159
1160   /* we know the start_time of the pad data, see if we
1161    * can activate the complete chain if this is a dynamic
1162    * chain. We need all the headers too for this. */
1163   if (pad->start_time != GST_CLOCK_TIME_NONE && pad->map.have_headers) {
1164     GstOggChain *chain = pad->chain;
1165
1166     /* check if complete chain has start time */
1167     if (chain == ogg->building_chain) {
1168       GstEvent *event = NULL;
1169
1170       if (ogg->resync) {
1171         guint64 start_time;
1172
1173         GST_DEBUG_OBJECT (ogg, "need to resync");
1174
1175         /* when we need to resync after a seek, we wait until we have received
1176          * timestamps on all streams */
1177         start_time = gst_ogg_demux_collect_start_time (ogg, chain);
1178
1179         if (start_time != G_MAXUINT64) {
1180           gint64 segment_time;
1181           GstSegment segment;
1182
1183           GST_DEBUG_OBJECT (ogg, "start_time:  %" GST_TIME_FORMAT,
1184               GST_TIME_ARGS (start_time));
1185
1186           if (chain->segment_start < start_time)
1187             segment_time =
1188                 (start_time - chain->segment_start) + chain->begin_time;
1189           else
1190             segment_time = chain->begin_time;
1191
1192           /* create the newsegment event we are going to send out */
1193           gst_segment_init (&segment, GST_FORMAT_TIME);
1194
1195           GST_PUSH_LOCK (ogg);
1196           if (!ogg->pullmode && ogg->push_state == PUSH_LINEAR2) {
1197             /* if we are fast forwarding to the actual seek target,
1198                ensure previous frames are clipped */
1199             GST_DEBUG_OBJECT (ogg,
1200                 "Resynced, starting segment at %" GST_TIME_FORMAT
1201                 ", start_time %" GST_TIME_FORMAT,
1202                 GST_TIME_ARGS (ogg->push_seek_time_original_target),
1203                 GST_TIME_ARGS (start_time));
1204             segment.rate = ogg->push_seek_rate;
1205             segment.start = ogg->push_seek_time_original_target;
1206             segment.position = ogg->push_seek_time_original_target;
1207             segment.stop = ogg->push_seek_time_original_stop;
1208             segment.time = ogg->push_seek_time_original_target;
1209             segment.base = ogg->segment.base;
1210             event = gst_event_new_segment (&segment);
1211             ogg->push_state = PUSH_PLAYING;
1212           } else {
1213             segment.rate = ogg->segment.rate;
1214             segment.applied_rate = ogg->segment.applied_rate;
1215             segment.start = start_time;
1216             segment.position = start_time;
1217             segment.stop = chain->segment_stop;
1218             segment.time = segment_time;
1219             segment.base = ogg->segment.base;
1220             event = gst_event_new_segment (&segment);
1221           }
1222           GST_PUSH_UNLOCK (ogg);
1223
1224           ogg->resync = FALSE;
1225         }
1226       } else {
1227         /* see if we have enough info to activate the chain, we have enough info
1228          * when all streams have a valid start time. */
1229         if (gst_ogg_demux_collect_chain_info (ogg, chain)) {
1230           GstSegment segment;
1231
1232           GST_DEBUG_OBJECT (ogg, "segment_start: %" GST_TIME_FORMAT,
1233               GST_TIME_ARGS (chain->segment_start));
1234           GST_DEBUG_OBJECT (ogg, "segment_stop:  %" GST_TIME_FORMAT,
1235               GST_TIME_ARGS (chain->segment_stop));
1236           GST_DEBUG_OBJECT (ogg, "segment_time:  %" GST_TIME_FORMAT,
1237               GST_TIME_ARGS (chain->begin_time));
1238
1239           /* create the newsegment event we are going to send out */
1240           gst_segment_init (&segment, GST_FORMAT_TIME);
1241           segment.rate = ogg->segment.rate;
1242           segment.applied_rate = ogg->segment.applied_rate;
1243           segment.start = chain->segment_start;
1244           segment.position = chain->segment_start;
1245           segment.stop = chain->segment_stop;
1246           segment.time = chain->begin_time;
1247           segment.base = ogg->segment.base + segment.time;
1248           event = gst_event_new_segment (&segment);
1249         }
1250       }
1251
1252       if (event) {
1253         gst_event_set_seqnum (event, ogg->seqnum);
1254
1255         gst_ogg_demux_activate_chain (ogg, chain, event);
1256
1257         ogg->building_chain = NULL;
1258       }
1259     }
1260   }
1261
1262   /* if we are building a chain, store buffer for when we activate
1263    * it. This path is taken if we operate in streaming mode. */
1264   if (ogg->building_chain) {
1265     /* bos packets where stored in the header list so we can discard
1266      * them here*/
1267     if (!packet->b_o_s)
1268       ret = gst_ogg_demux_queue_data (pad, packet);
1269   }
1270   /* else we are completely streaming to the peer */
1271   else {
1272     ret = gst_ogg_demux_chain_peer (pad, packet, !ogg->pullmode);
1273   }
1274   return ret;
1275 }
1276
1277 /* flush at most @npackets from the stream layer. All packets if 
1278  * @npackets is 0;
1279  */
1280 static GstFlowReturn
1281 gst_ogg_pad_stream_out (GstOggPad * pad, gint npackets)
1282 {
1283   GstFlowReturn result = GST_FLOW_OK;
1284   gboolean done = FALSE;
1285   GstOggDemux *ogg;
1286
1287   ogg = pad->ogg;
1288
1289   while (!done) {
1290     int ret;
1291     ogg_packet packet;
1292
1293     ret = ogg_stream_packetout (&pad->map.stream, &packet);
1294     switch (ret) {
1295       case 0:
1296         GST_LOG_OBJECT (ogg, "packetout done");
1297         done = TRUE;
1298         break;
1299       case -1:
1300         GST_LOG_OBJECT (ogg, "packetout discont");
1301         if (!pad->map.is_sparse) {
1302           gst_ogg_chain_mark_discont (pad->chain);
1303         } else {
1304           gst_ogg_pad_mark_discont (pad);
1305         }
1306         break;
1307       case 1:
1308         GST_LOG_OBJECT (ogg, "packetout gave packet of size %ld", packet.bytes);
1309
1310         if (packet.granulepos < -1) {
1311           GST_WARNING_OBJECT (ogg,
1312               "Invalid granulepos (%" G_GINT64_FORMAT "), resetting stream",
1313               (gint64) packet.granulepos);
1314           gst_ogg_pad_reset (pad);
1315           break;
1316         }
1317
1318         if (packet.bytes > ogg->max_packet_size)
1319           ogg->max_packet_size = packet.bytes;
1320         result = gst_ogg_pad_submit_packet (pad, &packet);
1321         /* not linked is not a problem, it's possible that we are still
1322          * collecting headers and that we don't have exposed the pads yet */
1323         if (result == GST_FLOW_NOT_LINKED)
1324           break;
1325         else if (result <= GST_FLOW_EOS)
1326           goto could_not_submit;
1327         break;
1328       default:
1329         GST_WARNING_OBJECT (ogg,
1330             "invalid return value %d for ogg_stream_packetout, resetting stream",
1331             ret);
1332         gst_ogg_pad_reset (pad);
1333         break;
1334     }
1335     if (npackets > 0) {
1336       npackets--;
1337       done = (npackets == 0);
1338     }
1339   }
1340   return result;
1341
1342   /* ERRORS */
1343 could_not_submit:
1344   {
1345     GST_WARNING_OBJECT (ogg,
1346         "could not submit packet for stream %08x, "
1347         "error: %d", pad->map.serialno, result);
1348     gst_ogg_pad_reset (pad);
1349     return result;
1350   }
1351 }
1352
1353 static void
1354 gst_ogg_demux_setup_first_granule (GstOggDemux * ogg, GstOggPad * pad,
1355     ogg_page * page)
1356 {
1357   /* When we submit a page, we check if we have started tracking granules.
1358    * If not, we calculate the granule corresponding to the first packet
1359    * on the page. */
1360   gboolean valid_granule = TRUE;
1361
1362   if (pad->current_granule == -1) {
1363     ogg_int64_t granpos = ogg_page_granulepos (page);
1364     if (granpos > 0) {
1365       gint64 granule =
1366           (gint64) gst_ogg_stream_granulepos_to_granule (&pad->map, granpos);
1367       gint64 duration;
1368       int packets = ogg_page_packets (page), n;
1369       GST_DEBUG_OBJECT (pad,
1370           "This page completes %d packets, granule %" G_GINT64_FORMAT, packets,
1371           granule);
1372
1373       if (packets > 0) {
1374         ogg_stream_state os;
1375         ogg_packet op;
1376         int last_size = pad->map.last_size;
1377
1378         memcpy (&os, &pad->map.stream, sizeof (os));
1379         for (n = 0; valid_granule && n < packets; ++n) {
1380           int ret = ogg_stream_packetout (&os, &op);
1381           if (ret < 0) {
1382             /* This usually means a continued packet after a seek and we can't calc the first granule,
1383              * but sometimes not - so if it's ret == -1 and first packet, try again */
1384             if (ret == -1 && n == 0) {
1385               n--;
1386               continue;
1387             }
1388             GST_DEBUG_OBJECT (pad, "Failed to read packet off first page");
1389             valid_granule = FALSE;
1390             break;
1391           }
1392           if (ret == 0) {
1393             GST_WARNING_OBJECT (pad,
1394                 "Short read getting %d packets off first page", packets);
1395             valid_granule = FALSE;
1396             break;
1397           }
1398           duration = gst_ogg_stream_get_packet_duration (&pad->map, &op);
1399           GST_DEBUG_OBJECT (pad, "Packet %d has duration %" G_GINT64_FORMAT,
1400               n, duration);
1401           granule -= duration;
1402         }
1403         pad->map.last_size = last_size;
1404         if (valid_granule) {
1405           if (granule >= 0) {
1406             pad->current_granule = granule;
1407             GST_INFO_OBJECT (pad,
1408                 "Starting with first granule %" G_GINT64_FORMAT, granule);
1409           } else {
1410             pad->current_granule = 0;
1411             GST_INFO_OBJECT (pad, "Extrapolated first granule is negative, "
1412                 "used to clip samples at start");
1413           }
1414         }
1415       } else {
1416         GST_WARNING_OBJECT (pad,
1417             "Ogg page finishing no packets, but a valid granule");
1418       }
1419     }
1420   }
1421 }
1422
1423 static void
1424 gst_ogg_demux_setup_bisection_bounds (GstOggDemux * ogg)
1425 {
1426   if (ogg->push_last_seek_time >= ogg->push_seek_time_target) {
1427     GST_DEBUG_OBJECT (ogg, "We overshot by %" GST_TIME_FORMAT,
1428         GST_TIME_ARGS (ogg->push_last_seek_time - ogg->push_seek_time_target));
1429     ogg->push_offset1 = ogg->push_last_seek_offset;
1430     ogg->push_time1 = ogg->push_last_seek_time;
1431     ogg->seek_undershot = FALSE;
1432   } else {
1433     GST_DEBUG_OBJECT (ogg, "We undershot by %" GST_TIME_FORMAT,
1434         GST_TIME_ARGS (ogg->push_seek_time_target - ogg->push_last_seek_time));
1435     ogg->push_offset0 = ogg->push_last_seek_offset;
1436     ogg->push_time0 = ogg->push_last_seek_time;
1437     ogg->seek_undershot = TRUE;
1438   }
1439 }
1440
1441 static gint64
1442 gst_ogg_demux_estimate_bisection_target (GstOggDemux * ogg, float seek_quality)
1443 {
1444   gint64 best;
1445   gint64 segment_bitrate;
1446   gint64 skew;
1447
1448   /* we might not know the length of the stream in time,
1449      so push_time1 might not be set */
1450   GST_DEBUG_OBJECT (ogg,
1451       "push time 1: %" GST_TIME_FORMAT ", dbytes %" G_GINT64_FORMAT,
1452       GST_TIME_ARGS (ogg->push_time1), ogg->push_offset1 - ogg->push_offset0);
1453   if (ogg->push_time1 == GST_CLOCK_TIME_NONE) {
1454     GST_DEBUG_OBJECT (ogg,
1455         "New segment to consider: bytes %" G_GINT64_FORMAT " %" G_GINT64_FORMAT
1456         ", time %" GST_TIME_FORMAT " (open ended)", ogg->push_offset0,
1457         ogg->push_offset1, GST_TIME_ARGS (ogg->push_time0));
1458     if (ogg->push_last_seek_time == ogg->push_start_time) {
1459       /* if we're at start and don't know the end time, we can't estimate
1460          bitrate, so get the nominal declared bitrate as a failsafe, or some
1461          random constant which will be discarded after we made a (probably
1462          dire) first guess */
1463       segment_bitrate = (ogg->bitrate > 0 ? ogg->bitrate : 1000);
1464     } else {
1465       segment_bitrate =
1466           gst_util_uint64_scale (ogg->push_last_seek_offset - 0,
1467           8 * GST_SECOND, ogg->push_last_seek_time - ogg->push_start_time);
1468     }
1469     best =
1470         ogg->push_offset0 +
1471         gst_util_uint64_scale (ogg->push_seek_time_target - ogg->push_time0,
1472         segment_bitrate, 8 * GST_SECOND);
1473     ogg->seek_secant = TRUE;
1474   } else {
1475     GST_DEBUG_OBJECT (ogg,
1476         "New segment to consider: bytes %" G_GINT64_FORMAT " %" G_GINT64_FORMAT
1477         ", time %" GST_TIME_FORMAT " %" GST_TIME_FORMAT, ogg->push_offset0,
1478         ogg->push_offset1, GST_TIME_ARGS (ogg->push_time0),
1479         GST_TIME_ARGS (ogg->push_time1));
1480     if (ogg->push_time0 == ogg->push_time1) {
1481       best = ogg->push_offset0;
1482     } else {
1483       segment_bitrate =
1484           gst_util_uint64_scale (ogg->push_offset1 - ogg->push_offset0,
1485           8 * GST_SECOND, ogg->push_time1 - ogg->push_time0);
1486       GST_DEBUG_OBJECT (ogg,
1487           "Local bitrate on the %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT
1488           " segment: %" G_GINT64_FORMAT, GST_TIME_ARGS (ogg->push_time0),
1489           GST_TIME_ARGS (ogg->push_time1), segment_bitrate);
1490
1491       best =
1492           ogg->push_offset0 +
1493           gst_util_uint64_scale (ogg->push_seek_time_target - ogg->push_time0,
1494           segment_bitrate, 8 * GST_SECOND);
1495       if (seek_quality < 0.5f && ogg->seek_secant) {
1496         gint64 new_best, best2 = (ogg->push_offset0 + ogg->push_offset1) / 2;
1497         /* if dire result, give as much as 25% weight to a dumb bisection guess */
1498         float secant_weight = 1.0f - ((0.5 - seek_quality) / 0.5f) * 0.25;
1499         new_best = (best * secant_weight + best2 * (1.0f - secant_weight));
1500         GST_DEBUG_OBJECT (ogg,
1501             "Secant says %" G_GINT64_FORMAT ", straight is %" G_GINT64_FORMAT
1502             ", new best %" G_GINT64_FORMAT " with secant_weight %f", best,
1503             best2, new_best, secant_weight);
1504         best = new_best;
1505         ogg->seek_secant = FALSE;
1506       } else {
1507         ogg->seek_secant = TRUE;
1508       }
1509     }
1510   }
1511
1512   GST_DEBUG_OBJECT (ogg, "Raw best guess: %" G_GINT64_FORMAT, best);
1513
1514   /* offset the guess down as we need to capture the start of the
1515      page we are targeting - but only do so if we did not undershoot
1516      last time, as we're likely to still do this time */
1517   if (!ogg->seek_undershot) {
1518     /* very small packets are packed on pages, so offset by at least
1519        a value which is likely to get us at least one page where the
1520        packet starts */
1521     skew =
1522         ogg->max_packet_size >
1523         ogg->max_page_size ? ogg->max_packet_size : ogg->max_page_size;
1524     GST_DEBUG_OBJECT (ogg, "Offsetting by %" G_GINT64_FORMAT, skew);
1525     best -= skew;
1526   }
1527
1528   /* do not seek too close to the bounds, as we stop seeking
1529      when we get to within max_packet_size before the target */
1530   if (best > ogg->push_offset1 - ogg->max_packet_size) {
1531     best = ogg->push_offset1 - ogg->max_packet_size;
1532     GST_DEBUG_OBJECT (ogg,
1533         "Too close to high bound, pushing back to %" G_GINT64_FORMAT, best);
1534   } else if (best < ogg->push_offset0 + ogg->max_packet_size) {
1535     best = ogg->push_offset0 + ogg->max_packet_size;
1536     GST_DEBUG_OBJECT (ogg,
1537         "Too close to low bound, pushing forth to %" G_GINT64_FORMAT, best);
1538   }
1539
1540   /* keep within bounds */
1541   if (best > ogg->push_offset1)
1542     best = ogg->push_offset1;
1543   if (best < ogg->push_offset0)
1544     best = ogg->push_offset0;
1545
1546   GST_DEBUG_OBJECT (ogg, "Choosing target %" G_GINT64_FORMAT, best);
1547   return best;
1548 }
1549
1550 static void
1551 gst_ogg_demux_record_keyframe_time (GstOggDemux * ogg, GstOggPad * pad,
1552     ogg_int64_t granpos)
1553 {
1554   gint64 kf_granule;
1555   GstClockTime kf_time;
1556
1557   kf_granule = gst_ogg_stream_granulepos_to_key_granule (&pad->map, granpos);
1558   kf_time = gst_ogg_stream_granule_to_time (&pad->map, kf_granule);
1559
1560   pad->push_kf_time = kf_time;
1561 }
1562
1563 /* returns the earliest keyframe time for all non sparse pads in the chain,
1564  * if known, and GST_CLOCK_TIME_NONE if not */
1565 static GstClockTime
1566 gst_ogg_demux_get_earliest_keyframe_time (GstOggDemux * ogg)
1567 {
1568   GstClockTime t = GST_CLOCK_TIME_NONE;
1569   GstOggChain *chain = ogg->building_chain;
1570   int i;
1571
1572   if (!chain) {
1573     GST_WARNING_OBJECT (ogg, "No chain!");
1574     return GST_CLOCK_TIME_NONE;
1575   }
1576   for (i = 0; i < chain->streams->len; i++) {
1577     GstOggPad *pad = g_array_index (chain->streams, GstOggPad *, i);
1578
1579     if (pad->map.is_sparse)
1580       continue;
1581     if (pad->push_kf_time == GST_CLOCK_TIME_NONE)
1582       return GST_CLOCK_TIME_NONE;
1583     if (t == GST_CLOCK_TIME_NONE || pad->push_kf_time < t)
1584       t = pad->push_kf_time;
1585   }
1586
1587   return t;
1588 }
1589
1590 /* MUST be called with the push lock locked, and will unlock it
1591    regardless of return value. */
1592 static GstFlowReturn
1593 gst_ogg_demux_seek_back_after_push_duration_check_unlock (GstOggDemux * ogg)
1594 {
1595   GstEvent *event;
1596
1597   /* Get the delayed event, if any */
1598   event = ogg->push_mode_seek_delayed_event;
1599   ogg->push_mode_seek_delayed_event = NULL;
1600
1601   /* if we haven't learnt about the total time yet, disable seeking */
1602   if (ogg->total_time == -1)
1603     ogg->push_disable_seeking = TRUE;
1604
1605   ogg->push_state = PUSH_PLAYING;
1606
1607   /* If there is one, perform it. Otherwise, seek back at start to start
1608    * normal playback  */
1609   if (!event) {
1610     GST_INFO_OBJECT (ogg, "Seeking back to 0 after duration check");
1611     event = gst_event_new_seek (1.0, GST_FORMAT_BYTES,
1612         GST_SEEK_FLAG_ACCURATE | GST_SEEK_FLAG_FLUSH,
1613         GST_SEEK_TYPE_SET, 1, GST_SEEK_TYPE_SET, GST_CLOCK_TIME_NONE);
1614   }
1615   gst_event_replace (&ogg->seek_event, event);
1616   gst_event_unref (event);
1617   GST_PUSH_UNLOCK (ogg);
1618   g_mutex_lock (&ogg->seek_event_mutex);
1619   g_cond_broadcast (&ogg->seek_event_cond);
1620   g_mutex_unlock (&ogg->seek_event_mutex);
1621
1622   return GST_FLOW_OK;
1623 }
1624
1625 static float
1626 gst_ogg_demux_estimate_seek_quality (GstOggDemux * ogg)
1627 {
1628   GstClockTimeDiff diff;        /* how far from the goal we ended up */
1629   GstClockTimeDiff dist;        /* how far we moved this iteration */
1630   float seek_quality;
1631
1632   if (ogg->push_prev_seek_time == GST_CLOCK_TIME_NONE) {
1633     /* for the first seek, we pretend we got a good seek,
1634        as we don't have a previous seek yet */
1635     return 1.0f;
1636   }
1637
1638   /* We take a guess at how good the last seek was at guessing
1639      the byte target by comparing the amplitude of the last
1640      seek to the error */
1641   diff = GST_CLOCK_DIFF (ogg->push_seek_time_target, ogg->push_last_seek_time);
1642   if (diff < 0)
1643     diff = -diff;
1644   dist = GST_CLOCK_DIFF (ogg->push_last_seek_time, ogg->push_prev_seek_time);
1645   if (dist < 0)
1646     dist = -dist;
1647
1648   seek_quality = (dist == 0) ? 0.0f : 1.0f / (1.0f + diff / (float) dist);
1649
1650   GST_DEBUG_OBJECT (ogg,
1651       "We moved %" GST_STIME_FORMAT ", we're off by %" GST_STIME_FORMAT
1652       ", seek quality %f", GST_STIME_ARGS (dist), GST_STIME_ARGS (diff),
1653       seek_quality);
1654   return seek_quality;
1655 }
1656
1657 static void
1658 gst_ogg_demux_update_bisection_stats (GstOggDemux * ogg)
1659 {
1660   int n;
1661
1662   GST_INFO_OBJECT (ogg, "Bisection needed %d + %d steps",
1663       ogg->push_bisection_steps[0], ogg->push_bisection_steps[1]);
1664
1665   for (n = 0; n < 2; ++n) {
1666     ogg->stats_bisection_steps[n] += ogg->push_bisection_steps[n];
1667     if (ogg->stats_bisection_max_steps[n] < ogg->push_bisection_steps[n])
1668       ogg->stats_bisection_max_steps[n] = ogg->push_bisection_steps[n];
1669   }
1670   ogg->stats_nbisections++;
1671
1672   GST_INFO_OBJECT (ogg,
1673       "So far, %.2f + %.2f bisections needed per seek (max %d + %d)",
1674       ogg->stats_bisection_steps[0] / (float) ogg->stats_nbisections,
1675       ogg->stats_bisection_steps[1] / (float) ogg->stats_nbisections,
1676       ogg->stats_bisection_max_steps[0], ogg->stats_bisection_max_steps[1]);
1677 }
1678
1679 static gboolean
1680 gst_ogg_pad_handle_push_mode_state (GstOggPad * pad, ogg_page * page)
1681 {
1682   GstOggDemux *ogg = pad->ogg;
1683   ogg_int64_t granpos = ogg_page_granulepos (page);
1684
1685   GST_PUSH_LOCK (ogg);
1686   if (granpos >= 0 && pad->have_type) {
1687     if (ogg->push_start_time == GST_CLOCK_TIME_NONE) {
1688       ogg->push_start_time =
1689           gst_ogg_stream_get_start_time_for_granulepos (&pad->map, granpos);
1690       GST_DEBUG_OBJECT (ogg, "Stream start time: %" GST_TIME_FORMAT,
1691           GST_TIME_ARGS (ogg->push_start_time));
1692     }
1693     ogg->push_time_offset =
1694         gst_ogg_stream_get_end_time_for_granulepos (&pad->map, granpos);
1695     if (ogg->push_time_offset > 0) {
1696       GST_DEBUG_OBJECT (ogg, "Bitrate since start: %" G_GUINT64_FORMAT,
1697           gst_util_uint64_scale (ogg->push_byte_offset, 8 * GST_SECOND,
1698               ogg->push_time_offset));
1699     }
1700
1701     if (ogg->push_state == PUSH_DURATION) {
1702       GstClockTime t =
1703           gst_ogg_stream_get_end_time_for_granulepos (&pad->map, granpos);
1704
1705       if (ogg->total_time == GST_CLOCK_TIME_NONE || t > ogg->total_time) {
1706         GST_DEBUG_OBJECT (ogg, "New total time: %" GST_TIME_FORMAT,
1707             GST_TIME_ARGS (t));
1708         ogg->total_time = t;
1709         ogg->push_time_length = t;
1710       }
1711
1712       /* If we're still receiving data from before the seek segment, drop it */
1713       if (ogg->seek_event_drop_till != 0) {
1714         GST_PUSH_UNLOCK (ogg);
1715         return GST_FLOW_SKIP_PUSH;
1716       }
1717
1718       /* If we were determining the duration of the stream, we're now done,
1719          and can get back to sending the original event we delayed.
1720          We stop a bit before the end of the stream, as if we get a EOS
1721          event and there is a queue2 upstream (such as when using playbin),
1722          it will pause the task *after* we come back from the EOS handler,
1723          so we cannot prevent the pausing by issuing a seek. */
1724       if (ogg->push_byte_offset >= ogg->push_byte_length) {
1725         GstMessage *message;
1726         GstFlowReturn res;
1727
1728         /* tell the pipeline we've just found out the duration */
1729         ogg->push_time_length = ogg->total_time;
1730         GST_INFO_OBJECT (ogg, "New duration found: %" GST_TIME_FORMAT,
1731             GST_TIME_ARGS (ogg->total_time));
1732         message = gst_message_new_duration_changed (GST_OBJECT (ogg));
1733         gst_element_post_message (GST_ELEMENT (ogg), message);
1734
1735         GST_DEBUG_OBJECT (ogg,
1736             "We're close enough to the end, and we're scared "
1737             "to get too close, seeking back to start");
1738
1739         res = gst_ogg_demux_seek_back_after_push_duration_check_unlock (ogg);
1740         if (res != GST_FLOW_OK)
1741           return res;
1742         return GST_FLOW_SKIP_PUSH;
1743       } else {
1744         GST_PUSH_UNLOCK (ogg);
1745       }
1746       return GST_FLOW_SKIP_PUSH;
1747     }
1748   }
1749
1750   /* if we're seeking, look at time, and decide what to do */
1751   if (ogg->push_state != PUSH_PLAYING && ogg->push_state != PUSH_LINEAR2) {
1752     GstClockTime t;
1753     gint64 best = -1;
1754     GstEvent *sevent;
1755     gboolean close_enough;
1756     float seek_quality;
1757
1758     /* ignore -1 granpos when seeking, we want to sync on a real granpos */
1759     if (granpos < 0) {
1760       GST_PUSH_UNLOCK (ogg);
1761       if (ogg_stream_pagein (&pad->map.stream, page) != 0)
1762         goto choked;
1763       if (pad->current_granule == -1)
1764         gst_ogg_demux_setup_first_granule (ogg, pad, page);
1765       return GST_FLOW_SKIP_PUSH;
1766     }
1767
1768     t = gst_ogg_stream_get_end_time_for_granulepos (&pad->map, granpos);
1769
1770     if (ogg->push_state == PUSH_BISECT1 || ogg->push_state == PUSH_BISECT2) {
1771       GstClockTime sync_time;
1772
1773       if (pad->push_sync_time == GST_CLOCK_TIME_NONE)
1774         pad->push_sync_time = t;
1775       GST_DEBUG_OBJECT (ogg, "Got PTS %" GST_TIME_FORMAT " for %s",
1776           GST_TIME_ARGS (t), gst_ogg_stream_get_media_type (&pad->map));
1777       sync_time = gst_ogg_demux_collect_sync_time (ogg, ogg->building_chain);
1778       if (sync_time == GST_CLOCK_TIME_NONE) {
1779         GST_PUSH_UNLOCK (ogg);
1780         GST_DEBUG_OBJECT (ogg,
1781             "Not enough timing info collected for sync, waiting for more");
1782         if (ogg_stream_pagein (&pad->map.stream, page) != 0)
1783           goto choked;
1784         if (pad->current_granule == -1)
1785           gst_ogg_demux_setup_first_granule (ogg, pad, page);
1786         return GST_FLOW_SKIP_PUSH;
1787       }
1788       ogg->push_last_seek_time = sync_time;
1789
1790       GST_DEBUG_OBJECT (ogg,
1791           "Bisection just seeked at %" G_GINT64_FORMAT ", time %"
1792           GST_TIME_FORMAT ", target was %" GST_TIME_FORMAT,
1793           ogg->push_last_seek_offset,
1794           GST_TIME_ARGS (ogg->push_last_seek_time),
1795           GST_TIME_ARGS (ogg->push_seek_time_target));
1796
1797       if (ogg->push_time1 != GST_CLOCK_TIME_NONE) {
1798         seek_quality = gst_ogg_demux_estimate_seek_quality (ogg);
1799         GST_DEBUG_OBJECT (ogg,
1800             "Interval was %" G_GINT64_FORMAT " - %" G_GINT64_FORMAT " (%"
1801             G_GINT64_FORMAT "), time %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT
1802             " (%" GST_TIME_FORMAT "), seek quality %f", ogg->push_offset0,
1803             ogg->push_offset1, ogg->push_offset1 - ogg->push_offset0,
1804             GST_TIME_ARGS (ogg->push_time0), GST_TIME_ARGS (ogg->push_time1),
1805             GST_TIME_ARGS (ogg->push_time1 - ogg->push_time0), seek_quality);
1806       } else {
1807         /* in a open ended seek, we can't do bisection, so we pretend
1808            we like our result so far */
1809         seek_quality = 1.0f;
1810         GST_DEBUG_OBJECT (ogg,
1811             "Interval was %" G_GINT64_FORMAT " - %" G_GINT64_FORMAT " (%"
1812             G_GINT64_FORMAT "), time %" GST_TIME_FORMAT " - unknown",
1813             ogg->push_offset0, ogg->push_offset1,
1814             ogg->push_offset1 - ogg->push_offset0,
1815             GST_TIME_ARGS (ogg->push_time0));
1816       }
1817       ogg->push_prev_seek_time = ogg->push_last_seek_time;
1818
1819       gst_ogg_demux_setup_bisection_bounds (ogg);
1820
1821       best = gst_ogg_demux_estimate_bisection_target (ogg, seek_quality);
1822
1823       if (ogg->push_seek_time_target == 0) {
1824         GST_DEBUG_OBJECT (ogg, "Seeking to 0, deemed close enough");
1825         close_enough = (ogg->push_last_seek_time == 0);
1826       } else {
1827         /* TODO: make this dependent on framerate ? */
1828         GstClockTime time_threshold = GST_SECOND / 2;
1829         guint64 byte_threshold =
1830             (ogg->max_packet_size >
1831             64 * 1024 ? ogg->max_packet_size : 64 * 1024);
1832
1833         /* We want to be within half a second before the target,
1834            or before the target and half less or equal to the max
1835            packet size left to search in */
1836         if (time_threshold > ogg->push_seek_time_target)
1837           time_threshold = ogg->push_seek_time_target;
1838         close_enough = ogg->push_last_seek_time < ogg->push_seek_time_target
1839             && (ogg->push_last_seek_time >=
1840             ogg->push_seek_time_target - time_threshold
1841             || ogg->push_offset1 <= ogg->push_offset0 + byte_threshold);
1842         GST_DEBUG_OBJECT (ogg,
1843             "testing if we're close enough: %" GST_TIME_FORMAT " <= %"
1844             GST_TIME_FORMAT " < %" GST_TIME_FORMAT ", or %" G_GUINT64_FORMAT
1845             " <= %" G_GUINT64_FORMAT " ? %s",
1846             GST_TIME_ARGS (ogg->push_seek_time_target - time_threshold),
1847             GST_TIME_ARGS (ogg->push_last_seek_time),
1848             GST_TIME_ARGS (ogg->push_seek_time_target),
1849             ogg->push_offset1 - ogg->push_offset0, byte_threshold,
1850             close_enough ? "Yes" : "No");
1851       }
1852
1853       if (close_enough || best == ogg->push_last_seek_offset) {
1854         if (ogg->push_state == PUSH_BISECT1) {
1855           /* we now know the time segment we'll have to search for
1856              the second bisection */
1857           ogg->push_time0 = ogg->push_start_time;
1858           ogg->push_offset0 = 0;
1859
1860           GST_DEBUG_OBJECT (ogg,
1861               "Seek to %" GST_TIME_FORMAT
1862               " (%lx) done, now gathering pages for all non-sparse streams",
1863               GST_TIME_ARGS (ogg->push_seek_time_target), (long) granpos);
1864           ogg->push_state = PUSH_LINEAR1;
1865         } else {
1866           /* If we're asked for an accurate seek, we'll go forward till
1867              we get to the original seek target time, else we'll just drop
1868              here at the keyframe */
1869           if (ogg->push_seek_flags & GST_SEEK_FLAG_ACCURATE) {
1870             GST_INFO_OBJECT (ogg,
1871                 "Seek to keyframe at %" GST_TIME_FORMAT " done (we're at %"
1872                 GST_TIME_FORMAT "), skipping to original target (%"
1873                 GST_TIME_FORMAT ")",
1874                 GST_TIME_ARGS (ogg->push_seek_time_target),
1875                 GST_TIME_ARGS (sync_time),
1876                 GST_TIME_ARGS (ogg->push_seek_time_original_target));
1877             ogg->push_state = PUSH_LINEAR2;
1878           } else {
1879             GST_INFO_OBJECT (ogg, "Seek to keyframe done, playing");
1880
1881             /* we're synced to the seek target, so flush stream and stuff
1882                any queued pages into the stream so we start decoding there */
1883             ogg->push_state = PUSH_PLAYING;
1884           }
1885           gst_ogg_demux_update_bisection_stats (ogg);
1886         }
1887       }
1888     } else if (ogg->push_state == PUSH_LINEAR1) {
1889       if (pad->push_kf_time == GST_CLOCK_TIME_NONE) {
1890         GstClockTime earliest_keyframe_time;
1891
1892         gst_ogg_demux_record_keyframe_time (ogg, pad, granpos);
1893         GST_DEBUG_OBJECT (ogg,
1894             "Previous keyframe for %s stream at %" GST_TIME_FORMAT,
1895             gst_ogg_stream_get_media_type (&pad->map),
1896             GST_TIME_ARGS (pad->push_kf_time));
1897         earliest_keyframe_time = gst_ogg_demux_get_earliest_keyframe_time (ogg);
1898         if (earliest_keyframe_time != GST_CLOCK_TIME_NONE) {
1899           if (earliest_keyframe_time > ogg->push_last_seek_time) {
1900             GST_INFO_OBJECT (ogg,
1901                 "All non sparse streams now have a previous keyframe time, "
1902                 "and we already decoded it, switching to playing");
1903             ogg->push_state = PUSH_PLAYING;
1904             gst_ogg_demux_update_bisection_stats (ogg);
1905           } else {
1906             GST_INFO_OBJECT (ogg,
1907                 "All non sparse streams now have a previous keyframe time, "
1908                 "bisecting again to %" GST_TIME_FORMAT,
1909                 GST_TIME_ARGS (earliest_keyframe_time));
1910
1911             ogg->push_seek_time_target = earliest_keyframe_time;
1912             ogg->push_offset0 = 0;
1913             ogg->push_time0 = ogg->push_start_time;
1914             ogg->push_offset1 = ogg->push_last_seek_offset;
1915             ogg->push_time1 = ogg->push_last_seek_time;
1916             ogg->push_prev_seek_time = GST_CLOCK_TIME_NONE;
1917             ogg->seek_secant = FALSE;
1918             ogg->seek_undershot = FALSE;
1919
1920             ogg->push_state = PUSH_BISECT2;
1921             best = gst_ogg_demux_estimate_bisection_target (ogg, 1.0f);
1922           }
1923         }
1924       }
1925     }
1926
1927     if (ogg->push_state == PUSH_BISECT1 || ogg->push_state == PUSH_BISECT2) {
1928       gint i;
1929
1930       ogg_sync_reset (&ogg->sync);
1931       for (i = 0; i < ogg->building_chain->streams->len; i++) {
1932         GstOggPad *pad =
1933             g_array_index (ogg->building_chain->streams, GstOggPad *, i);
1934
1935         pad->push_sync_time = GST_CLOCK_TIME_NONE;
1936         ogg_stream_reset (&pad->map.stream);
1937       }
1938
1939       GST_DEBUG_OBJECT (ogg,
1940           "seeking to %" G_GINT64_FORMAT " - %" G_GINT64_FORMAT, best,
1941           (gint64) - 1);
1942       /* do seek */
1943       g_assert (best != -1);
1944       ogg->push_bisection_steps[ogg->push_state == PUSH_BISECT2 ? 1 : 0]++;
1945       sevent =
1946           gst_event_new_seek (ogg->push_seek_rate, GST_FORMAT_BYTES,
1947           ogg->push_seek_flags, GST_SEEK_TYPE_SET, best,
1948           GST_SEEK_TYPE_NONE, -1);
1949       gst_event_set_seqnum (sevent, ogg->seqnum);
1950
1951       gst_event_replace (&ogg->seek_event, sevent);
1952       gst_event_unref (sevent);
1953       GST_PUSH_UNLOCK (ogg);
1954       g_mutex_lock (&ogg->seek_event_mutex);
1955       g_cond_broadcast (&ogg->seek_event_cond);
1956       g_mutex_unlock (&ogg->seek_event_mutex);
1957       return GST_FLOW_SKIP_PUSH;
1958     }
1959
1960     if (ogg->push_state != PUSH_PLAYING) {
1961       GST_PUSH_UNLOCK (ogg);
1962       return GST_FLOW_SKIP_PUSH;
1963     }
1964   }
1965   GST_PUSH_UNLOCK (ogg);
1966
1967   return GST_FLOW_OK;
1968
1969 choked:
1970   {
1971     GST_WARNING_OBJECT (ogg,
1972         "ogg stream choked on page (serial %08x), "
1973         "resetting stream", pad->map.serialno);
1974     gst_ogg_pad_reset (pad);
1975     /* we continue to recover */
1976     return GST_FLOW_SKIP_PUSH;
1977   }
1978 }
1979
1980 static void
1981 gst_ogg_demux_query_duration_push (GstOggDemux * ogg)
1982 {
1983   if (!ogg->pullmode && ogg->push_byte_length == -1) {
1984     GstQuery *query;
1985     gboolean seekable = FALSE;
1986
1987     query = gst_query_new_seeking (GST_FORMAT_BYTES);
1988     if (gst_pad_peer_query (ogg->sinkpad, query))
1989       gst_query_parse_seeking (query, NULL, &seekable, NULL, NULL);
1990     gst_query_unref (query);
1991
1992     if (seekable) {
1993       gint64 length = -1;
1994       if (!gst_element_query_duration (GST_ELEMENT (ogg), GST_FORMAT_BYTES,
1995               &length)
1996           || length <= 0) {
1997         GST_DEBUG_OBJECT (ogg,
1998             "Unable to determine stream size, assuming live, seeking disabled");
1999         ogg->push_disable_seeking = TRUE;
2000       } else {
2001         ogg->push_disable_seeking = FALSE;
2002       }
2003     } else {
2004       GST_DEBUG_OBJECT (ogg, "Stream is not seekable, seeking disabled");
2005       ogg->push_disable_seeking = TRUE;
2006     }
2007   }
2008 }
2009
2010 /* submit a page to an oggpad, this function will then submit all
2011  * the packets in the page.
2012  */
2013 static GstFlowReturn
2014 gst_ogg_pad_submit_page (GstOggPad * pad, ogg_page * page)
2015 {
2016   GstFlowReturn result = GST_FLOW_OK;
2017   GstOggDemux *ogg;
2018   gboolean continued = FALSE;
2019
2020   ogg = pad->ogg;
2021
2022   /* for negative rates we read pages backwards and must therefore be careful
2023    * with continued pages */
2024   if (ogg->segment.rate < 0.0) {
2025     gint npackets;
2026
2027     continued = ogg_page_continued (page);
2028
2029     /* number of completed packets in the page */
2030     npackets = ogg_page_packets (page);
2031     if (!continued) {
2032       /* page is not continued so it contains at least one packet start. It's
2033        * possible that no packet ends on this page (npackets == 0). In that
2034        * case, the next (continued) page(s) we kept contain the remainder of the
2035        * packets. We mark npackets=1 to make us start decoding the pages in the
2036        * remainder of the algorithm. */
2037       if (npackets == 0)
2038         npackets = 1;
2039     }
2040     GST_LOG_OBJECT (ogg, "continued: %d, %d packets", continued, npackets);
2041
2042     if (npackets == 0) {
2043       GST_LOG_OBJECT (ogg, "no decodable packets, we need a previous page");
2044       goto done;
2045     }
2046   }
2047
2048   gst_ogg_demux_query_duration_push (ogg);
2049
2050   /* keep track of time in push mode */
2051   if (!ogg->pullmode) {
2052     result = gst_ogg_pad_handle_push_mode_state (pad, page);
2053     if (result == GST_FLOW_SKIP_PUSH)
2054       return GST_FLOW_OK;
2055     if (result != GST_FLOW_OK)
2056       return result;
2057   }
2058
2059   if (page->header_len + page->body_len > ogg->max_page_size)
2060     ogg->max_page_size = page->header_len + page->body_len;
2061
2062   if (ogg_stream_pagein (&pad->map.stream, page) != 0)
2063     goto choked;
2064   if (pad->current_granule == -1)
2065     gst_ogg_demux_setup_first_granule (ogg, pad, page);
2066
2067   /* flush all packets in the stream layer, this might not give a packet if
2068    * the page had no packets finishing on the page (npackets == 0). */
2069   result = gst_ogg_pad_stream_out (pad, 0);
2070
2071   if (pad->continued) {
2072     ogg_packet packet;
2073
2074     /* now send the continued pages to the stream layer */
2075     while (pad->continued) {
2076       ogg_page *p = (ogg_page *) pad->continued->data;
2077
2078       GST_LOG_OBJECT (ogg, "submitting continued page %p", p);
2079       if (ogg_stream_pagein (&pad->map.stream, p) != 0)
2080         goto choked;
2081
2082       pad->continued = g_list_delete_link (pad->continued, pad->continued);
2083
2084       /* free the page */
2085       gst_ogg_page_free (p);
2086     }
2087
2088     GST_LOG_OBJECT (ogg, "flushing last continued packet");
2089     /* flush 1 continued packet in the stream layer */
2090     result = gst_ogg_pad_stream_out (pad, 1);
2091
2092     /* flush all remaining packets, we pushed them in the previous round.
2093      * We don't use _reset() because we still want to get the discont when
2094      * we submit a next page. */
2095     while (ogg_stream_packetout (&pad->map.stream, &packet) != 0);
2096   }
2097
2098 done:
2099   /* keep continued pages (only in reverse mode) */
2100   if (continued) {
2101     ogg_page *p = gst_ogg_page_copy (page);
2102
2103     GST_LOG_OBJECT (ogg, "keeping continued page %p", p);
2104     pad->continued = g_list_prepend (pad->continued, p);
2105   }
2106
2107   return result;
2108
2109 choked:
2110   {
2111     GST_WARNING_OBJECT (ogg,
2112         "ogg stream choked on page (serial %08x), "
2113         "resetting stream", pad->map.serialno);
2114     gst_ogg_pad_reset (pad);
2115     /* we continue to recover */
2116     return GST_FLOW_OK;
2117   }
2118 }
2119
2120
2121 static GstOggChain *
2122 gst_ogg_chain_new (GstOggDemux * ogg)
2123 {
2124   GstOggChain *chain = g_slice_new0 (GstOggChain);
2125
2126   GST_DEBUG_OBJECT (ogg, "creating new chain %p", chain);
2127   chain->ogg = ogg;
2128   chain->offset = -1;
2129   chain->bytes = -1;
2130   chain->have_bos = FALSE;
2131   chain->streams = g_array_new (FALSE, TRUE, sizeof (GstOggPad *));
2132   chain->begin_time = GST_CLOCK_TIME_NONE;
2133   chain->segment_start = GST_CLOCK_TIME_NONE;
2134   chain->segment_stop = GST_CLOCK_TIME_NONE;
2135   chain->total_time = GST_CLOCK_TIME_NONE;
2136
2137   return chain;
2138 }
2139
2140 static void
2141 gst_ogg_chain_free (GstOggChain * chain)
2142 {
2143   gint i;
2144
2145   for (i = 0; i < chain->streams->len; i++) {
2146     GstOggPad *pad = g_array_index (chain->streams, GstOggPad *, i);
2147
2148     gst_object_unref (pad);
2149   }
2150   g_array_free (chain->streams, TRUE);
2151   g_slice_free (GstOggChain, chain);
2152 }
2153
2154 static void
2155 gst_ogg_pad_mark_discont (GstOggPad * pad)
2156 {
2157   GST_LOG_OBJECT (pad, "Marking discont on pad");
2158   pad->discont = TRUE;
2159   pad->map.last_size = 0;
2160 }
2161
2162 static void
2163 gst_ogg_chain_mark_discont (GstOggChain * chain)
2164 {
2165   gint i;
2166
2167   for (i = 0; i < chain->streams->len; i++) {
2168     GstOggPad *pad = g_array_index (chain->streams, GstOggPad *, i);
2169
2170     gst_ogg_pad_mark_discont (pad);
2171   }
2172 }
2173
2174 static void
2175 gst_ogg_chain_reset (GstOggChain * chain)
2176 {
2177   gint i;
2178
2179   for (i = 0; i < chain->streams->len; i++) {
2180     GstOggPad *pad = g_array_index (chain->streams, GstOggPad *, i);
2181
2182     gst_ogg_pad_reset (pad);
2183   }
2184 }
2185
2186 static GstOggPad *
2187 gst_ogg_chain_new_stream (GstOggChain * chain, guint32 serialno)
2188 {
2189   GstOggPad *ret;
2190   gchar *name;
2191
2192   GST_DEBUG_OBJECT (chain->ogg,
2193       "creating new stream %08x in chain %p", serialno, chain);
2194
2195   name = g_strdup_printf ("src_%08x", serialno);
2196   ret = g_object_new (GST_TYPE_OGG_PAD, "name", name, NULL);
2197   g_free (name);
2198   /* we own this one */
2199   gst_object_ref_sink (ret);
2200
2201   GST_PAD_DIRECTION (ret) = GST_PAD_SRC;
2202   gst_ogg_pad_mark_discont (ret);
2203
2204   ret->chain = chain;
2205   ret->ogg = chain->ogg;
2206
2207   ret->map.serialno = serialno;
2208   if (ogg_stream_init (&ret->map.stream, serialno) != 0)
2209     goto init_failed;
2210
2211   GST_DEBUG_OBJECT (chain->ogg,
2212       "created new ogg src %p for stream with serial %08x", ret, serialno);
2213
2214   g_array_append_val (chain->streams, ret);
2215   gst_pad_set_active (GST_PAD_CAST (ret), TRUE);
2216
2217   return ret;
2218
2219   /* ERRORS */
2220 init_failed:
2221   {
2222     GST_ERROR ("Could not initialize ogg_stream struct for serial %08x",
2223         serialno);
2224     gst_object_unref (ret);
2225     return NULL;
2226   }
2227 }
2228
2229 static GstOggPad *
2230 gst_ogg_chain_get_stream (GstOggChain * chain, guint32 serialno)
2231 {
2232   gint i;
2233
2234   for (i = 0; i < chain->streams->len; i++) {
2235     GstOggPad *pad = g_array_index (chain->streams, GstOggPad *, i);
2236
2237     if (pad->map.serialno == serialno)
2238       return pad;
2239   }
2240   return NULL;
2241 }
2242
2243 static gboolean
2244 gst_ogg_chain_has_stream (GstOggChain * chain, guint32 serialno)
2245 {
2246   return gst_ogg_chain_get_stream (chain, serialno) != NULL;
2247 }
2248
2249 /* signals and args */
2250 enum
2251 {
2252   /* FILL ME */
2253   LAST_SIGNAL
2254 };
2255
2256 enum
2257 {
2258   ARG_0
2259       /* FILL ME */
2260 };
2261
2262 static GstStaticPadTemplate ogg_demux_src_template_factory =
2263 GST_STATIC_PAD_TEMPLATE ("src_%08x",
2264     GST_PAD_SRC,
2265     GST_PAD_SOMETIMES,
2266     GST_STATIC_CAPS_ANY);
2267
2268 static GstStaticPadTemplate ogg_demux_sink_template_factory =
2269     GST_STATIC_PAD_TEMPLATE ("sink",
2270     GST_PAD_SINK,
2271     GST_PAD_ALWAYS,
2272     GST_STATIC_CAPS ("application/ogg; audio/ogg; video/ogg; application/kate")
2273     );
2274
2275 static void gst_ogg_demux_finalize (GObject * object);
2276
2277 static GstFlowReturn gst_ogg_demux_read_chain (GstOggDemux * ogg,
2278     GstOggChain ** chain);
2279 static GstFlowReturn gst_ogg_demux_read_end_chain (GstOggDemux * ogg,
2280     GstOggChain * chain);
2281
2282 static gboolean gst_ogg_demux_sink_event (GstPad * pad, GstObject * parent,
2283     GstEvent * event);
2284 static void gst_ogg_demux_loop (GstOggPad * pad);
2285 static GstFlowReturn gst_ogg_demux_chain (GstPad * pad, GstObject * parent,
2286     GstBuffer * buffer);
2287 static gboolean gst_ogg_demux_sink_activate (GstPad * sinkpad,
2288     GstObject * parent);
2289 static gboolean gst_ogg_demux_sink_activate_mode (GstPad * sinkpad,
2290     GstObject * parent, GstPadMode mode, gboolean active);
2291 static GstStateChangeReturn gst_ogg_demux_change_state (GstElement * element,
2292     GstStateChange transition);
2293
2294 static void gst_ogg_print (GstOggDemux * demux);
2295 static gboolean gst_ogg_demux_plugin_init (GstPlugin * plugin);
2296
2297 #define gst_ogg_demux_parent_class parent_class
2298 G_DEFINE_TYPE (GstOggDemux, gst_ogg_demux, GST_TYPE_ELEMENT);
2299 GST_ELEMENT_REGISTER_DEFINE_WITH_CODE (oggdemux, "oggdemux", GST_RANK_PRIMARY,
2300     GST_TYPE_OGG_DEMUX, gst_ogg_demux_plugin_init (plugin));
2301
2302 static void
2303 gst_ogg_demux_class_init (GstOggDemuxClass * klass)
2304 {
2305   GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
2306   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
2307
2308   gst_element_class_set_static_metadata (gstelement_class,
2309       "Ogg demuxer", "Codec/Demuxer",
2310       "demux ogg streams (info about ogg: http://xiph.org)",
2311       "Wim Taymans <wim@fluendo.com>");
2312
2313   gst_element_class_add_static_pad_template (gstelement_class,
2314       &ogg_demux_sink_template_factory);
2315   gst_element_class_add_static_pad_template (gstelement_class,
2316       &ogg_demux_src_template_factory);
2317
2318   gstelement_class->change_state = gst_ogg_demux_change_state;
2319   gstelement_class->send_event = gst_ogg_demux_receive_event;
2320
2321   gobject_class->finalize = gst_ogg_demux_finalize;
2322 }
2323
2324 static void
2325 gst_ogg_demux_init (GstOggDemux * ogg)
2326 {
2327   /* create the sink pad */
2328   ogg->sinkpad =
2329       gst_pad_new_from_static_template (&ogg_demux_sink_template_factory,
2330       "sink");
2331
2332   gst_pad_set_event_function (ogg->sinkpad, gst_ogg_demux_sink_event);
2333   gst_pad_set_chain_function (ogg->sinkpad, gst_ogg_demux_chain);
2334   gst_pad_set_activate_function (ogg->sinkpad, gst_ogg_demux_sink_activate);
2335   gst_pad_set_activatemode_function (ogg->sinkpad,
2336       gst_ogg_demux_sink_activate_mode);
2337   gst_element_add_pad (GST_ELEMENT (ogg), ogg->sinkpad);
2338
2339   g_mutex_init (&ogg->chain_lock);
2340   g_mutex_init (&ogg->push_lock);
2341   g_mutex_init (&ogg->seek_event_mutex);
2342   g_cond_init (&ogg->seek_event_cond);
2343   g_cond_init (&ogg->thread_started_cond);
2344
2345   ogg->chains = g_array_new (FALSE, TRUE, sizeof (GstOggChain *));
2346
2347   ogg->stats_nbisections = 0;
2348   ogg->stats_bisection_steps[0] = 0;
2349   ogg->stats_bisection_steps[1] = 0;
2350   ogg->stats_bisection_max_steps[0] = 0;
2351   ogg->stats_bisection_max_steps[1] = 0;
2352
2353   ogg->newsegment = NULL;
2354   ogg->seqnum = GST_SEQNUM_INVALID;
2355
2356   ogg->chunk_size = CHUNKSIZE;
2357   ogg->flowcombiner = gst_flow_combiner_new ();
2358 }
2359
2360 static void
2361 gst_ogg_demux_finalize (GObject * object)
2362 {
2363   GstOggDemux *ogg;
2364
2365   ogg = GST_OGG_DEMUX (object);
2366
2367   g_array_free (ogg->chains, TRUE);
2368   g_mutex_clear (&ogg->chain_lock);
2369   g_mutex_clear (&ogg->push_lock);
2370   g_cond_clear (&ogg->seek_event_cond);
2371   g_cond_clear (&ogg->thread_started_cond);
2372   g_mutex_clear (&ogg->seek_event_mutex);
2373
2374   ogg_sync_clear (&ogg->sync);
2375
2376   if (ogg->newsegment)
2377     gst_event_unref (ogg->newsegment);
2378
2379   gst_flow_combiner_free (ogg->flowcombiner);
2380
2381   if (ogg->building_chain)
2382     gst_ogg_chain_free (ogg->building_chain);
2383
2384   G_OBJECT_CLASS (parent_class)->finalize (object);
2385 }
2386
2387 static void
2388 gst_ogg_demux_reset_streams (GstOggDemux * ogg)
2389 {
2390   GstOggChain *chain;
2391   guint i;
2392
2393   chain = ogg->current_chain;
2394   if (chain == NULL)
2395     return;
2396
2397   for (i = 0; i < chain->streams->len; i++) {
2398     GstOggPad *stream = g_array_index (chain->streams, GstOggPad *, i);
2399
2400     stream->start_time = -1;
2401     stream->map.accumulated_granule = 0;
2402     stream->current_granule = -1;
2403     stream->keyframe_granule = -1;
2404   }
2405   ogg->building_chain = chain;
2406   GST_DEBUG_OBJECT (ogg, "Resetting current chain");
2407   ogg->current_chain = NULL;
2408   ogg->resync = TRUE;
2409   gst_ogg_chain_mark_discont (chain);
2410
2411   ogg->chunk_size = CHUNKSIZE;
2412 }
2413
2414 static gboolean
2415 gst_ogg_demux_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
2416 {
2417   gboolean res;
2418   GstOggDemux *ogg;
2419
2420   ogg = GST_OGG_DEMUX (parent);
2421
2422   switch (GST_EVENT_TYPE (event)) {
2423     case GST_EVENT_FLUSH_START:
2424       if (ogg->seqnum != GST_SEQNUM_INVALID) {
2425         event = gst_event_make_writable (event);
2426         gst_event_set_seqnum (event, ogg->seqnum);
2427       }
2428       res = gst_ogg_demux_send_event (ogg, event);
2429       break;
2430     case GST_EVENT_FLUSH_STOP:
2431       GST_DEBUG_OBJECT (ogg, "got a flush stop event");
2432       ogg_sync_reset (&ogg->sync);
2433       if (ogg->seqnum != GST_SEQNUM_INVALID) {
2434         event = gst_event_make_writable (event);
2435         gst_event_set_seqnum (event, ogg->seqnum);
2436       }
2437       res = gst_ogg_demux_send_event (ogg, event);
2438       if (ogg->pullmode || ogg->push_state != PUSH_DURATION) {
2439         /* it's starting to feel reaaaally dirty :(
2440            if we're on a spliced seek to get duration, don't reset streams,
2441            we'll need them for the delayed seek */
2442         gst_ogg_demux_reset_streams (ogg);
2443       }
2444       break;
2445     case GST_EVENT_SEGMENT:
2446       GST_DEBUG_OBJECT (ogg, "got a new segment event");
2447       {
2448         GstSegment segment;
2449         gboolean update;
2450
2451         gst_event_copy_segment (event, &segment);
2452
2453         if (segment.format == GST_FORMAT_BYTES) {
2454           GST_PUSH_LOCK (ogg);
2455           ogg->push_byte_offset = segment.start;
2456           ogg->push_last_seek_offset = segment.start;
2457
2458           if (gst_event_get_seqnum (event) == ogg->seqnum) {
2459             GstSeekType stop_type = GST_SEEK_TYPE_NONE;
2460             if (ogg->push_seek_time_original_stop != -1)
2461               stop_type = GST_SEEK_TYPE_SET;
2462             gst_segment_do_seek (&ogg->segment, ogg->push_seek_rate,
2463                 GST_FORMAT_TIME, ogg->push_seek_flags, GST_SEEK_TYPE_SET,
2464                 ogg->push_seek_time_original_target, stop_type,
2465                 ogg->push_seek_time_original_stop, &update);
2466           } else if (ogg->seqnum == GST_SEQNUM_INVALID) {
2467             ogg->seqnum = GST_EVENT_SEQNUM (event);
2468           }
2469
2470           if (!ogg->pullmode && !(ogg->push_seek_flags & GST_SEEK_FLAG_FLUSH)) {
2471             int i;
2472             GstOggChain *chain = ogg->current_chain;
2473
2474             ogg->push_seek_flags = 0;
2475             if (!chain) {
2476               /* This will happen when we bisect, as we clear the chain when
2477                  we do the first seek. On subsequent ones, we just reset the
2478                  ogg sync object as we already reset the chain */
2479               GST_DEBUG_OBJECT (ogg, "No chain, just resetting ogg sync");
2480               ogg_sync_reset (&ogg->sync);
2481             } else {
2482               /* reset pad push mode seeking state */
2483               for (i = 0; i < chain->streams->len; i++) {
2484                 GstOggPad *pad = g_array_index (chain->streams, GstOggPad *, i);
2485                 pad->push_kf_time = GST_CLOCK_TIME_NONE;
2486                 pad->push_sync_time = GST_CLOCK_TIME_NONE;
2487               }
2488               ogg_sync_reset (&ogg->sync);
2489               gst_ogg_demux_reset_streams (ogg);
2490             }
2491           }
2492
2493           if (!ogg->pullmode) {
2494             if (ogg->seek_event_drop_till == gst_event_get_seqnum (event)) {
2495               GST_DEBUG_OBJECT (ogg,
2496                   "Got event seqnum %u, stopping dropping (ogg->seqnum:%u)",
2497                   ogg->seek_event_drop_till, ogg->seqnum);
2498               ogg->seek_event_drop_till = 0;
2499             }
2500           }
2501           GST_PUSH_UNLOCK (ogg);
2502         } else {
2503           GST_WARNING_OBJECT (ogg, "unexpected segment format: %s",
2504               gst_format_get_name (segment.format));
2505         }
2506       }
2507
2508       gst_event_unref (event);
2509       res = TRUE;
2510       break;
2511     case GST_EVENT_EOS:
2512     {
2513       GST_DEBUG_OBJECT (ogg, "got an EOS event");
2514       GST_PUSH_LOCK (ogg);
2515       if (ogg->push_state == PUSH_DURATION) {
2516         GST_DEBUG_OBJECT (ogg, "Got EOS while determining length");
2517         res = gst_ogg_demux_seek_back_after_push_duration_check_unlock (ogg);
2518         if (res != GST_FLOW_OK) {
2519           GST_DEBUG_OBJECT (ogg, "Error seeking back after duration check: %d",
2520               res);
2521         }
2522         break;
2523       } else
2524         GST_PUSH_UNLOCK (ogg);
2525       res = gst_ogg_demux_send_event (ogg, event);
2526       if (ogg->current_chain == NULL) {
2527         GST_WARNING_OBJECT (ogg,
2528             "EOS while trying to retrieve chain, seeking disabled");
2529         ogg->push_disable_seeking = TRUE;
2530         res = TRUE;
2531       }
2532       break;
2533     }
2534     default:
2535       res = gst_pad_event_default (pad, parent, event);
2536       break;
2537   }
2538
2539   return res;
2540 }
2541
2542 /* submit the given buffer to the ogg sync */
2543 static GstFlowReturn
2544 gst_ogg_demux_submit_buffer (GstOggDemux * ogg, GstBuffer * buffer)
2545 {
2546   gsize size;
2547   gchar *oggbuffer;
2548   GstFlowReturn ret = GST_FLOW_OK;
2549
2550   size = gst_buffer_get_size (buffer);
2551   GST_DEBUG_OBJECT (ogg, "submitting %" G_GSIZE_FORMAT " bytes", size);
2552   if (G_UNLIKELY (size == 0))
2553     goto done;
2554
2555   oggbuffer = ogg_sync_buffer (&ogg->sync, size);
2556   if (G_UNLIKELY (oggbuffer == NULL))
2557     goto no_buffer;
2558
2559   gst_buffer_extract (buffer, 0, oggbuffer, size);
2560
2561   if (G_UNLIKELY (ogg_sync_wrote (&ogg->sync, size) < 0))
2562     goto write_failed;
2563
2564   if (!ogg->pullmode) {
2565     GST_PUSH_LOCK (ogg);
2566     ogg->push_byte_offset += size;
2567     GST_PUSH_UNLOCK (ogg);
2568   }
2569
2570 done:
2571   gst_buffer_unref (buffer);
2572
2573   return ret;
2574
2575   /* ERRORS */
2576 no_buffer:
2577   {
2578     GST_ELEMENT_ERROR (ogg, STREAM, DECODE,
2579         (NULL), ("failed to get ogg sync buffer"));
2580     ret = GST_FLOW_ERROR;
2581     goto done;
2582   }
2583 write_failed:
2584   {
2585     GST_ELEMENT_ERROR (ogg, STREAM, DECODE, (NULL),
2586         ("failed to write %" G_GSIZE_FORMAT " bytes to the sync buffer", size));
2587     ret = GST_FLOW_ERROR;
2588     goto done;
2589   }
2590 }
2591
2592 /* in random access mode this code updates the current read position
2593  * and resets the ogg sync buffer so that the next read will happen
2594  * from this new location.
2595  */
2596 static void
2597 gst_ogg_demux_seek (GstOggDemux * ogg, gint64 offset)
2598 {
2599   GST_LOG_OBJECT (ogg, "seeking to %" G_GINT64_FORMAT, offset);
2600
2601   ogg->offset = offset;
2602   ogg->read_offset = offset;
2603   ogg_sync_reset (&ogg->sync);
2604 }
2605
2606 /* read more data from the current offset and submit to
2607  * the ogg sync layer.
2608  */
2609 static GstFlowReturn
2610 gst_ogg_demux_get_data (GstOggDemux * ogg, gint64 end_offset)
2611 {
2612   GstFlowReturn ret;
2613   GstBuffer *buffer;
2614   gchar *oggbuffer;
2615   gsize size;
2616
2617   GST_LOG_OBJECT (ogg,
2618       "get data %" G_GINT64_FORMAT " %" G_GINT64_FORMAT " %" G_GINT64_FORMAT,
2619       ogg->read_offset, ogg->length, end_offset);
2620
2621   if (end_offset > 0 && ogg->read_offset >= end_offset)
2622     goto boundary_reached;
2623
2624   if (ogg->read_offset == ogg->length)
2625     goto eos;
2626
2627   oggbuffer = ogg_sync_buffer (&ogg->sync, ogg->chunk_size);
2628   if (G_UNLIKELY (oggbuffer == NULL))
2629     goto no_buffer;
2630
2631   buffer =
2632       gst_buffer_new_wrapped_full (0, oggbuffer, ogg->chunk_size, 0,
2633       ogg->chunk_size, NULL, NULL);
2634
2635   ret =
2636       gst_pad_pull_range (ogg->sinkpad, ogg->read_offset, ogg->chunk_size,
2637       &buffer);
2638   if (ret != GST_FLOW_OK)
2639     goto error;
2640
2641   size = gst_buffer_get_size (buffer);
2642
2643   if (G_UNLIKELY (ogg_sync_wrote (&ogg->sync, size) < 0))
2644     goto write_failed;
2645
2646   ogg->read_offset += size;
2647   gst_buffer_unref (buffer);
2648
2649   return ret;
2650
2651   /* ERROR */
2652 boundary_reached:
2653   {
2654     GST_LOG_OBJECT (ogg, "reached boundary");
2655     return GST_FLOW_LIMIT;
2656   }
2657 eos:
2658   {
2659     GST_LOG_OBJECT (ogg, "reached EOS");
2660     return GST_FLOW_EOS;
2661   }
2662 no_buffer:
2663   {
2664     GST_ELEMENT_ERROR (ogg, STREAM, DECODE,
2665         (NULL), ("failed to get ogg sync buffer"));
2666     return GST_FLOW_ERROR;
2667   }
2668 error:
2669   {
2670     GST_WARNING_OBJECT (ogg, "got %d (%s) from pull range", ret,
2671         gst_flow_get_name (ret));
2672     gst_buffer_unref (buffer);
2673     return ret;
2674   }
2675 write_failed:
2676   {
2677     GST_ELEMENT_ERROR (ogg, STREAM, DECODE, (NULL),
2678         ("failed to write %" G_GSIZE_FORMAT " bytes to the sync buffer", size));
2679     gst_buffer_unref (buffer);
2680     return GST_FLOW_ERROR;
2681   }
2682 }
2683
2684 /* Read the next page from the current offset.
2685  * boundary: number of bytes ahead we allow looking for;
2686  * -1 if no boundary
2687  *
2688  * @offset will contain the offset the next page starts at when this function
2689  * returns GST_FLOW_OK.
2690  *
2691  * GST_FLOW_EOS is returned on EOS.
2692  *
2693  * GST_FLOW_LIMIT is returned when we did not find a page before the
2694  * boundary. If @boundary is -1, this is never returned.
2695  *
2696  * Any other error returned while retrieving data from the peer is returned as
2697  * is.
2698  */
2699 static GstFlowReturn
2700 gst_ogg_demux_get_next_page (GstOggDemux * ogg, ogg_page * og,
2701     gint64 boundary, gint64 * offset)
2702 {
2703   gint64 end_offset = -1;
2704   GstFlowReturn ret;
2705
2706   GST_LOG_OBJECT (ogg,
2707       "get next page, current offset %" G_GINT64_FORMAT ", bytes boundary %"
2708       G_GINT64_FORMAT, ogg->offset, boundary);
2709
2710   if (boundary >= 0)
2711     end_offset = ogg->offset + boundary;
2712
2713   while (TRUE) {
2714     glong more;
2715
2716     if (end_offset > 0 && ogg->offset >= end_offset)
2717       goto boundary_reached;
2718
2719     more = ogg_sync_pageseek (&ogg->sync, og);
2720
2721     GST_LOG_OBJECT (ogg, "pageseek gave %ld", more);
2722
2723     if (more < 0) {
2724       /* skipped n bytes */
2725       ogg->offset -= more;
2726       GST_LOG_OBJECT (ogg, "skipped %ld bytes, offset %" G_GINT64_FORMAT,
2727           more, ogg->offset);
2728     } else if (more == 0) {
2729       /* we need more data */
2730       if (boundary == 0)
2731         goto boundary_reached;
2732
2733       GST_LOG_OBJECT (ogg, "need more data");
2734       ret = gst_ogg_demux_get_data (ogg, end_offset);
2735       if (ret != GST_FLOW_OK)
2736         break;
2737     } else {
2738       gint64 res_offset = ogg->offset;
2739
2740       /* got a page.  Return the offset at the page beginning,
2741          advance the internal offset past the page end */
2742       if (offset)
2743         *offset = res_offset;
2744       ret = GST_FLOW_OK;
2745
2746       ogg->offset += more;
2747
2748       GST_LOG_OBJECT (ogg,
2749           "got page at %" G_GINT64_FORMAT ", serial %08x, end at %"
2750           G_GINT64_FORMAT ", granule %" G_GINT64_FORMAT, res_offset,
2751           ogg_page_serialno (og), ogg->offset,
2752           (gint64) ogg_page_granulepos (og));
2753       break;
2754     }
2755   }
2756   GST_LOG_OBJECT (ogg, "returning %d", ret);
2757
2758   return ret;
2759
2760   /* ERRORS */
2761 boundary_reached:
2762   {
2763     GST_LOG_OBJECT (ogg,
2764         "offset %" G_GINT64_FORMAT " >= end_offset %" G_GINT64_FORMAT,
2765         ogg->offset, end_offset);
2766     return GST_FLOW_LIMIT;
2767   }
2768 }
2769
2770 /* from the current offset, find the previous page, seeking backwards
2771  * until we find the page. 
2772  */
2773 static GstFlowReturn
2774 gst_ogg_demux_get_prev_page (GstOggDemux * ogg, ogg_page * og, gint64 * offset)
2775 {
2776   GstFlowReturn ret;
2777   gint64 begin = ogg->offset;
2778   gint64 end = begin;
2779   gint64 cur_offset = -1;
2780
2781   GST_LOG_OBJECT (ogg, "getting page before %" G_GINT64_FORMAT, begin);
2782
2783   while (cur_offset == -1) {
2784     begin -= ogg->chunk_size;
2785     if (begin < 0)
2786       begin = 0;
2787
2788     /* seek ogg->chunk_size back */
2789     GST_LOG_OBJECT (ogg, "seeking back to %" G_GINT64_FORMAT, begin);
2790     gst_ogg_demux_seek (ogg, begin);
2791
2792     /* now continue reading until we run out of data, if we find a page
2793      * start, we save it. It might not be the final page as there could be
2794      * another page after this one. */
2795     while (ogg->offset < end) {
2796       gint64 new_offset, boundary;
2797
2798       /* An Ogg page cannot be more than a bit less than 64 KB, so we can
2799          bound the boundary to that size when searching backwards if we
2800          haven't found a page yet. So the most we have to look at is twice
2801          the max page size, which is the worst case if we start scanning
2802          just after a large page, after which also lies a large page. */
2803       boundary = end - ogg->offset;
2804       if (boundary > 2 * MAX_OGG_PAGE_SIZE)
2805         boundary = 2 * MAX_OGG_PAGE_SIZE;
2806
2807       ret = gst_ogg_demux_get_next_page (ogg, og, boundary, &new_offset);
2808       /* we hit the upper limit, offset contains the last page start */
2809       if (ret == GST_FLOW_LIMIT) {
2810         GST_LOG_OBJECT (ogg, "hit limit");
2811         break;
2812       }
2813       /* something went wrong */
2814       if (ret == GST_FLOW_EOS) {
2815         new_offset = 0;
2816         GST_LOG_OBJECT (ogg, "got unexpected");
2817         /* We hit EOS. */
2818         goto beach;
2819       } else if (ret != GST_FLOW_OK) {
2820         GST_LOG_OBJECT (ogg, "got error %d", ret);
2821         return ret;
2822       }
2823
2824       GST_LOG_OBJECT (ogg, "found page at %" G_GINT64_FORMAT, new_offset);
2825
2826       /* offset is next page start */
2827       cur_offset = new_offset;
2828     }
2829   }
2830
2831   GST_LOG_OBJECT (ogg, "found previous page at %" G_GINT64_FORMAT, cur_offset);
2832
2833   /* we have the offset.  Actually snork and hold the page now */
2834   gst_ogg_demux_seek (ogg, cur_offset);
2835   ret = gst_ogg_demux_get_next_page (ogg, og, -1, NULL);
2836   if (ret != GST_FLOW_OK) {
2837     GST_WARNING_OBJECT (ogg, "can't get last page at %" G_GINT64_FORMAT,
2838         cur_offset);
2839     /* this shouldn't be possible */
2840     return ret;
2841   }
2842
2843   if (offset)
2844     *offset = cur_offset;
2845
2846 beach:
2847   return ret;
2848 }
2849
2850 static gboolean
2851 gst_ogg_demux_deactivate_current_chain (GstOggDemux * ogg)
2852 {
2853   gint i;
2854   GstOggChain *chain = ogg->current_chain;
2855
2856   if (chain == NULL)
2857     return TRUE;
2858
2859   GST_DEBUG_OBJECT (ogg, "deactivating chain %p", chain);
2860
2861   /* send EOS on all the pads */
2862   for (i = 0; i < chain->streams->len; i++) {
2863     GstOggPad *pad = g_array_index (chain->streams, GstOggPad *, i);
2864     GstEvent *event;
2865
2866     if (!pad->added)
2867       continue;
2868
2869     event = gst_event_new_eos ();
2870     gst_event_set_seqnum (event, ogg->seqnum);
2871     gst_pad_push_event (GST_PAD_CAST (pad), event);
2872
2873     GST_DEBUG_OBJECT (ogg, "removing pad %" GST_PTR_FORMAT, pad);
2874
2875     /* deactivate first */
2876     gst_pad_set_active (GST_PAD_CAST (pad), FALSE);
2877
2878     gst_flow_combiner_remove_pad (ogg->flowcombiner, GST_PAD_CAST (pad));
2879
2880     gst_element_remove_pad (GST_ELEMENT (ogg), GST_PAD_CAST (pad));
2881
2882     pad->added = FALSE;
2883   }
2884
2885   /* if we cannot seek back to the chain, we can destroy the chain 
2886    * completely */
2887   if (!ogg->pullmode) {
2888     if (ogg->building_chain == chain)
2889       ogg->building_chain = NULL;
2890     ogg->current_chain = NULL;
2891     gst_ogg_chain_free (chain);
2892   }
2893
2894   return TRUE;
2895 }
2896
2897 static GstCaps *
2898 gst_ogg_demux_set_header_on_caps (GstOggDemux * ogg, GstCaps * caps,
2899     GList * headers)
2900 {
2901   GstStructure *structure;
2902   GValue array = { 0 };
2903
2904   GST_LOG_OBJECT (ogg, "caps: %" GST_PTR_FORMAT, caps);
2905
2906   if (G_UNLIKELY (!caps))
2907     return NULL;
2908   if (G_UNLIKELY (!headers))
2909     return caps;
2910
2911   caps = gst_caps_make_writable (caps);
2912   structure = gst_caps_get_structure (caps, 0);
2913
2914   g_value_init (&array, GST_TYPE_ARRAY);
2915
2916   while (headers) {
2917     GValue value = { 0 };
2918     GstBuffer *buffer;
2919     ogg_packet *op = headers->data;
2920     g_assert (op);
2921     buffer = gst_buffer_new_and_alloc (op->bytes);
2922     if (op->bytes)
2923       gst_buffer_fill (buffer, 0, op->packet, op->bytes);
2924     GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_HEADER);
2925     g_value_init (&value, GST_TYPE_BUFFER);
2926     gst_value_take_buffer (&value, buffer);
2927     gst_value_array_append_value (&array, &value);
2928     g_value_unset (&value);
2929     headers = headers->next;
2930   }
2931
2932   gst_structure_take_value (structure, "streamheader", &array);
2933   GST_LOG_OBJECT (ogg, "here are the newly set caps: %" GST_PTR_FORMAT, caps);
2934
2935   return caps;
2936 }
2937
2938 static void
2939 gst_ogg_demux_push_queued_buffers (GstOggDemux * ogg, GstOggPad * pad)
2940 {
2941   GList *walk;
2942
2943   /* push queued packets */
2944   for (walk = pad->map.queued; walk; walk = g_list_next (walk)) {
2945     ogg_packet *p = walk->data;
2946
2947     gst_ogg_demux_chain_peer (pad, p, TRUE);
2948     _ogg_packet_free (p);
2949   }
2950   /* and free the queued buffers */
2951   g_list_free (pad->map.queued);
2952   pad->map.queued = NULL;
2953 }
2954
2955 static gboolean
2956 gst_ogg_demux_activate_chain (GstOggDemux * ogg, GstOggChain * chain,
2957     GstEvent * event)
2958 {
2959   gint i;
2960   gint bitrate, idx_bitrate;
2961
2962   g_return_val_if_fail (chain != NULL, FALSE);
2963
2964   if (chain == ogg->current_chain) {
2965     if (event)
2966       gst_event_unref (event);
2967
2968     for (i = 0; i < chain->streams->len; i++) {
2969       GstOggPad *pad = g_array_index (chain->streams, GstOggPad *, i);
2970       gst_ogg_demux_push_queued_buffers (ogg, pad);
2971     }
2972     return TRUE;
2973   }
2974
2975
2976   GST_DEBUG_OBJECT (ogg, "activating chain %p", chain);
2977
2978   bitrate = idx_bitrate = 0;
2979
2980   /* first add the pads */
2981   for (i = 0; i < chain->streams->len; i++) {
2982     GstOggPad *pad;
2983     GstEvent *ss_event;
2984     gchar *stream_id;
2985
2986     pad = g_array_index (chain->streams, GstOggPad *, i);
2987
2988     if (pad->map.idx_bitrate)
2989       idx_bitrate = MAX (idx_bitrate, pad->map.idx_bitrate);
2990
2991     bitrate += pad->map.bitrate;
2992
2993     /* mark discont */
2994     gst_ogg_pad_mark_discont (pad);
2995     pad->last_ret = GST_FLOW_OK;
2996
2997     if (pad->map.is_skeleton || pad->map.is_cmml || pad->added
2998         || !pad->map.caps)
2999       continue;
3000
3001     GST_DEBUG_OBJECT (ogg, "adding pad %" GST_PTR_FORMAT, pad);
3002
3003     /* activate first */
3004     gst_pad_set_active (GST_PAD_CAST (pad), TRUE);
3005
3006     stream_id =
3007         gst_pad_create_stream_id_printf (GST_PAD (pad), GST_ELEMENT_CAST (ogg),
3008         "%08x", pad->map.serialno);
3009     ss_event =
3010         gst_pad_get_sticky_event (ogg->sinkpad, GST_EVENT_STREAM_START, 0);
3011     if (ss_event) {
3012       if (gst_event_parse_group_id (ss_event, &ogg->group_id))
3013         ogg->have_group_id = TRUE;
3014       else
3015         ogg->have_group_id = FALSE;
3016       gst_event_unref (ss_event);
3017     } else if (!ogg->have_group_id) {
3018       ogg->have_group_id = TRUE;
3019       ogg->group_id = gst_util_group_id_next ();
3020     }
3021     ss_event = gst_event_new_stream_start (stream_id);
3022     if (ogg->have_group_id)
3023       gst_event_set_group_id (ss_event, ogg->group_id);
3024
3025     gst_pad_push_event (GST_PAD (pad), ss_event);
3026     g_free (stream_id);
3027
3028     /* Set headers on caps */
3029     pad->map.caps =
3030         gst_ogg_demux_set_header_on_caps (ogg, pad->map.caps, pad->map.headers);
3031     gst_pad_set_caps (GST_PAD_CAST (pad), pad->map.caps);
3032
3033     gst_element_add_pad (GST_ELEMENT (ogg), GST_PAD_CAST (pad));
3034     pad->added = TRUE;
3035     gst_flow_combiner_add_pad (ogg->flowcombiner, GST_PAD_CAST (pad));
3036   }
3037   /* prefer the index bitrate over the ones encoded in the streams */
3038   ogg->bitrate = (idx_bitrate ? idx_bitrate : bitrate);
3039
3040   /* after adding the new pads, remove the old pads */
3041   gst_ogg_demux_deactivate_current_chain (ogg);
3042
3043   GST_DEBUG_OBJECT (ogg, "Setting current chain to %p", chain);
3044   ogg->current_chain = chain;
3045
3046   /* we are finished now */
3047   gst_element_no_more_pads (GST_ELEMENT (ogg));
3048
3049   GST_DEBUG_OBJECT (ogg, "starting chain");
3050
3051   /* then send out any headers and queued packets */
3052   for (i = 0; i < chain->streams->len; i++) {
3053     GList *walk;
3054     GstOggPad *pad;
3055     GstTagList *tags;
3056
3057     pad = g_array_index (chain->streams, GstOggPad *, i);
3058
3059     /* Skip pads that were not added, e.g. Skeleton streams */
3060     if (!pad->added)
3061       continue;
3062
3063     /* FIXME, must be sent from the streaming thread */
3064     if (event)
3065       gst_pad_push_event (GST_PAD_CAST (pad), gst_event_ref (event));
3066
3067     /* FIXME also streaming thread */
3068     if (pad->map.taglist) {
3069       GST_DEBUG_OBJECT (ogg, "pushing tags");
3070       gst_pad_push_event (GST_PAD_CAST (pad),
3071           gst_event_new_tag (pad->map.taglist));
3072       pad->map.taglist = NULL;
3073     }
3074
3075     tags = gst_tag_list_new (GST_TAG_CONTAINER_FORMAT, "Ogg", NULL);
3076     gst_tag_list_set_scope (tags, GST_TAG_SCOPE_GLOBAL);
3077     gst_pad_push_event (GST_PAD (pad), gst_event_new_tag (tags));
3078
3079     GST_DEBUG_OBJECT (ogg, "pushing headers");
3080     /* push headers */
3081     for (walk = pad->map.headers; walk; walk = g_list_next (walk)) {
3082       ogg_packet *p = walk->data;
3083
3084       gst_ogg_demux_chain_peer (pad, p, TRUE);
3085     }
3086
3087     GST_DEBUG_OBJECT (ogg, "pushing queued buffers");
3088     gst_ogg_demux_push_queued_buffers (ogg, pad);
3089   }
3090
3091   if (event)
3092     gst_event_unref (event);
3093
3094   return TRUE;
3095 }
3096
3097 static gboolean
3098 do_binary_search (GstOggDemux * ogg, GstOggChain * chain, gint64 begin,
3099     gint64 end, gint64 begintime, gint64 endtime, gint64 target,
3100     gint64 * offset, gboolean only_serial_no, gint serialno)
3101 {
3102   gint64 best;
3103   GstFlowReturn ret;
3104   gint64 result = 0;
3105
3106   best = begin;
3107
3108   GST_DEBUG_OBJECT (ogg,
3109       "chain offset %" G_GINT64_FORMAT ", end offset %" G_GINT64_FORMAT,
3110       begin, end);
3111   GST_DEBUG_OBJECT (ogg,
3112       "chain begin time %" GST_TIME_FORMAT ", end time %" GST_TIME_FORMAT,
3113       GST_TIME_ARGS (begintime), GST_TIME_ARGS (endtime));
3114   GST_DEBUG_OBJECT (ogg, "target %" GST_TIME_FORMAT, GST_TIME_ARGS (target));
3115
3116   /* perform the seek */
3117   while (begin < end) {
3118     gint64 bisect;
3119
3120     if ((end - begin < ogg->chunk_size) || (endtime == begintime)) {
3121       bisect = begin;
3122     } else {
3123       /* take a (pretty decent) guess, avoiding overflow */
3124       gint64 rate = (end - begin) * GST_MSECOND / (endtime - begintime);
3125
3126       bisect =
3127           (target - begintime) / GST_MSECOND * rate + begin - ogg->chunk_size;
3128
3129       if (bisect <= begin)
3130         bisect = begin;
3131       GST_DEBUG_OBJECT (ogg, "Initial guess: %" G_GINT64_FORMAT, bisect);
3132     }
3133     gst_ogg_demux_seek (ogg, bisect);
3134
3135     while (begin < end) {
3136       ogg_page og;
3137
3138       GST_DEBUG_OBJECT (ogg,
3139           "after seek, bisect %" G_GINT64_FORMAT ", begin %" G_GINT64_FORMAT
3140           ", end %" G_GINT64_FORMAT, bisect, begin, end);
3141
3142       ret = gst_ogg_demux_get_next_page (ogg, &og, end - ogg->offset, &result);
3143       GST_LOG_OBJECT (ogg, "looking for next page returned %" G_GINT64_FORMAT,
3144           result);
3145
3146       if (ret == GST_FLOW_LIMIT) {
3147         /* we hit the upper limit, go back a bit */
3148         if (bisect <= begin + 1) {
3149           end = begin;          /* found it */
3150         } else {
3151           if (bisect == 0)
3152             goto seek_error;
3153
3154           bisect -= ogg->chunk_size;
3155           if (bisect <= begin)
3156             bisect = begin + 1;
3157
3158           gst_ogg_demux_seek (ogg, bisect);
3159         }
3160       } else if (ret == GST_FLOW_OK) {
3161         /* found offset of next ogg page */
3162         gint64 granulepos;
3163         GstClockTime granuletime;
3164         GstOggPad *pad;
3165
3166         /* get the granulepos */
3167         GST_LOG_OBJECT (ogg, "found next ogg page at %" G_GINT64_FORMAT,
3168             result);
3169         granulepos = ogg_page_granulepos (&og);
3170         if (granulepos == -1) {
3171           GST_LOG_OBJECT (ogg, "granulepos of next page is -1");
3172           continue;
3173         }
3174
3175         /* Avoid seeking to an incorrect granuletime by only considering 
3176            the stream for which we found the earliest time */
3177         if (only_serial_no && ogg_page_serialno (&og) != serialno)
3178           continue;
3179
3180         /* get the stream */
3181         pad = gst_ogg_chain_get_stream (chain, ogg_page_serialno (&og));
3182         if (pad == NULL || pad->map.is_skeleton)
3183           continue;
3184
3185         /* convert granulepos to time */
3186         granuletime = gst_ogg_stream_get_end_time_for_granulepos (&pad->map,
3187             granulepos);
3188         if (granuletime < pad->start_time)
3189           continue;
3190
3191         GST_LOG_OBJECT (ogg, "granulepos %" G_GINT64_FORMAT " maps to PTS %"
3192             GST_TIME_FORMAT, granulepos, GST_TIME_ARGS (granuletime));
3193
3194         granuletime -= pad->start_time;
3195         granuletime += chain->begin_time;
3196
3197         GST_DEBUG_OBJECT (ogg,
3198             "found page with granule %" G_GINT64_FORMAT " and time %"
3199             GST_TIME_FORMAT, granulepos, GST_TIME_ARGS (granuletime));
3200
3201         if (granuletime < target) {
3202           best = result;        /* raw offset of packet with granulepos */
3203           begin = ogg->offset;  /* raw offset of next page */
3204           begintime = granuletime;
3205
3206           bisect = begin;       /* *not* begin + 1 */
3207         } else {
3208           if (bisect <= begin + 1) {
3209             end = begin;        /* found it */
3210           } else {
3211             if (end == ogg->offset) {   /* we're pretty close - we'd be stuck in */
3212               end = result;
3213               bisect -= ogg->chunk_size;        /* an endless loop otherwise. */
3214               if (bisect <= begin)
3215                 bisect = begin + 1;
3216               gst_ogg_demux_seek (ogg, bisect);
3217             } else {
3218               end = result;
3219               endtime = granuletime;
3220               break;
3221             }
3222           }
3223         }
3224       } else
3225         goto seek_error;
3226     }
3227   }
3228   GST_DEBUG_OBJECT (ogg, "seeking to %" G_GINT64_FORMAT, best);
3229   gst_ogg_demux_seek (ogg, best);
3230   *offset = best;
3231
3232   return TRUE;
3233
3234   /* ERRORS */
3235 seek_error:
3236   {
3237     GST_DEBUG_OBJECT (ogg, "got a seek error");
3238     return FALSE;
3239   }
3240 }
3241
3242 static gboolean
3243 do_index_search (GstOggDemux * ogg, GstOggChain * chain, gint64 begin,
3244     gint64 end, gint64 begintime, gint64 endtime, gint64 target,
3245     gint64 * p_offset, gint64 * p_timestamp)
3246 {
3247   guint i;
3248   guint64 timestamp, offset;
3249   guint64 r_timestamp, r_offset;
3250   gboolean result = FALSE;
3251
3252   target -= begintime;
3253
3254   r_offset = -1;
3255   r_timestamp = -1;
3256
3257   for (i = 0; i < chain->streams->len; i++) {
3258     GstOggPad *pad = g_array_index (chain->streams, GstOggPad *, i);
3259
3260     timestamp = target;
3261     if (gst_ogg_map_search_index (&pad->map, TRUE, &timestamp, &offset)) {
3262       GST_INFO ("found %" G_GUINT64_FORMAT " at offset %" G_GUINT64_FORMAT,
3263           timestamp, offset);
3264
3265       if (r_offset == -1 || offset < r_offset) {
3266         r_offset = offset;
3267         r_timestamp = timestamp;
3268       }
3269       result |= TRUE;
3270     }
3271   }
3272
3273   if (p_timestamp)
3274     *p_timestamp = r_timestamp;
3275   if (p_offset)
3276     *p_offset = r_offset;
3277
3278   return result;
3279 }
3280
3281 /*
3282  * do seek to time @position, return FALSE or chain and TRUE
3283  */
3284 static gboolean
3285 gst_ogg_demux_do_seek (GstOggDemux * ogg, GstSegment * segment,
3286     gboolean accurate, gboolean keyframe, GstOggChain ** rchain)
3287 {
3288   guint64 position;
3289   GstOggChain *chain = NULL;
3290   gint64 begin, end;
3291   gint64 begintime, endtime;
3292   gint64 target, keytarget;
3293   gint64 best;
3294   gint64 total;
3295   gint64 result = 0;
3296   GstFlowReturn ret;
3297   gint i, pending;
3298   gint serialno = 0;
3299   gboolean found_keyframe = FALSE;
3300   GstClockTime ts, first_ts = GST_CLOCK_TIME_NONE;
3301
3302   position = segment->position;
3303
3304   /* first find the chain to search in */
3305   total = ogg->total_time;
3306   if (ogg->chains->len == 0)
3307     goto no_chains;
3308
3309   for (i = ogg->chains->len - 1; i >= 0; i--) {
3310     chain = g_array_index (ogg->chains, GstOggChain *, i);
3311     total -= chain->total_time;
3312     if (position >= total)
3313       break;
3314   }
3315
3316   /* first step, locate page containing the required data */
3317   begin = chain->offset;
3318   end = chain->end_offset;
3319   begintime = chain->begin_time;
3320   endtime = begintime + chain->total_time;
3321   target = position - total + begintime;
3322
3323   if (!do_binary_search (ogg, chain, begin, end, begintime, endtime, target,
3324           &best, FALSE, 0))
3325     goto seek_error;
3326
3327   /* second step: find pages for all relevant streams. We use the
3328    * keyframe_granule to keep track of which ones we saw. If we have
3329    * seen a page for each stream we can calculate the positions of
3330    * each keyframe.
3331    * Relevant streams are defined as those streams which are not
3332    * Skeleton (which only has header pages). Discontinuous streams
3333    * such as Kate and CMML are currently excluded, as they could
3334    * cause performance issues if there are few pages in the area.
3335    * TODO: We might want to include them on a flag, if we want to
3336    * not miss a subtitle (Kate has repeat packets for this purpose,
3337    * but a stream does not have to use them). */
3338   pending = chain->streams->len;
3339   for (i = 0; i < chain->streams->len; i++) {
3340     GstOggPad *pad = g_array_index (chain->streams, GstOggPad *, i);
3341     if (!pad) {
3342       GST_WARNING_OBJECT (ogg, "No pad at index %d", i);
3343       pending--;
3344       continue;
3345     }
3346     if (pad->map.is_skeleton) {
3347       GST_DEBUG_OBJECT (ogg, "Not finding pages for Skeleton stream %08x",
3348           pad->map.serialno);
3349       pending--;
3350       continue;
3351     }
3352     if (pad->map.is_sparse) {
3353       GST_DEBUG_OBJECT (ogg, "Not finding pages for sparse stream %08x (%s)",
3354           pad->map.serialno, gst_ogg_stream_get_media_type (&pad->map));
3355       pending--;
3356       continue;
3357     }
3358   }
3359   GST_DEBUG_OBJECT (ogg, "find keyframes for %d/%d streams", pending,
3360       chain->streams->len);
3361
3362   /* figure out where the keyframes are */
3363   keytarget = target;
3364
3365   while (TRUE) {
3366     ogg_page og;
3367     gint64 granulepos;
3368     GstOggPad *pad;
3369     GstClockTime keyframe_time, granule_time;
3370
3371     ret = gst_ogg_demux_get_next_page (ogg, &og, end - ogg->offset, &result);
3372     GST_LOG_OBJECT (ogg, "looking for next page returned %" G_GINT64_FORMAT,
3373         result);
3374     if (ret == GST_FLOW_LIMIT) {
3375       GST_LOG_OBJECT (ogg, "reached limit");
3376       break;
3377     } else if (ret != GST_FLOW_OK)
3378       goto seek_error;
3379
3380     /* get the stream */
3381     pad = gst_ogg_chain_get_stream (chain, ogg_page_serialno (&og));
3382     if (pad == NULL)
3383       continue;
3384
3385     if (pad->map.is_skeleton || pad->map.is_sparse)
3386       goto next;
3387
3388     granulepos = ogg_page_granulepos (&og);
3389     if (granulepos == -1 || granulepos == 0) {
3390       GST_LOG_OBJECT (ogg, "granulepos of next page is -1");
3391       continue;
3392     }
3393
3394     /* We have a valid granpos, and we bail out when the time since the
3395        first seen time to the time corresponding to this granpos is larger
3396        then a threshold, to guard against some streams having large holes
3397        (eg, a stream ending early, which would cause seeking after that
3398        to fill up a queue for streams still active). */
3399     ts = gst_ogg_stream_get_end_time_for_granulepos (&pad->map, granulepos);
3400     if (GST_CLOCK_TIME_IS_VALID (ts)) {
3401       if (first_ts == GST_CLOCK_TIME_NONE) {
3402         GST_WARNING_OBJECT (pad, "Locking on pts %" GST_TIME_FORMAT,
3403             GST_TIME_ARGS (ts));
3404         first_ts = ts;
3405       }
3406       if (ts - first_ts > SEEK_GIVE_UP_THRESHOLD) {
3407         GST_WARNING_OBJECT (pad,
3408             "No data found for %" GST_TIME_FORMAT ", giving up",
3409             GST_TIME_ARGS (SEEK_GIVE_UP_THRESHOLD));
3410         found_keyframe = FALSE;
3411         keytarget = target;
3412         break;
3413       }
3414     }
3415
3416     /* in reverse we want to go past the page with the lower timestamp */
3417     if (segment->rate < 0.0) {
3418       /* get time for this pad */
3419       granule_time = gst_ogg_stream_get_end_time_for_granulepos (&pad->map,
3420           granulepos);
3421
3422       /* Convert to stream time */
3423       granule_time -= pad->start_time;
3424       granule_time += chain->begin_time;
3425
3426       GST_LOG_OBJECT (ogg,
3427           "looking at page with time %" GST_TIME_FORMAT ", target %"
3428           GST_TIME_FORMAT, GST_TIME_ARGS (granule_time),
3429           GST_TIME_ARGS (target));
3430       if (granule_time < target)
3431         continue;
3432     }
3433
3434     /* we've seen this pad before */
3435     if (pad->keyframe_granule != -1)
3436       continue;
3437
3438     /* convert granule of this pad to the granule of the keyframe */
3439     pad->keyframe_granule =
3440         gst_ogg_stream_granulepos_to_key_granule (&pad->map, granulepos);
3441     GST_LOG_OBJECT (ogg, "marking stream granule %" G_GINT64_FORMAT,
3442         pad->keyframe_granule);
3443
3444     /* get time of the keyframe */
3445     keyframe_time =
3446         gst_ogg_stream_granule_to_time (&pad->map, pad->keyframe_granule);
3447     GST_LOG_OBJECT (ogg,
3448         "stream %08x keyframe granule PTS %" GST_TIME_FORMAT
3449         " target %" GST_TIME_FORMAT,
3450         pad->map.serialno, GST_TIME_ARGS (keyframe_time),
3451         GST_TIME_ARGS (keytarget));
3452
3453     /* collect smallest value */
3454     if (keyframe_time != -1) {
3455       keyframe_time -= pad->start_time;
3456       keyframe_time += begintime;
3457       if (keyframe_time < keytarget) {
3458         serialno = pad->map.serialno;
3459         keytarget = keyframe_time;
3460         found_keyframe = TRUE;
3461         GST_LOG_OBJECT (ogg, "storing keytarget %" GST_TIME_FORMAT,
3462             GST_TIME_ARGS (keytarget));
3463       }
3464     }
3465
3466   next:
3467     pending--;
3468     if (pending == 0)
3469       break;
3470   }
3471
3472   /* for negative rates we will get to the keyframe backwards */
3473   if (segment->rate < 0.0)
3474     goto done;
3475
3476   /* No keyframe found, no need to bisect again, keytarget == target here */
3477   if (!found_keyframe)
3478     best = 0;
3479
3480   if (keytarget != target) {
3481     GST_LOG_OBJECT (ogg, "final seek to target %" GST_TIME_FORMAT,
3482         GST_TIME_ARGS (keytarget));
3483
3484     /* last step, seek to the location of the keyframe */
3485     if (!do_binary_search (ogg, chain, begin, end, begintime, endtime,
3486             keytarget, &best, TRUE, serialno))
3487       goto seek_error;
3488   } else {
3489     /* seek back to previous position */
3490     GST_LOG_OBJECT (ogg, "keyframe on target");
3491     gst_ogg_demux_seek (ogg, best);
3492   }
3493
3494 done:
3495   if (keyframe) {
3496     if (segment->rate > 0.0)
3497       segment->time = keytarget;
3498     segment->position = keytarget - begintime;
3499   }
3500
3501   *rchain = chain;
3502
3503   return TRUE;
3504
3505 no_chains:
3506   {
3507     GST_DEBUG_OBJECT (ogg, "no chains");
3508     return FALSE;
3509   }
3510 seek_error:
3511   {
3512     GST_DEBUG_OBJECT (ogg, "got a seek error");
3513     return FALSE;
3514   }
3515 }
3516
3517 /* does not take ownership of the event */
3518 static gboolean
3519 gst_ogg_demux_perform_seek_pull (GstOggDemux * ogg, GstEvent * event)
3520 {
3521   GstOggChain *chain = NULL;
3522   gboolean res;
3523   gboolean accurate, keyframe;
3524   GstFormat format;
3525   gdouble rate;
3526   GstSeekFlags flags;
3527   GstSeekType start_type, stop_type;
3528   gint64 start, stop;
3529   gboolean update;
3530   guint32 seqnum;
3531
3532   if (event) {
3533     GST_DEBUG_OBJECT (ogg, "seek with event");
3534
3535     gst_event_parse_seek (event, &rate, &format, &flags,
3536         &start_type, &start, &stop_type, &stop);
3537
3538     /* we can only seek on time */
3539     if (format != GST_FORMAT_TIME) {
3540       GST_DEBUG_OBJECT (ogg, "can only seek on TIME");
3541       goto error;
3542     }
3543     seqnum = gst_event_get_seqnum (event);
3544   } else {
3545     GST_DEBUG_OBJECT (ogg, "seek without event");
3546
3547     flags = 0;
3548     rate = 1.0;
3549     seqnum = gst_util_seqnum_next ();
3550   }
3551
3552   GST_DEBUG_OBJECT (ogg, "seek, rate %g", rate);
3553
3554   accurate = flags & GST_SEEK_FLAG_ACCURATE;
3555   keyframe = flags & GST_SEEK_FLAG_KEY_UNIT;
3556
3557   gst_pad_pause_task (ogg->sinkpad);
3558
3559   /* now grab the stream lock so that streaming cannot continue, for
3560    * non flushing seeks when the element is in PAUSED this could block
3561    * forever. */
3562   GST_PAD_STREAM_LOCK (ogg->sinkpad);
3563
3564   if (event) {
3565     gst_segment_do_seek (&ogg->segment, rate, format, flags,
3566         start_type, start, stop_type, stop, &update);
3567   }
3568
3569   GST_DEBUG_OBJECT (ogg, "segment positions set to %" GST_TIME_FORMAT "-%"
3570       GST_TIME_FORMAT, GST_TIME_ARGS (ogg->segment.start),
3571       GST_TIME_ARGS (ogg->segment.stop));
3572
3573   {
3574     gint i;
3575
3576     /* reset all ogg streams now, need to do this from within the lock to
3577      * make sure the streaming thread is not messing with the stream */
3578     for (i = 0; i < ogg->chains->len; i++) {
3579       GstOggChain *chain = g_array_index (ogg->chains, GstOggChain *, i);
3580
3581       gst_ogg_chain_reset (chain);
3582     }
3583   }
3584
3585   /* for reverse we will already seek accurately */
3586   res = gst_ogg_demux_do_seek (ogg, &ogg->segment, accurate, keyframe, &chain);
3587
3588   /* seek failed, make sure we continue the current chain */
3589   if (!res) {
3590     GST_DEBUG_OBJECT (ogg, "seek failed");
3591     chain = ogg->current_chain;
3592   } else {
3593     GST_DEBUG_OBJECT (ogg, "seek success");
3594   }
3595
3596   if (!chain)
3597     goto no_chain;
3598
3599   /* now we have a new position, prepare for streaming again */
3600   {
3601     GstEvent *event;
3602     gint64 stop;
3603     gint64 start;
3604     gint64 position, begin_time;
3605     GstSegment segment;
3606
3607     /* we need this to see how far inside the chain we need to start */
3608     if (chain->begin_time != GST_CLOCK_TIME_NONE)
3609       begin_time = chain->begin_time;
3610     else
3611       begin_time = 0;
3612
3613     /* segment.start gives the start over all chains, we calculate the amount
3614      * of time into this chain we need to start */
3615     start = ogg->segment.start - begin_time;
3616     if (chain->segment_start != GST_CLOCK_TIME_NONE)
3617       start += chain->segment_start;
3618
3619     if ((stop = ogg->segment.stop) == -1)
3620       stop = ogg->segment.duration;
3621
3622     /* segment.stop gives the stop time over all chains, calculate the amount of
3623      * time we need to stop in this chain */
3624     if (stop != -1) {
3625       if (stop > begin_time)
3626         stop -= begin_time;
3627       else
3628         stop = 0;
3629       stop += chain->segment_start;
3630       /* we must stop when this chain ends and switch to the next chain to play
3631        * the remainder of the segment. */
3632       stop = MIN (stop, chain->segment_stop);
3633     }
3634
3635     position = ogg->segment.position;
3636     if (chain->segment_start != GST_CLOCK_TIME_NONE)
3637       position += chain->segment_start;
3638
3639     gst_segment_copy_into (&ogg->segment, &segment);
3640
3641     /* create the segment event we are going to send out */
3642     if (ogg->segment.rate >= 0.0) {
3643       segment.start = position;
3644       segment.stop = stop;
3645     } else {
3646       segment.start = start;
3647       segment.stop = position;
3648     }
3649     event = gst_event_new_segment (&segment);
3650     gst_event_set_seqnum (event, seqnum);
3651
3652     if (chain != ogg->current_chain) {
3653       /* switch to different chain, send segment on new chain */
3654       gst_ogg_demux_activate_chain (ogg, chain, event);
3655     } else {
3656       /* mark discont and send segment on current chain */
3657       gst_ogg_chain_mark_discont (chain);
3658       /* This event should be sent from the streaming thread (sink pad task) */
3659       if (ogg->newsegment)
3660         gst_event_unref (ogg->newsegment);
3661       ogg->newsegment = event;
3662     }
3663
3664     /* notify start of new segment */
3665     if (ogg->segment.flags & GST_SEEK_FLAG_SEGMENT) {
3666       GstMessage *message;
3667
3668       message = gst_message_new_segment_start (GST_OBJECT (ogg),
3669           GST_FORMAT_TIME, ogg->segment.position);
3670       gst_message_set_seqnum (message, seqnum);
3671
3672       gst_element_post_message (GST_ELEMENT (ogg), message);
3673     }
3674
3675     ogg->seqnum = seqnum;
3676     /* restart our task since it might have been stopped when we did the 
3677      * flush. */
3678     gst_pad_start_task (ogg->sinkpad, (GstTaskFunction) gst_ogg_demux_loop,
3679         ogg->sinkpad, NULL);
3680   }
3681
3682   /* streaming can continue now */
3683   GST_PAD_STREAM_UNLOCK (ogg->sinkpad);
3684
3685 done:
3686   if (event)
3687     gst_event_unref (event);
3688   return res;
3689
3690   /* ERRORS */
3691 error:
3692   {
3693     GST_DEBUG_OBJECT (ogg, "seek failed");
3694     res = FALSE;
3695     goto done;
3696   }
3697 no_chain:
3698   {
3699     GST_DEBUG_OBJECT (ogg, "no chain to seek in");
3700     GST_PAD_STREAM_UNLOCK (ogg->sinkpad);
3701     res = FALSE;
3702     goto done;
3703   }
3704 }
3705
3706 static gboolean
3707 gst_ogg_demux_get_duration_push (GstOggDemux * ogg, int flags)
3708 {
3709   /* In push mode, we get to the end of the stream to get the duration */
3710   gint64 position;
3711   GstEvent *sevent;
3712
3713   /* A full Ogg page can be almost 64 KB. There's no guarantee that there'll be a
3714      granpos there, but it's fairly likely */
3715   position = ogg->push_byte_length - DURATION_CHUNK_OFFSET;
3716   if (position < 0)
3717     position = 0;
3718
3719   GST_DEBUG_OBJECT (ogg,
3720       "Getting duration, seeking near the end, to %" G_GINT64_FORMAT, position);
3721   ogg->push_state = PUSH_DURATION;
3722   /* do not read the last byte */
3723   sevent = gst_event_new_seek (1.0, GST_FORMAT_BYTES, flags, GST_SEEK_TYPE_SET,
3724       position, GST_SEEK_TYPE_SET, ogg->push_byte_length - 1);
3725   gst_event_replace (&ogg->seek_event, sevent);
3726   gst_event_unref (sevent);
3727   g_mutex_lock (&ogg->seek_event_mutex);
3728   g_cond_broadcast (&ogg->seek_event_cond);
3729   g_mutex_unlock (&ogg->seek_event_mutex);
3730   return TRUE;
3731 }
3732
3733 static gboolean
3734 gst_ogg_demux_check_duration_push (GstOggDemux * ogg, GstSeekFlags flags,
3735     GstEvent * event)
3736 {
3737   if (ogg->push_byte_length < 0) {
3738     GstPad *peer;
3739
3740     GST_DEBUG_OBJECT (ogg, "Trying to find byte/time length");
3741     if ((peer = gst_pad_get_peer (ogg->sinkpad)) != NULL) {
3742       gint64 length;
3743       int res;
3744
3745       res = gst_pad_query_duration (peer, GST_FORMAT_BYTES, &length);
3746       if (res && length > 0) {
3747         ogg->push_byte_length = length;
3748         GST_DEBUG_OBJECT (ogg,
3749             "File byte length %" G_GINT64_FORMAT, ogg->push_byte_length);
3750       } else {
3751         GST_DEBUG_OBJECT (ogg, "File byte length unknown, assuming live");
3752         ogg->push_disable_seeking = TRUE;
3753         gst_object_unref (peer);
3754         return TRUE;
3755       }
3756       res = gst_pad_query_duration (peer, GST_FORMAT_TIME, &length);
3757       gst_object_unref (peer);
3758       if (res && length >= 0) {
3759         ogg->push_time_length = length;
3760         GST_DEBUG_OBJECT (ogg, "File time length %" GST_TIME_FORMAT,
3761             GST_TIME_ARGS (ogg->push_time_length));
3762       } else if (!ogg->push_disable_seeking) {
3763         gboolean res;
3764
3765         res = gst_ogg_demux_get_duration_push (ogg, flags);
3766         if (res) {
3767           GST_DEBUG_OBJECT (ogg,
3768               "File time length unknown, trying to determine");
3769           ogg->push_mode_seek_delayed_event = NULL;
3770           if (event) {
3771             GST_DEBUG_OBJECT (ogg,
3772                 "Let me intercept this innocent looking seek request");
3773             ogg->push_mode_seek_delayed_event = gst_event_copy (event);
3774           }
3775           return FALSE;
3776         }
3777       }
3778     }
3779   }
3780   return TRUE;
3781 }
3782
3783 static gboolean
3784 gst_ogg_demux_perform_seek_push (GstOggDemux * ogg, GstEvent * event)
3785 {
3786   gint bitrate;
3787   gboolean res = TRUE;
3788   GstFormat format;
3789   gdouble rate;
3790   GstSeekFlags flags;
3791   GstSeekType start_type, stop_type;
3792   gint64 start, stop;
3793   GstEvent *sevent;
3794   GstOggChain *chain;
3795   gint64 best, best_time;
3796   gint i;
3797
3798   GST_DEBUG_OBJECT (ogg, "Push mode seek request received");
3799
3800   gst_event_parse_seek (event, &rate, &format, &flags,
3801       &start_type, &start, &stop_type, &stop);
3802
3803   if (format != GST_FORMAT_TIME) {
3804     GST_DEBUG_OBJECT (ogg, "can only seek on TIME");
3805     goto error;
3806   }
3807
3808   if (start_type != GST_SEEK_TYPE_SET) {
3809     GST_DEBUG_OBJECT (ogg, "can only seek to a SET target");
3810     goto error;
3811   }
3812
3813   /* If stop is unset, make sure it is -1, as this value will be tested
3814      later to check whether stop is set or not */
3815   if (stop_type == GST_SEEK_TYPE_NONE)
3816     stop = -1;
3817
3818   GST_DEBUG_OBJECT (ogg, "Push mode seek request: %" GST_TIME_FORMAT,
3819       GST_TIME_ARGS (start));
3820
3821   chain = ogg->current_chain;
3822   if (!chain) {
3823     GST_WARNING_OBJECT (ogg, "No chain to seek on");
3824     goto error;
3825   }
3826
3827   /* start accessing push_* members */
3828   GST_PUSH_LOCK (ogg);
3829
3830   /* not if we disabled seeking (chained streams) */
3831   if (ogg->push_disable_seeking) {
3832     GST_DEBUG_OBJECT (ogg, "Seeking disabled");
3833     goto error_locked;
3834   }
3835
3836   /* not when we're trying to work out duration */
3837   if (ogg->push_state == PUSH_DURATION) {
3838     GST_DEBUG_OBJECT (ogg, "Busy working out duration, try again later");
3839     goto error_locked;
3840   }
3841
3842   /* actually, not if we're doing any seeking already */
3843   if (ogg->push_state != PUSH_PLAYING) {
3844     GST_DEBUG_OBJECT (ogg, "Already doing some seeking, try again later");
3845     goto error_locked;
3846   }
3847
3848   /* on the first seek, get length if we can */
3849   if (!gst_ogg_demux_check_duration_push (ogg, flags, event)) {
3850     GST_PUSH_UNLOCK (ogg);
3851     return FALSE;
3852   }
3853
3854   if (do_index_search (ogg, chain, 0, -1, 0, -1, start, &best, &best_time)) {
3855     /* the index gave some result */
3856     GST_DEBUG_OBJECT (ogg,
3857         "found offset %" G_GINT64_FORMAT " with time %" G_GUINT64_FORMAT,
3858         best, best_time);
3859   } else {
3860     if (ogg->push_time_length > 0) {
3861       /* if we know the time length, we know the full segment bitrate */
3862       GST_DEBUG_OBJECT (ogg, "Using real file bitrate");
3863       bitrate =
3864           gst_util_uint64_scale (ogg->push_byte_length, 8 * GST_SECOND,
3865           ogg->push_time_length);
3866     } else if (ogg->push_time_offset > 0) {
3867       /* get a first approximation using known bitrate to the current position */
3868       GST_DEBUG_OBJECT (ogg, "Using file bitrate so far");
3869       bitrate =
3870           gst_util_uint64_scale (ogg->push_byte_offset, 8 * GST_SECOND,
3871           ogg->push_time_offset);
3872     } else if (ogg->bitrate > 0) {
3873       /* nominal bitrate is better than nothing, even if it lies often */
3874       GST_DEBUG_OBJECT (ogg, "Using nominal bitrate");
3875       bitrate = ogg->bitrate;
3876     } else {
3877       /* meh */
3878       GST_DEBUG_OBJECT (ogg,
3879           "At stream start, and no nominal bitrate, using some random magic "
3880           "number to seed");
3881       /* the bisection, once started, should give us a better approximation */
3882       bitrate = 1000;
3883     }
3884     best = gst_util_uint64_scale (start, bitrate, 8 * GST_SECOND);
3885   }
3886
3887   /* offset by typical page length, and ensure our best guess is within
3888      reasonable bounds */
3889   best -= ogg->chunk_size;
3890   if (best < 0)
3891     best = 0;
3892   if (ogg->push_byte_length > 0 && best >= ogg->push_byte_length)
3893     best = ogg->push_byte_length - 1;
3894
3895   /* set up bisection search */
3896   ogg->push_offset0 = 0;
3897   ogg->push_offset1 = ogg->push_byte_length - 1;
3898   ogg->push_time0 = ogg->push_start_time;
3899   ogg->push_time1 = ogg->push_time_length;
3900   ogg->seqnum = gst_event_get_seqnum (event);
3901   ogg->push_seek_time_target = start;
3902   ogg->push_prev_seek_time = GST_CLOCK_TIME_NONE;
3903   ogg->push_seek_time_original_target = start;
3904   ogg->push_seek_time_original_stop = stop;
3905   ogg->push_state = PUSH_BISECT1;
3906   ogg->seek_secant = FALSE;
3907   ogg->seek_undershot = FALSE;
3908
3909   if (flags & GST_SEEK_FLAG_FLUSH) {
3910     /* reset pad push mode seeking state */
3911     for (i = 0; i < chain->streams->len; i++) {
3912       GstOggPad *pad = g_array_index (chain->streams, GstOggPad *, i);
3913       pad->push_kf_time = GST_CLOCK_TIME_NONE;
3914       pad->push_sync_time = GST_CLOCK_TIME_NONE;
3915     }
3916   }
3917
3918   GST_DEBUG_OBJECT (ogg,
3919       "Setting up bisection search for %" G_GINT64_FORMAT " - %" G_GINT64_FORMAT
3920       " (time %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT ")", ogg->push_offset0,
3921       ogg->push_offset1, GST_TIME_ARGS (ogg->push_time0),
3922       GST_TIME_ARGS (ogg->push_time1));
3923   GST_DEBUG_OBJECT (ogg,
3924       "Target time is %" GST_TIME_FORMAT ", best first guess is %"
3925       G_GINT64_FORMAT, GST_TIME_ARGS (ogg->push_seek_time_target), best);
3926
3927   ogg->push_seek_rate = rate;
3928   ogg->push_seek_flags = flags;
3929   ogg->push_mode_seek_delayed_event = NULL;
3930   ogg->push_bisection_steps[0] = 1;
3931   ogg->push_bisection_steps[1] = 0;
3932   sevent = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags,
3933       start_type, best, GST_SEEK_TYPE_NONE, -1);
3934   gst_event_set_seqnum (sevent, gst_event_get_seqnum (event));
3935
3936   gst_event_replace (&ogg->seek_event, sevent);
3937   gst_event_unref (sevent);
3938   GST_PUSH_UNLOCK (ogg);
3939   g_mutex_lock (&ogg->seek_event_mutex);
3940   g_cond_broadcast (&ogg->seek_event_cond);
3941   g_mutex_unlock (&ogg->seek_event_mutex);
3942
3943   return res;
3944
3945   /* ERRORS */
3946 error:
3947   {
3948     GST_DEBUG_OBJECT (ogg, "seek failed");
3949     return FALSE;
3950   }
3951
3952 error_locked:
3953   GST_PUSH_UNLOCK (ogg);
3954   goto error;
3955 }
3956
3957 static gboolean
3958 gst_ogg_demux_setup_seek_pull (GstOggDemux * ogg, GstEvent * event)
3959 {
3960   gboolean flush;
3961   GstSeekFlags flags;
3962   GstEvent *tevent;
3963   guint32 seqnum = gst_event_get_seqnum (event);
3964
3965   GST_DEBUG_OBJECT (ogg, "Scheduling seek: %" GST_PTR_FORMAT, event);
3966   gst_event_parse_seek (event, NULL, NULL, &flags, NULL, NULL, NULL, NULL);
3967
3968   flush = flags & GST_SEEK_FLAG_FLUSH;
3969
3970   /* first step is to unlock the streaming thread if it is
3971    * blocked in a chain call, we do this by starting the flush. because
3972    * we cannot yet hold any streaming lock, we have to protect the chains
3973    * with their own lock. */
3974   if (flush) {
3975     gint i;
3976
3977     tevent = gst_event_new_flush_start ();
3978     gst_event_set_seqnum (tevent, seqnum);
3979
3980     gst_event_ref (tevent);
3981     gst_pad_push_event (ogg->sinkpad, tevent);
3982
3983     GST_CHAIN_LOCK (ogg);
3984     for (i = 0; i < ogg->chains->len; i++) {
3985       GstOggChain *chain = g_array_index (ogg->chains, GstOggChain *, i);
3986       gint j;
3987
3988       for (j = 0; j < chain->streams->len; j++) {
3989         GstOggPad *pad = g_array_index (chain->streams, GstOggPad *, j);
3990
3991         gst_event_ref (tevent);
3992         gst_pad_push_event (GST_PAD (pad), tevent);
3993       }
3994     }
3995     GST_CHAIN_UNLOCK (ogg);
3996
3997     gst_event_unref (tevent);
3998   }
3999
4000   gst_pad_pause_task (ogg->sinkpad);
4001
4002   /* now grab the stream lock so that streaming cannot continue, for
4003    * non flushing seeks when the element is in PAUSED this could block
4004    * forever. */
4005   GST_PAD_STREAM_LOCK (ogg->sinkpad);
4006
4007   /* we need to stop flushing on the sinkpad as we're going to use it
4008    * next. We can do this as we have the STREAM lock now. */
4009   if (flush) {
4010     tevent = gst_event_new_flush_stop (TRUE);
4011     gst_event_set_seqnum (tevent, seqnum);
4012     gst_pad_push_event (ogg->sinkpad, gst_event_ref (tevent));
4013     gst_ogg_demux_send_event (ogg, tevent);
4014   }
4015
4016   gst_event_replace (&ogg->seek_event, event);
4017   gst_pad_start_task (ogg->sinkpad, (GstTaskFunction) gst_ogg_demux_loop,
4018       ogg->sinkpad, NULL);
4019   GST_PAD_STREAM_UNLOCK (ogg->sinkpad);
4020
4021   return TRUE;
4022 }
4023
4024 static gboolean
4025 gst_ogg_demux_perform_seek (GstOggDemux * ogg, GstEvent * event)
4026 {
4027   gboolean res;
4028
4029   if (ogg->pullmode) {
4030     res = gst_ogg_demux_setup_seek_pull (ogg, event);
4031   } else {
4032     res = gst_ogg_demux_perform_seek_push (ogg, event);
4033   }
4034   return res;
4035 }
4036
4037
4038 /* finds each bitstream link one at a time using a bisection search
4039  * (has to begin by knowing the offset of the lb's initial page).
4040  * Recurses for each link so it can alloc the link storage after
4041  * finding them all, then unroll and fill the cache at the same time
4042  */
4043 static GstFlowReturn
4044 gst_ogg_demux_bisect_forward_serialno (GstOggDemux * ogg,
4045     gint64 begin, gint64 searched, gint64 end, GstOggChain * chain, glong m)
4046 {
4047   gint64 endsearched = end;
4048   gint64 next = end;
4049   ogg_page og;
4050   GstFlowReturn ret;
4051   gint64 offset;
4052   GstOggChain *nextchain;
4053
4054   GST_LOG_OBJECT (ogg,
4055       "bisect begin: %" G_GINT64_FORMAT ", searched: %" G_GINT64_FORMAT
4056       ", end %" G_GINT64_FORMAT ", chain: %p", begin, searched, end, chain);
4057
4058   /* the below guards against garbage separating the last and
4059    * first pages of two links. */
4060   while (searched < endsearched) {
4061     gint64 bisect;
4062
4063     if (endsearched - searched < ogg->chunk_size) {
4064       bisect = searched;
4065     } else {
4066       bisect = (searched + endsearched) / 2;
4067     }
4068
4069     gst_ogg_demux_seek (ogg, bisect);
4070     ret = gst_ogg_demux_get_next_page (ogg, &og, -1, &offset);
4071
4072     if (ret == GST_FLOW_EOS) {
4073       endsearched = bisect;
4074     } else if (ret == GST_FLOW_OK) {
4075       guint32 serial = ogg_page_serialno (&og);
4076
4077       if (!gst_ogg_chain_has_stream (chain, serial)) {
4078         endsearched = bisect;
4079         next = offset;
4080       } else {
4081         searched = offset + og.header_len + og.body_len;
4082       }
4083     } else
4084       return ret;
4085   }
4086
4087   GST_LOG_OBJECT (ogg, "current chain ends at %" G_GINT64_FORMAT, searched);
4088
4089   chain->end_offset = searched;
4090   ret = gst_ogg_demux_read_end_chain (ogg, chain);
4091   if (ret != GST_FLOW_OK)
4092     return ret;
4093
4094   GST_LOG_OBJECT (ogg, "found begin at %" G_GINT64_FORMAT, next);
4095
4096   gst_ogg_demux_seek (ogg, next);
4097   ret = gst_ogg_demux_read_chain (ogg, &nextchain);
4098   if (ret == GST_FLOW_EOS) {
4099     nextchain = NULL;
4100     ret = GST_FLOW_OK;
4101     GST_LOG_OBJECT (ogg, "no next chain");
4102   } else if (ret != GST_FLOW_OK)
4103     goto done;
4104
4105   if (searched < end && nextchain != NULL) {
4106     ret = gst_ogg_demux_bisect_forward_serialno (ogg, next, ogg->offset,
4107         end, nextchain, m + 1);
4108     if (ret != GST_FLOW_OK)
4109       goto done;
4110   }
4111   GST_LOG_OBJECT (ogg, "adding chain %p", chain);
4112
4113   g_array_insert_val (ogg->chains, 0, chain);
4114
4115 done:
4116   return ret;
4117 }
4118
4119 /* read a chain from the ogg file. This code will
4120  * read all BOS pages and will create and return a GstOggChain 
4121  * structure with the results. 
4122  * 
4123  * This function will also read N pages from each stream in the
4124  * chain and submit them to the internal ogg stream parser/mapper
4125  * until we know the timestamp of the first page in the chain.
4126  */
4127 static GstFlowReturn
4128 gst_ogg_demux_read_chain (GstOggDemux * ogg, GstOggChain ** res_chain)
4129 {
4130   GstFlowReturn ret;
4131   GstOggChain *chain = NULL;
4132   gint64 offset = ogg->offset;
4133   ogg_page og;
4134   gboolean done;
4135   gint i;
4136
4137   GST_LOG_OBJECT (ogg, "reading chain at %" G_GINT64_FORMAT, offset);
4138
4139   /* first read the BOS pages, detect the stream types, create the internal
4140    * stream mappers, send data to them. */
4141   while (TRUE) {
4142     GstOggPad *pad;
4143     guint32 serial;
4144
4145     ret = gst_ogg_demux_get_next_page (ogg, &og, -1, NULL);
4146     if (ret != GST_FLOW_OK) {
4147       if (ret == GST_FLOW_EOS) {
4148         GST_DEBUG_OBJECT (ogg, "Reached EOS, done reading end chain");
4149       } else {
4150         GST_WARNING_OBJECT (ogg, "problem reading BOS page: ret=%d", ret);
4151       }
4152       break;
4153     }
4154     if (!ogg_page_bos (&og)) {
4155       GST_INFO_OBJECT (ogg, "page is not BOS page, all streams identified");
4156       /* if we did not find a chain yet, assume this is a bogus stream and
4157        * ignore it */
4158       if (!chain) {
4159         GST_WARNING_OBJECT (ogg, "No chain found, no Ogg data in stream ?");
4160         ret = GST_FLOW_EOS;
4161       }
4162       break;
4163     }
4164
4165     if (chain == NULL) {
4166       chain = gst_ogg_chain_new (ogg);
4167       chain->offset = offset;
4168     }
4169
4170     serial = ogg_page_serialno (&og);
4171     if (gst_ogg_chain_get_stream (chain, serial) != NULL) {
4172       GST_WARNING_OBJECT (ogg,
4173           "found serial %08x BOS page twice, ignoring", serial);
4174       continue;
4175     }
4176
4177     pad = gst_ogg_chain_new_stream (chain, serial);
4178     gst_ogg_pad_submit_page (pad, &og);
4179   }
4180
4181   if (ret != GST_FLOW_OK || chain == NULL) {
4182     if (ret == GST_FLOW_OK) {
4183       GST_WARNING_OBJECT (ogg, "no chain was found");
4184       ret = GST_FLOW_ERROR;
4185     } else if (ret != GST_FLOW_EOS) {
4186       GST_WARNING_OBJECT (ogg, "failed to read chain");
4187     } else {
4188       GST_DEBUG_OBJECT (ogg, "done reading chains");
4189     }
4190     if (chain) {
4191       gst_ogg_chain_free (chain);
4192     }
4193     if (res_chain)
4194       *res_chain = NULL;
4195     return ret;
4196   }
4197
4198   chain->have_bos = TRUE;
4199   GST_INFO_OBJECT (ogg, "read bos pages, ");
4200
4201   /* now read pages until each ogg stream mapper has figured out the
4202    * timestamp of the first packet in the chain */
4203
4204   /* save the offset to the first non bos page in the chain: if searching for
4205    * pad->first_time we read past the end of the chain, we'll seek back to this
4206    * position
4207    */
4208   offset = ogg->offset;
4209
4210   done = FALSE;
4211   while (!done) {
4212     guint32 serial;
4213     gboolean known_serial = FALSE;
4214     GstFlowReturn ret;
4215
4216     serial = ogg_page_serialno (&og);
4217     done = TRUE;
4218     for (i = 0; i < chain->streams->len; i++) {
4219       GstOggPad *pad = g_array_index (chain->streams, GstOggPad *, i);
4220
4221       GST_LOG_OBJECT (ogg,
4222           "serial %08x time %" GST_TIME_FORMAT,
4223           pad->map.serialno, GST_TIME_ARGS (pad->start_time));
4224
4225       if (pad->map.serialno == serial) {
4226         known_serial = TRUE;
4227
4228         /* submit the page now, this will fill in the start_time when the
4229          * internal stream mapper finds it */
4230         gst_ogg_pad_submit_page (pad, &og);
4231
4232         if (!pad->map.is_skeleton && pad->start_time == -1
4233             && ogg_page_eos (&og)) {
4234           /* got EOS on a pad before we could find its start_time.
4235            * We have no chance of finding a start_time for every pad so
4236            * stop searching for the other start_time(s).
4237            */
4238           done = TRUE;
4239           break;
4240         }
4241       }
4242       /* the timestamp will be filled in when we submit the pages */
4243       if (!pad->map.is_sparse)
4244         done &= (pad->start_time != GST_CLOCK_TIME_NONE);
4245
4246       GST_LOG_OBJECT (ogg, "done %08x now %d", pad->map.serialno, done);
4247     }
4248
4249     /* we read a page not belonging to the current chain: seek back to the
4250      * beginning of the chain
4251      */
4252     if (!known_serial) {
4253       GST_LOG_OBJECT (ogg, "unknown serial %08x", serial);
4254       gst_ogg_demux_seek (ogg, offset);
4255       break;
4256     }
4257
4258     if (!done) {
4259       ret = gst_ogg_demux_get_next_page (ogg, &og, -1, NULL);
4260       if (ret != GST_FLOW_OK)
4261         break;
4262     }
4263   }
4264   GST_LOG_OBJECT (ogg, "done reading chain");
4265
4266   if (res_chain)
4267     *res_chain = chain;
4268
4269   return GST_FLOW_OK;
4270 }
4271
4272 /* read the last pages from the ogg stream to get the final
4273  * page end_offsets.
4274  */
4275 static GstFlowReturn
4276 gst_ogg_demux_read_end_chain (GstOggDemux * ogg, GstOggChain * chain)
4277 {
4278   gint64 begin = chain->end_offset;
4279   gint64 end = begin;
4280   gint64 last_granule = -1;
4281   GstOggPad *last_pad = NULL;
4282   GstFlowReturn ret;
4283   gboolean done = FALSE;
4284   ogg_page og;
4285   gint i;
4286
4287   while (!done) {
4288     begin -= ogg->chunk_size;
4289     if (begin < 0)
4290       begin = 0;
4291
4292     gst_ogg_demux_seek (ogg, begin);
4293
4294     /* now continue reading until we run out of data, if we find a page
4295      * start, we save it. It might not be the final page as there could be
4296      * another page after this one. */
4297     while (ogg->offset < end) {
4298       ret = gst_ogg_demux_get_next_page (ogg, &og, end - ogg->offset, NULL);
4299
4300       if (ret == GST_FLOW_LIMIT)
4301         break;
4302       if (ret != GST_FLOW_OK)
4303         return ret;
4304
4305       for (i = 0; i < chain->streams->len; i++) {
4306         GstOggPad *pad = g_array_index (chain->streams, GstOggPad *, i);
4307
4308         if (pad->map.is_skeleton)
4309           continue;
4310
4311         if (pad->map.serialno == ogg_page_serialno (&og)) {
4312           gint64 granulepos = ogg_page_granulepos (&og);
4313
4314           if (granulepos != -1) {
4315             last_granule = granulepos;
4316             last_pad = pad;
4317             done = TRUE;
4318           }
4319           break;
4320         }
4321       }
4322     }
4323   }
4324
4325   if (last_pad) {
4326     chain->segment_stop =
4327         gst_ogg_stream_get_end_time_for_granulepos (&last_pad->map,
4328         last_granule);
4329   } else {
4330     chain->segment_stop = GST_CLOCK_TIME_NONE;
4331   }
4332
4333   GST_INFO ("segment stop %" G_GUINT64_FORMAT ", for last granule %"
4334       G_GUINT64_FORMAT, chain->segment_stop, last_granule);
4335
4336   return GST_FLOW_OK;
4337 }
4338
4339 /* find a pad with a given serial number
4340  */
4341 static GstOggPad *
4342 gst_ogg_demux_find_pad (GstOggDemux * ogg, guint32 serialno)
4343 {
4344   GstOggPad *pad;
4345   gint i;
4346
4347   /* first look in building chain if any */
4348   if (ogg->building_chain) {
4349     pad = gst_ogg_chain_get_stream (ogg->building_chain, serialno);
4350     if (pad)
4351       return pad;
4352   }
4353
4354   /* then look in current chain if any */
4355   if (ogg->current_chain) {
4356     pad = gst_ogg_chain_get_stream (ogg->current_chain, serialno);
4357     if (pad)
4358       return pad;
4359   }
4360
4361   for (i = 0; i < ogg->chains->len; i++) {
4362     GstOggChain *chain = g_array_index (ogg->chains, GstOggChain *, i);
4363
4364     pad = gst_ogg_chain_get_stream (chain, serialno);
4365     if (pad)
4366       return pad;
4367   }
4368   return NULL;
4369 }
4370
4371 /* find a chain with a given serial number
4372  */
4373 static GstOggChain *
4374 gst_ogg_demux_find_chain (GstOggDemux * ogg, guint32 serialno)
4375 {
4376   GstOggPad *pad;
4377
4378   pad = gst_ogg_demux_find_pad (ogg, serialno);
4379   if (pad) {
4380     return pad->chain;
4381   }
4382   return NULL;
4383 }
4384
4385 /* returns TRUE if all streams have valid start time */
4386 static gboolean
4387 gst_ogg_demux_collect_chain_info (GstOggDemux * ogg, GstOggChain * chain)
4388 {
4389   gboolean res = TRUE;
4390
4391   chain->total_time = GST_CLOCK_TIME_NONE;
4392   GST_DEBUG_OBJECT (ogg, "trying to collect chain info");
4393
4394   /* see if we have a start time on all streams */
4395   chain->segment_start = gst_ogg_demux_collect_start_time (ogg, chain);
4396
4397   if (chain->segment_start == G_MAXUINT64) {
4398     /* not yet, stream some more data */
4399     res = FALSE;
4400   } else if (chain->segment_stop != GST_CLOCK_TIME_NONE) {
4401     /* we can calculate a total time */
4402     chain->total_time = chain->segment_stop - chain->segment_start;
4403   }
4404
4405   GST_DEBUG ("total time %" G_GUINT64_FORMAT, chain->total_time);
4406
4407   GST_DEBUG_OBJECT (ogg, "return %d", res);
4408
4409   return res;
4410 }
4411
4412 static void
4413 gst_ogg_demux_collect_info (GstOggDemux * ogg)
4414 {
4415   gint i;
4416
4417   /* collect all info */
4418   ogg->total_time = 0;
4419
4420   for (i = 0; i < ogg->chains->len; i++) {
4421     GstOggChain *chain = g_array_index (ogg->chains, GstOggChain *, i);
4422
4423     chain->begin_time = ogg->total_time;
4424
4425     gst_ogg_demux_collect_chain_info (ogg, chain);
4426
4427     ogg->total_time += chain->total_time;
4428   }
4429   ogg->segment.duration = ogg->total_time;
4430 }
4431
4432 /* find all the chains in the ogg file, this reads the first and
4433  * last page of the ogg stream, if they match then the ogg file has
4434  * just one chain, else we do a binary search for all chains.
4435  */
4436 static GstFlowReturn
4437 gst_ogg_demux_find_chains (GstOggDemux * ogg)
4438 {
4439   ogg_page og;
4440   GstPad *peer;
4441   gboolean res;
4442   guint32 serialno;
4443   GstOggChain *chain;
4444   GstFlowReturn ret;
4445
4446   /* get peer to figure out length */
4447   if ((peer = gst_pad_get_peer (ogg->sinkpad)) == NULL)
4448     goto no_peer;
4449
4450   /* find length to read last page, we store this for later use. */
4451   res = gst_pad_query_duration (peer, GST_FORMAT_BYTES, &ogg->length);
4452   gst_object_unref (peer);
4453   if (!res || ogg->length <= 0)
4454     goto no_length;
4455
4456   GST_DEBUG_OBJECT (ogg, "file length %" G_GINT64_FORMAT, ogg->length);
4457
4458   /* read chain from offset 0, this is the first chain of the
4459    * ogg file. */
4460   gst_ogg_demux_seek (ogg, 0);
4461   ret = gst_ogg_demux_read_chain (ogg, &chain);
4462   if (ret != GST_FLOW_OK) {
4463     if (ret == GST_FLOW_FLUSHING)
4464       goto flushing;
4465     else
4466       goto no_first_chain;
4467   }
4468
4469   /* read page from end offset, we use this page to check if its serial
4470    * number is contained in the first chain. If this is the case then
4471    * this ogg is not a chained ogg and we can skip the scanning. */
4472   gst_ogg_demux_seek (ogg, ogg->length);
4473   ret = gst_ogg_demux_get_prev_page (ogg, &og, NULL);
4474   if (ret != GST_FLOW_OK)
4475     goto no_last_page;
4476
4477   serialno = ogg_page_serialno (&og);
4478
4479   if (!gst_ogg_chain_has_stream (chain, serialno)) {
4480     /* the last page is not in the first stream, this means we should
4481      * find all the chains in this chained ogg. */
4482     ret =
4483         gst_ogg_demux_bisect_forward_serialno (ogg, 0, 0, ogg->length, chain,
4484         0);
4485   } else {
4486     /* we still call this function here but with an empty range so that
4487      * we can reuse the setup code in this routine. */
4488     ret =
4489         gst_ogg_demux_bisect_forward_serialno (ogg, 0, ogg->length,
4490         ogg->length, chain, 0);
4491   }
4492   if (ret != GST_FLOW_OK)
4493     goto done;
4494
4495   /* all fine, collect and print */
4496   gst_ogg_demux_collect_info (ogg);
4497
4498   /* dump our chains and streams */
4499   gst_ogg_print (ogg);
4500
4501 done:
4502   return ret;
4503
4504   /*** error cases ***/
4505 no_peer:
4506   {
4507     GST_ELEMENT_ERROR (ogg, STREAM, DEMUX, (NULL), ("we don't have a peer"));
4508     return GST_FLOW_NOT_LINKED;
4509   }
4510 no_length:
4511   {
4512     GST_ELEMENT_ERROR (ogg, STREAM, DEMUX, (NULL), ("can't get file length"));
4513     return GST_FLOW_NOT_SUPPORTED;
4514   }
4515 no_first_chain:
4516   {
4517     GST_ELEMENT_ERROR (ogg, STREAM, DEMUX, (NULL), ("can't get first chain"));
4518     return GST_FLOW_ERROR;
4519   }
4520 no_last_page:
4521   {
4522     GST_DEBUG_OBJECT (ogg, "can't get last page");
4523     if (chain)
4524       gst_ogg_chain_free (chain);
4525     return ret;
4526   }
4527 flushing:
4528   {
4529     GST_DEBUG_OBJECT (ogg, "Flushing, can't read chain");
4530     return GST_FLOW_FLUSHING;
4531   }
4532 }
4533
4534 static void
4535 gst_ogg_demux_update_chunk_size (GstOggDemux * ogg, ogg_page * page)
4536 {
4537   long size = page->header_len + page->body_len;
4538   long chunk_size = size * 2;
4539   if (chunk_size > ogg->chunk_size) {
4540     GST_LOG_OBJECT (ogg, "Updating chunk size to %ld", chunk_size);
4541     ogg->chunk_size = chunk_size;
4542   }
4543 }
4544
4545 static GstFlowReturn
4546 gst_ogg_demux_handle_page (GstOggDemux * ogg, ogg_page * page, gboolean discont)
4547 {
4548   GstOggPad *pad;
4549   gint64 granule;
4550   guint32 serialno;
4551   GstFlowReturn result = GST_FLOW_OK;
4552
4553   serialno = ogg_page_serialno (page);
4554   granule = ogg_page_granulepos (page);
4555
4556   gst_ogg_demux_update_chunk_size (ogg, page);
4557
4558   GST_LOG_OBJECT (ogg,
4559       "processing ogg page (serial %08x, "
4560       "pageno %ld, granulepos %" G_GINT64_FORMAT ", bos %d)", serialno,
4561       ogg_page_pageno (page), granule, ogg_page_bos (page));
4562
4563   if (ogg_page_bos (page)) {
4564     GstOggChain *chain;
4565
4566     /* first page */
4567     /* see if we know about the chain already */
4568     chain = gst_ogg_demux_find_chain (ogg, serialno);
4569     if (chain) {
4570       GstEvent *event;
4571       gint64 start = 0;
4572       GstSegment segment;
4573
4574       if (chain->segment_start != GST_CLOCK_TIME_NONE)
4575         start = chain->segment_start;
4576
4577       /* create the newsegment event we are going to send out */
4578       gst_segment_copy_into (&ogg->segment, &segment);
4579       segment.start = start;
4580       segment.stop = chain->segment_stop;
4581       segment.time = chain->begin_time;
4582       segment.base += chain->begin_time;
4583       event = gst_event_new_segment (&segment);
4584       gst_event_set_seqnum (event, ogg->seqnum);
4585
4586       GST_DEBUG_OBJECT (ogg,
4587           "segment: start %" GST_TIME_FORMAT ", stop %" GST_TIME_FORMAT
4588           ", time %" GST_TIME_FORMAT, GST_TIME_ARGS (start),
4589           GST_TIME_ARGS (chain->segment_stop),
4590           GST_TIME_ARGS (chain->begin_time));
4591
4592       /* activate it as it means we have a non-header, this will also deactivate
4593        * the currently running chain. */
4594       gst_ogg_demux_activate_chain (ogg, chain, event);
4595       pad = gst_ogg_demux_find_pad (ogg, serialno);
4596     } else {
4597       GstClockTime chain_time;
4598       gint64 current_time;
4599
4600       /* this can only happen in push mode */
4601       if (ogg->pullmode)
4602         goto unknown_chain;
4603
4604       current_time = ogg->segment.position;
4605
4606       /* time of new chain is current time */
4607       chain_time = current_time;
4608
4609       if (ogg->building_chain == NULL) {
4610         GstOggChain *newchain;
4611
4612         newchain = gst_ogg_chain_new (ogg);
4613         newchain->offset = 0;
4614         /* set new chain begin time aligned with end time of old chain */
4615         newchain->begin_time = chain_time;
4616         GST_DEBUG_OBJECT (ogg, "new chain, begin time %" GST_TIME_FORMAT,
4617             GST_TIME_ARGS (chain_time));
4618
4619         /* and this is the one we are building now */
4620         ogg->building_chain = newchain;
4621       }
4622       pad = gst_ogg_chain_new_stream (ogg->building_chain, serialno);
4623     }
4624   } else {
4625     pad = gst_ogg_demux_find_pad (ogg, serialno);
4626   }
4627   if (pad) {
4628     /* Reset granule interpolation if chaining in reverse (discont = TRUE) */
4629     if (discont)
4630       pad->current_granule = -1;
4631
4632     result = gst_ogg_pad_submit_page (pad, page);
4633   } else {
4634     GST_PUSH_LOCK (ogg);
4635     if (!ogg->pullmode && !ogg->push_disable_seeking) {
4636       /* no pad while probing for duration, we must have a chained stream,
4637          and we don't support them, so back off */
4638       GST_INFO_OBJECT (ogg, "We seem to have a chained stream, we won't seek");
4639       if (ogg->push_state == PUSH_DURATION) {
4640         GstFlowReturn res;
4641
4642         res = gst_ogg_demux_seek_back_after_push_duration_check_unlock (ogg);
4643         /* Call to function above unlocks, relock */
4644         GST_PUSH_LOCK (ogg);
4645         if (res != GST_FLOW_OK)
4646           return res;
4647       }
4648
4649       /* only once we seeked back */
4650       ogg->push_disable_seeking = TRUE;
4651     } else {
4652       GST_PUSH_UNLOCK (ogg);
4653       /* no pad. This means an ogg page without bos has been seen for this
4654        * serialno. we just ignore it but post a warning... */
4655       GST_ELEMENT_WARNING (ogg, STREAM, DECODE,
4656           (NULL), ("unknown ogg pad for serial %08x detected", serialno));
4657       return GST_FLOW_OK;
4658     }
4659     GST_PUSH_UNLOCK (ogg);
4660   }
4661   return result;
4662
4663   /* ERRORS */
4664 unknown_chain:
4665   {
4666     GST_ELEMENT_ERROR (ogg, STREAM, DECODE,
4667         (NULL), ("unknown ogg chain for serial %08x detected", serialno));
4668     return GST_FLOW_ERROR;
4669   }
4670 }
4671
4672 /* streaming mode, receive a buffer, parse it, create pads for
4673  * the serialno, submit pages and packets to the oggpads
4674  */
4675 static GstFlowReturn
4676 gst_ogg_demux_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer)
4677 {
4678   GstOggDemux *ogg;
4679   gint ret = 0;
4680   GstFlowReturn result = GST_FLOW_OK;
4681   gboolean drop;
4682
4683   ogg = GST_OGG_DEMUX (parent);
4684
4685   GST_PUSH_LOCK (ogg);
4686   drop = (ogg->seek_event_drop_till > 0);
4687   GST_PUSH_UNLOCK (ogg);
4688   if (drop) {
4689     GST_DEBUG_OBJECT (ogg, "Dropping buffer because we have a pending seek");
4690     gst_buffer_unref (buffer);
4691     return GST_FLOW_OK;
4692   }
4693
4694   GST_DEBUG_OBJECT (ogg, "enter");
4695   result = gst_ogg_demux_submit_buffer (ogg, buffer);
4696   if (result < 0) {
4697     GST_DEBUG_OBJECT (ogg, "gst_ogg_demux_submit_buffer returned %d", result);
4698   }
4699
4700   while (result == GST_FLOW_OK) {
4701     ogg_page page;
4702
4703     ret = ogg_sync_pageout (&ogg->sync, &page);
4704     if (ret == 0)
4705       /* need more data */
4706       break;
4707     if (ret == -1) {
4708       /* discontinuity in the pages */
4709       GST_DEBUG_OBJECT (ogg, "discont in page found, continuing");
4710     } else {
4711       result = gst_ogg_demux_handle_page (ogg, &page, FALSE);
4712       if (result < 0) {
4713         GST_DEBUG_OBJECT (ogg, "gst_ogg_demux_handle_page returned %d", result);
4714       }
4715     }
4716   }
4717   if (ret == 0 || result == GST_FLOW_OK) {
4718     gst_ogg_demux_sync_streams (ogg);
4719   }
4720   GST_DEBUG_OBJECT (ogg, "leave with %d", result);
4721   return result;
4722 }
4723
4724 static gboolean
4725 gst_ogg_demux_send_event (GstOggDemux * ogg, GstEvent * event)
4726 {
4727   GstOggChain *chain = ogg->current_chain;
4728   gboolean event_sent = FALSE;
4729   gboolean res = TRUE;
4730
4731   if (!chain)
4732     chain = ogg->building_chain;
4733
4734   if (chain) {
4735     gint i;
4736
4737     for (i = 0; i < chain->streams->len; i++) {
4738       GstOggPad *pad = g_array_index (chain->streams, GstOggPad *, i);
4739
4740       gst_event_ref (event);
4741       GST_DEBUG_OBJECT (pad, "Pushing event %" GST_PTR_FORMAT, event);
4742       res &= gst_pad_push_event (GST_PAD (pad), event);
4743       if (pad->added)
4744         event_sent = TRUE;
4745     }
4746   }
4747
4748   gst_event_unref (event);
4749
4750   if (!event_sent && GST_EVENT_TYPE (event) == GST_EVENT_EOS) {
4751     GST_ELEMENT_ERROR (ogg, STREAM, DEMUX, (NULL),
4752         ("EOS before finding a chain"));
4753   }
4754
4755   return res;
4756 }
4757
4758 static GstFlowReturn
4759 gst_ogg_demux_combine_flows (GstOggDemux * ogg, GstOggPad * pad,
4760     GstFlowReturn ret)
4761 {
4762   /* store the value */
4763   pad->last_ret = ret;
4764   pad->is_eos = (ret == GST_FLOW_EOS);
4765
4766   return gst_flow_combiner_update_pad_flow (ogg->flowcombiner,
4767       GST_PAD_CAST (pad), ret);
4768 }
4769
4770 static GstFlowReturn
4771 gst_ogg_demux_loop_forward (GstOggDemux * ogg)
4772 {
4773   GstFlowReturn ret;
4774   GstBuffer *buffer = NULL;
4775
4776   if (ogg->offset == ogg->length) {
4777     GST_LOG_OBJECT (ogg, "no more data to pull %" G_GINT64_FORMAT
4778         " == %" G_GINT64_FORMAT, ogg->offset, ogg->length);
4779     ret = GST_FLOW_EOS;
4780     goto done;
4781   }
4782
4783   GST_LOG_OBJECT (ogg, "pull data %" G_GINT64_FORMAT, ogg->offset);
4784   ret =
4785       gst_pad_pull_range (ogg->sinkpad, ogg->offset, ogg->chunk_size, &buffer);
4786   if (ret != GST_FLOW_OK) {
4787     GST_LOG_OBJECT (ogg, "Failed pull_range");
4788     goto done;
4789   }
4790
4791   ogg->offset += gst_buffer_get_size (buffer);
4792
4793   if (G_UNLIKELY (ogg->newsegment)) {
4794     gst_ogg_demux_send_event (ogg, ogg->newsegment);
4795     ogg->newsegment = NULL;
4796   }
4797
4798   ret = gst_ogg_demux_chain (ogg->sinkpad, GST_OBJECT_CAST (ogg), buffer);
4799   if (ret != GST_FLOW_OK && ret != GST_FLOW_EOS) {
4800     GST_LOG_OBJECT (ogg, "Failed demux_chain");
4801   }
4802
4803 done:
4804   return ret;
4805 }
4806
4807 /* reverse mode.
4808  *
4809  * We read the pages backwards and send the packets forwards. The first packet
4810  * in the page will be pushed with the DISCONT flag set.
4811  *
4812  * Special care has to be taken for continued pages, which we can only decode
4813  * when we have the previous page(s).
4814  */
4815 static GstFlowReturn
4816 gst_ogg_demux_loop_reverse (GstOggDemux * ogg)
4817 {
4818   GstFlowReturn ret;
4819   ogg_page page;
4820   gint64 offset;
4821
4822   if (ogg->offset == 0) {
4823     GST_LOG_OBJECT (ogg, "no more data to pull %" G_GINT64_FORMAT
4824         " == 0", ogg->offset);
4825     ret = GST_FLOW_EOS;
4826     goto done;
4827   }
4828
4829   GST_LOG_OBJECT (ogg, "read page from %" G_GINT64_FORMAT, ogg->offset);
4830   ret = gst_ogg_demux_get_prev_page (ogg, &page, &offset);
4831   if (ret != GST_FLOW_OK)
4832     goto done;
4833
4834   ogg->offset = offset;
4835
4836   if (G_UNLIKELY (ogg->newsegment)) {
4837     gst_ogg_demux_send_event (ogg, ogg->newsegment);
4838     ogg->newsegment = NULL;
4839   }
4840
4841   GST_LOG_OBJECT (ogg, "Handling page at offset %" G_GINT64_FORMAT,
4842       ogg->offset);
4843   ret = gst_ogg_demux_handle_page (ogg, &page, TRUE);
4844
4845 done:
4846   return ret;
4847 }
4848
4849 static void
4850 gst_ogg_demux_sync_streams (GstOggDemux * ogg)
4851 {
4852   GstClockTime cur;
4853   GstOggChain *chain;
4854   guint i;
4855
4856   chain = ogg->current_chain;
4857   cur = ogg->segment.position;
4858   if (chain == NULL || cur == -1)
4859     return;
4860
4861   for (i = 0; i < chain->streams->len; i++) {
4862     GstOggPad *stream = g_array_index (chain->streams, GstOggPad *, i);
4863
4864     /* Theoretically, we should be doing this for all streams, so we're doing
4865      * it, but it might break things break things for wrongly-muxed streams
4866      * (like we used to produce once) */
4867     if ( /*stream->map.is_sparse && */ stream->position != GST_CLOCK_TIME_NONE) {
4868
4869       /* Does this stream lag? Random threshold of 2 seconds */
4870       if (GST_CLOCK_DIFF (stream->position, cur) > (2 * GST_SECOND)) {
4871         GST_DEBUG_OBJECT (stream, "synchronizing stream with others by "
4872             "advancing time from %" GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
4873             GST_TIME_ARGS (stream->position), GST_TIME_ARGS (cur));
4874
4875         stream->position = cur;
4876
4877         gst_pad_push_event (GST_PAD_CAST (stream),
4878             gst_event_new_gap (stream->position, cur - stream->position));
4879       }
4880     }
4881   }
4882 }
4883
4884 /* random access code
4885  *
4886  * - first find all the chains and streams by scanning the file.
4887  * - then get and chain buffers, just like the streaming case.
4888  * - when seeking, we can use the chain info to perform the seek.
4889  */
4890 static void
4891 gst_ogg_demux_loop (GstOggPad * pad)
4892 {
4893   GstOggDemux *ogg;
4894   gboolean res;
4895   GstFlowReturn ret;
4896   GstEvent *seek;
4897
4898   ogg = GST_OGG_DEMUX (GST_OBJECT_PARENT (pad));
4899   seek = ogg->seek_event;
4900   ogg->seek_event = NULL;
4901
4902   if (ogg->need_chains) {
4903
4904     /* this is the only place where we write chains and thus need to lock. */
4905     GST_CHAIN_LOCK (ogg);
4906     ret = gst_ogg_demux_find_chains (ogg);
4907     GST_CHAIN_UNLOCK (ogg);
4908     if (ret != GST_FLOW_OK)
4909       goto chain_read_failed;
4910
4911     ogg->need_chains = FALSE;
4912
4913     GST_OBJECT_LOCK (ogg);
4914     ogg->running = TRUE;
4915     GST_OBJECT_UNLOCK (ogg);
4916
4917     /* and seek to configured positions without FLUSH */
4918     res = gst_ogg_demux_perform_seek_pull (ogg, seek);
4919
4920     if (!res)
4921       goto seek_failed;
4922   } else if (seek) {
4923     res = gst_ogg_demux_perform_seek_pull (ogg, seek);
4924     if (!res)
4925       goto seek_failed;
4926   }
4927
4928   if (ogg->segment.rate >= 0.0)
4929     ret = gst_ogg_demux_loop_forward (ogg);
4930   else
4931     ret = gst_ogg_demux_loop_reverse (ogg);
4932
4933   if (ret != GST_FLOW_OK)
4934     goto pause;
4935
4936   gst_ogg_demux_sync_streams (ogg);
4937   return;
4938
4939   /* ERRORS */
4940 chain_read_failed:
4941   {
4942     /* error was posted */
4943     goto pause;
4944   }
4945 seek_failed:
4946   {
4947     gboolean flushing;
4948
4949     GST_OBJECT_LOCK (pad);
4950     flushing = GST_PAD_IS_FLUSHING (pad);
4951     GST_OBJECT_UNLOCK (pad);
4952     if (flushing) {
4953       ret = GST_FLOW_FLUSHING;
4954     } else {
4955       GST_ELEMENT_FLOW_ERROR (ogg, ret);
4956       ret = GST_FLOW_ERROR;
4957     }
4958     goto pause;
4959   }
4960 pause:
4961   {
4962     const gchar *reason = gst_flow_get_name (ret);
4963     GstEvent *event = NULL;
4964
4965     GST_LOG_OBJECT (ogg, "pausing task, reason %s", reason);
4966     gst_pad_pause_task (ogg->sinkpad);
4967
4968     if (ret == GST_FLOW_EOS) {
4969       /* perform EOS logic */
4970       if (ogg->segment.flags & GST_SEEK_FLAG_SEGMENT) {
4971         gint64 stop;
4972         GstMessage *message;
4973
4974         /* for segment playback we need to post when (in stream time)
4975          * we stopped, this is either stop (when set) or the duration. */
4976         if ((stop = ogg->segment.stop) == -1)
4977           stop = ogg->segment.duration;
4978
4979         GST_LOG_OBJECT (ogg, "Sending segment done, at end of segment");
4980         message =
4981             gst_message_new_segment_done (GST_OBJECT (ogg), GST_FORMAT_TIME,
4982             stop);
4983         gst_message_set_seqnum (message, ogg->seqnum);
4984
4985         gst_element_post_message (GST_ELEMENT (ogg), message);
4986
4987         event = gst_event_new_segment_done (GST_FORMAT_TIME, stop);
4988         gst_event_set_seqnum (event, ogg->seqnum);
4989         gst_ogg_demux_send_event (ogg, event);
4990         event = NULL;
4991       } else {
4992         /* normal playback, send EOS to all linked pads */
4993         GST_LOG_OBJECT (ogg, "Sending EOS, at end of stream");
4994         event = gst_event_new_eos ();
4995       }
4996     } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS) {
4997       GST_ELEMENT_FLOW_ERROR (ogg, ret);
4998       event = gst_event_new_eos ();
4999     }
5000
5001     /* For wrong-state we still want to pause the task and stop
5002      * but no error message or other things are necessary.
5003      * wrong-state is no real error and will be caused by flushing,
5004      * e.g. because of a flushing seek.
5005      */
5006     if (event) {
5007       /* guard against corrupt/truncated files, where one can hit EOS
5008          before prerolling is done and a chain created. If we have no
5009          chain to send the event to, error out. */
5010       if (ogg->current_chain || ogg->building_chain) {
5011         gst_event_set_seqnum (event, ogg->seqnum);
5012         gst_ogg_demux_send_event (ogg, event);
5013       } else {
5014         gst_event_unref (event);
5015         GST_ELEMENT_ERROR (ogg, STREAM, DEMUX, (NULL),
5016             ("EOS before finding a chain"));
5017       }
5018     }
5019     return;
5020   }
5021 }
5022
5023 /* The sink pad task function for push mode.
5024  * It just sends any seek events queued by the streaming thread.
5025  */
5026 static gpointer
5027 gst_ogg_demux_loop_push (GstOggDemux * ogg)
5028 {
5029   GstEvent *event = NULL;
5030
5031   g_mutex_lock (&ogg->seek_event_mutex);
5032   /* Inform other threads that we started */
5033   ogg->seek_thread_started = TRUE;
5034   g_cond_broadcast (&ogg->thread_started_cond);
5035
5036
5037   while (!ogg->seek_event_thread_stop) {
5038
5039     while (!ogg->seek_event_thread_stop) {
5040       GST_PUSH_LOCK (ogg);
5041       event = ogg->seek_event;
5042       ogg->seek_event = NULL;
5043       if (event)
5044         ogg->seek_event_drop_till = gst_event_get_seqnum (event);
5045       GST_PUSH_UNLOCK (ogg);
5046
5047       if (event)
5048         break;
5049
5050       g_cond_wait (&ogg->seek_event_cond, &ogg->seek_event_mutex);
5051     }
5052
5053     if (ogg->seek_event_thread_stop) {
5054       break;
5055     }
5056     g_assert (event);
5057
5058     g_mutex_unlock (&ogg->seek_event_mutex);
5059
5060     GST_DEBUG_OBJECT (ogg->sinkpad, "Pushing event %" GST_PTR_FORMAT, event);
5061     if (!gst_pad_push_event (ogg->sinkpad, event)) {
5062       GST_WARNING_OBJECT (ogg, "Failed to push event");
5063       GST_PUSH_LOCK (ogg);
5064       if (!ogg->pullmode) {
5065         ogg->push_state = PUSH_PLAYING;
5066         ogg->push_disable_seeking = TRUE;
5067       }
5068       GST_PUSH_UNLOCK (ogg);
5069     } else {
5070       GST_DEBUG_OBJECT (ogg->sinkpad, "Pushed event ok");
5071     }
5072
5073     g_mutex_lock (&ogg->seek_event_mutex);
5074   }
5075
5076   g_mutex_unlock (&ogg->seek_event_mutex);
5077
5078   gst_object_unref (ogg);
5079   return NULL;
5080 }
5081
5082 static void
5083 gst_ogg_demux_clear_chains (GstOggDemux * ogg)
5084 {
5085   gint i;
5086
5087   gst_ogg_demux_deactivate_current_chain (ogg);
5088
5089   GST_CHAIN_LOCK (ogg);
5090   for (i = 0; i < ogg->chains->len; i++) {
5091     GstOggChain *chain = g_array_index (ogg->chains, GstOggChain *, i);
5092
5093     if (chain == ogg->current_chain)
5094       ogg->current_chain = NULL;
5095     if (chain == ogg->building_chain)
5096       ogg->building_chain = NULL;
5097     gst_ogg_chain_free (chain);
5098   }
5099   ogg->chains = g_array_set_size (ogg->chains, 0);
5100   if (ogg->current_chain != NULL) {
5101     GST_FIXME_OBJECT (ogg, "current chain was tracked in existing chains !");
5102     gst_ogg_chain_free (ogg->current_chain);
5103     ogg->current_chain = NULL;
5104   }
5105   if (ogg->building_chain != NULL) {
5106     GST_FIXME_OBJECT (ogg, "building chain was tracked in existing chains !");
5107     gst_ogg_chain_free (ogg->building_chain);
5108     ogg->building_chain = NULL;
5109   }
5110   GST_CHAIN_UNLOCK (ogg);
5111 }
5112
5113 /* this function is called when the pad is activated and should start
5114  * processing data.
5115  *
5116  * We check if we can do random access to decide if we work push or
5117  * pull based.
5118  */
5119 static gboolean
5120 gst_ogg_demux_sink_activate (GstPad * sinkpad, GstObject * parent)
5121 {
5122   GstQuery *query;
5123   gboolean pull_mode;
5124
5125   query = gst_query_new_scheduling ();
5126
5127   if (!gst_pad_peer_query (sinkpad, query)) {
5128     gst_query_unref (query);
5129     goto activate_push;
5130   }
5131
5132   pull_mode = gst_query_has_scheduling_mode_with_flags (query,
5133       GST_PAD_MODE_PULL, GST_SCHEDULING_FLAG_SEEKABLE);
5134   gst_query_unref (query);
5135
5136   if (!pull_mode)
5137     goto activate_push;
5138
5139   GST_DEBUG_OBJECT (sinkpad, "activating pull");
5140   return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);
5141
5142 activate_push:
5143   {
5144     GST_DEBUG_OBJECT (sinkpad, "activating push");
5145     return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
5146   }
5147 }
5148
5149 static gboolean
5150 gst_ogg_demux_sink_activate_mode (GstPad * sinkpad, GstObject * parent,
5151     GstPadMode mode, gboolean active)
5152 {
5153   gboolean res;
5154   GstOggDemux *ogg;
5155
5156   ogg = GST_OGG_DEMUX (parent);
5157
5158   switch (mode) {
5159     case GST_PAD_MODE_PUSH:
5160       ogg->pullmode = FALSE;
5161       ogg->resync = FALSE;
5162       if (active) {
5163         ogg->seek_event_thread_stop = FALSE;
5164         ogg->seek_thread_started = FALSE;
5165         ogg->seek_event_thread = g_thread_new ("seek_event_thread",
5166             (GThreadFunc) gst_ogg_demux_loop_push, gst_object_ref (ogg));
5167         /* And wait for the thread to start.
5168          * FIXME : This is hackish. And one wonders why we need a separate thread to
5169          * seek to a certain offset */
5170         g_mutex_lock (&ogg->seek_event_mutex);
5171         while (!ogg->seek_thread_started) {
5172           g_cond_wait (&ogg->thread_started_cond, &ogg->seek_event_mutex);
5173         }
5174         g_mutex_unlock (&ogg->seek_event_mutex);
5175       } else {
5176         g_mutex_lock (&ogg->seek_event_mutex);
5177         ogg->seek_event_thread_stop = TRUE;
5178         g_cond_broadcast (&ogg->seek_event_cond);
5179         g_mutex_unlock (&ogg->seek_event_mutex);
5180         g_thread_join (ogg->seek_event_thread);
5181         ogg->seek_event_thread = NULL;
5182       }
5183       res = TRUE;
5184       break;
5185     case GST_PAD_MODE_PULL:
5186       if (active) {
5187         ogg->need_chains = TRUE;
5188         ogg->pullmode = TRUE;
5189
5190         res = gst_pad_start_task (sinkpad, (GstTaskFunction) gst_ogg_demux_loop,
5191             sinkpad, NULL);
5192       } else {
5193         res = gst_pad_stop_task (sinkpad);
5194       }
5195       break;
5196     default:
5197       res = FALSE;
5198       break;
5199   }
5200   return res;
5201 }
5202
5203 static GstStateChangeReturn
5204 gst_ogg_demux_change_state (GstElement * element, GstStateChange transition)
5205 {
5206   GstOggDemux *ogg;
5207   GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
5208
5209   ogg = GST_OGG_DEMUX (element);
5210
5211   switch (transition) {
5212     case GST_STATE_CHANGE_NULL_TO_READY:
5213       ogg->basetime = 0;
5214       ogg_sync_init (&ogg->sync);
5215       break;
5216     case GST_STATE_CHANGE_READY_TO_PAUSED:
5217       ogg_sync_reset (&ogg->sync);
5218       ogg->running = FALSE;
5219       ogg->bitrate = 0;
5220       ogg->total_time = -1;
5221       GST_PUSH_LOCK (ogg);
5222       ogg->push_byte_offset = 0;
5223       ogg->push_byte_length = -1;
5224       ogg->push_time_length = GST_CLOCK_TIME_NONE;
5225       ogg->push_time_offset = GST_CLOCK_TIME_NONE;
5226       ogg->push_state = PUSH_PLAYING;
5227       ogg->have_group_id = FALSE;
5228       ogg->group_id = G_MAXUINT;
5229       ogg->seqnum = GST_SEQNUM_INVALID;
5230
5231       ogg->push_disable_seeking = FALSE;
5232       gst_ogg_demux_query_duration_push (ogg);
5233       GST_PUSH_UNLOCK (ogg);
5234       gst_segment_init (&ogg->segment, GST_FORMAT_TIME);
5235       break;
5236     default:
5237       break;
5238   }
5239
5240   result = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
5241
5242   switch (transition) {
5243     case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
5244       break;
5245     case GST_STATE_CHANGE_PAUSED_TO_READY:
5246       gst_ogg_demux_clear_chains (ogg);
5247       GST_OBJECT_LOCK (ogg);
5248       ogg->running = FALSE;
5249       GST_OBJECT_UNLOCK (ogg);
5250       break;
5251     case GST_STATE_CHANGE_READY_TO_NULL:
5252       ogg_sync_clear (&ogg->sync);
5253       break;
5254     default:
5255       break;
5256   }
5257   return result;
5258 }
5259
5260 static gboolean
5261 gst_ogg_demux_plugin_init (GstPlugin * plugin)
5262 {
5263   GST_DEBUG_CATEGORY_INIT (gst_ogg_demux_debug, "oggdemux", 0, "ogg demuxer");
5264   GST_DEBUG_CATEGORY_INIT (gst_ogg_demux_setup_debug, "oggdemux_setup", 0,
5265       "ogg demuxer setup stage when parsing pipeline");
5266
5267 #ifdef ENABLE_NLS
5268   GST_DEBUG ("binding text domain %s to locale dir %s", GETTEXT_PACKAGE,
5269       LOCALEDIR);
5270   bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
5271   bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
5272 #endif
5273
5274   return TRUE;
5275 }
5276
5277 /* prints all info about the element */
5278 #undef GST_CAT_DEFAULT
5279 #define GST_CAT_DEFAULT gst_ogg_demux_setup_debug
5280
5281 #ifdef GST_DISABLE_GST_DEBUG
5282
5283 static void
5284 gst_ogg_print (GstOggDemux * ogg)
5285 {
5286   /* NOP */
5287 }
5288
5289 #else /* !GST_DISABLE_GST_DEBUG */
5290
5291 static void
5292 gst_ogg_print (GstOggDemux * ogg)
5293 {
5294   guint j, i;
5295
5296   GST_INFO_OBJECT (ogg, "%u chains", ogg->chains->len);
5297   GST_INFO_OBJECT (ogg, " total time: %" GST_TIME_FORMAT,
5298       GST_TIME_ARGS (ogg->total_time));
5299
5300   for (i = 0; i < ogg->chains->len; i++) {
5301     GstOggChain *chain = g_array_index (ogg->chains, GstOggChain *, i);
5302
5303     GST_INFO_OBJECT (ogg, " chain %d (%u streams):", i, chain->streams->len);
5304     GST_INFO_OBJECT (ogg,
5305         "  offset: %" G_GINT64_FORMAT " - %" G_GINT64_FORMAT, chain->offset,
5306         chain->end_offset);
5307     GST_INFO_OBJECT (ogg, "  begin time: %" GST_TIME_FORMAT,
5308         GST_TIME_ARGS (chain->begin_time));
5309     GST_INFO_OBJECT (ogg, "  total time: %" GST_TIME_FORMAT,
5310         GST_TIME_ARGS (chain->total_time));
5311     GST_INFO_OBJECT (ogg, "  segment start: %" GST_TIME_FORMAT,
5312         GST_TIME_ARGS (chain->segment_start));
5313     GST_INFO_OBJECT (ogg, "  segment stop:  %" GST_TIME_FORMAT,
5314         GST_TIME_ARGS (chain->segment_stop));
5315
5316     for (j = 0; j < chain->streams->len; j++) {
5317       GstOggPad *stream = g_array_index (chain->streams, GstOggPad *, j);
5318
5319       GST_INFO_OBJECT (ogg, "  stream %08x: %s", stream->map.serialno,
5320           gst_ogg_stream_get_media_type (&stream->map));
5321       GST_INFO_OBJECT (ogg, "   start time:       %" GST_TIME_FORMAT,
5322           GST_TIME_ARGS (stream->start_time));
5323     }
5324   }
5325 }
5326 #endif /* GST_DISABLE_GST_DEBUG */