b27a9a74863f89b7d2d471c29aa91fea8af218a4
[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., 59 Temple Place - Suite 330,
19  * Boston, MA 02111-1307, USA.
20  */
21
22 /**
23  * SECTION:element-oggdemux
24  * @see_also: <link linkend="gst-plugins-base-plugins-oggmux">oggmux</link>
25  *
26  * This element demuxes ogg files into their encoded audio and video components.
27  *
28  * <refsect2>
29  * <title>Example pipelines</title>
30  * |[
31  * gst-launch -v filesrc location=test.ogg ! oggdemux ! vorbisdec ! audioconvert ! alsasink
32  * ]| Decodes the vorbis audio stored inside an ogg container.
33  * </refsect2>
34  *
35  * Last reviewed on 2006-12-30 (0.10.5)
36  */
37
38
39 #ifdef HAVE_CONFIG_H
40 #include "config.h"
41 #endif
42 #include <string.h>
43 #include <gst/gst-i18n-plugin.h>
44 #include <gst/tag/tag.h>
45
46 #include "gstoggdemux.h"
47
48 #define CHUNKSIZE (8500)        /* this is out of vorbisfile */
49
50 #define GST_FLOW_LIMIT GST_FLOW_CUSTOM_ERROR
51
52 #define GST_CHAIN_LOCK(ogg)     g_mutex_lock((ogg)->chain_lock)
53 #define GST_CHAIN_UNLOCK(ogg)   g_mutex_unlock((ogg)->chain_lock)
54
55 GST_DEBUG_CATEGORY (gst_ogg_demux_debug);
56 GST_DEBUG_CATEGORY (gst_ogg_demux_setup_debug);
57 #define GST_CAT_DEFAULT gst_ogg_demux_debug
58
59
60 static ogg_packet *
61 _ogg_packet_copy (const ogg_packet * packet)
62 {
63   ogg_packet *ret = g_new0 (ogg_packet, 1);
64
65   *ret = *packet;
66   ret->packet = g_memdup (packet->packet, packet->bytes);
67
68   return ret;
69 }
70
71 static void
72 _ogg_packet_free (ogg_packet * packet)
73 {
74   g_free (packet->packet);
75   g_free (packet);
76 }
77
78 static ogg_page *
79 gst_ogg_page_copy (ogg_page * page)
80 {
81   ogg_page *p = g_new0 (ogg_page, 1);
82
83   /* make a copy of the page */
84   p->header = g_memdup (page->header, page->header_len);
85   p->header_len = page->header_len;
86   p->body = g_memdup (page->body, page->body_len);
87   p->body_len = page->body_len;
88
89   return p;
90 }
91
92 static void
93 gst_ogg_page_free (ogg_page * page)
94 {
95   g_free (page->header);
96   g_free (page->body);
97   g_free (page);
98 }
99
100 static gboolean gst_ogg_demux_collect_chain_info (GstOggDemux * ogg,
101     GstOggChain * chain);
102 static gboolean gst_ogg_demux_activate_chain (GstOggDemux * ogg,
103     GstOggChain * chain, GstEvent * event);
104 static void gst_ogg_chain_mark_discont (GstOggChain * chain);
105
106 static gboolean gst_ogg_demux_perform_seek (GstOggDemux * ogg,
107     GstEvent * event);
108 static gboolean gst_ogg_demux_receive_event (GstElement * element,
109     GstEvent * event);
110
111 static void gst_ogg_pad_dispose (GObject * object);
112 static void gst_ogg_pad_finalize (GObject * object);
113
114 static const GstQueryType *gst_ogg_pad_query_types (GstPad * pad);
115 static gboolean gst_ogg_pad_src_query (GstPad * pad, GstQuery * query);
116 static gboolean gst_ogg_pad_event (GstPad * pad, GstEvent * event);
117 static GstCaps *gst_ogg_pad_getcaps (GstPad * pad);
118 static GstOggPad *gst_ogg_chain_get_stream (GstOggChain * chain,
119     glong serialno);
120
121 static GstFlowReturn gst_ogg_demux_combine_flows (GstOggDemux * ogg,
122     GstOggPad * pad, GstFlowReturn ret);
123 static void gst_ogg_demux_sync_streams (GstOggDemux * ogg);
124
125 GstCaps *gst_ogg_demux_set_header_on_caps (GstOggDemux * ogg,
126     GstCaps * caps, GList * headers);
127
128 GType gst_ogg_pad_get_type (void);
129 G_DEFINE_TYPE (GstOggPad, gst_ogg_pad, GST_TYPE_PAD);
130
131 static void
132 gst_ogg_pad_class_init (GstOggPadClass * klass)
133 {
134   GObjectClass *gobject_class;
135
136   gobject_class = (GObjectClass *) klass;
137
138   gobject_class->dispose = gst_ogg_pad_dispose;
139   gobject_class->finalize = gst_ogg_pad_finalize;
140 }
141
142 static void
143 gst_ogg_pad_init (GstOggPad * pad)
144 {
145   gst_pad_set_event_function (GST_PAD (pad),
146       GST_DEBUG_FUNCPTR (gst_ogg_pad_event));
147   gst_pad_set_getcaps_function (GST_PAD (pad),
148       GST_DEBUG_FUNCPTR (gst_ogg_pad_getcaps));
149   gst_pad_set_query_type_function (GST_PAD (pad),
150       GST_DEBUG_FUNCPTR (gst_ogg_pad_query_types));
151   gst_pad_set_query_function (GST_PAD (pad),
152       GST_DEBUG_FUNCPTR (gst_ogg_pad_src_query));
153
154   pad->mode = GST_OGG_PAD_MODE_INIT;
155
156   pad->current_granule = -1;
157   pad->keyframe_granule = -1;
158
159   pad->start_time = GST_CLOCK_TIME_NONE;
160
161   pad->last_stop = GST_CLOCK_TIME_NONE;
162
163   pad->have_type = FALSE;
164   pad->continued = NULL;
165   pad->map.headers = NULL;
166   pad->map.queued = NULL;
167 }
168
169 static void
170 gst_ogg_pad_dispose (GObject * object)
171 {
172   GstOggPad *pad = GST_OGG_PAD (object);
173
174   pad->chain = NULL;
175   pad->ogg = NULL;
176
177   g_list_foreach (pad->map.headers, (GFunc) _ogg_packet_free, NULL);
178   g_list_free (pad->map.headers);
179   pad->map.headers = NULL;
180   g_list_foreach (pad->map.queued, (GFunc) _ogg_packet_free, NULL);
181   g_list_free (pad->map.queued);
182   pad->map.queued = NULL;
183
184   g_free (pad->map.index);
185   pad->map.index = NULL;
186
187   /* clear continued pages */
188   g_list_foreach (pad->continued, (GFunc) gst_ogg_page_free, NULL);
189   g_list_free (pad->continued);
190   pad->continued = NULL;
191
192   if (pad->map.caps) {
193     gst_caps_unref (pad->map.caps);
194     pad->map.caps = NULL;
195   }
196
197   if (pad->map.taglist) {
198     gst_tag_list_free (pad->map.taglist);
199     pad->map.taglist = NULL;
200   }
201
202   ogg_stream_reset (&pad->map.stream);
203
204   G_OBJECT_CLASS (gst_ogg_pad_parent_class)->dispose (object);
205 }
206
207 static void
208 gst_ogg_pad_finalize (GObject * object)
209 {
210   GstOggPad *pad = GST_OGG_PAD (object);
211
212   ogg_stream_clear (&pad->map.stream);
213
214   G_OBJECT_CLASS (gst_ogg_pad_parent_class)->finalize (object);
215 }
216
217 static const GstQueryType *
218 gst_ogg_pad_query_types (GstPad * pad)
219 {
220   static const GstQueryType query_types[] = {
221     GST_QUERY_DURATION,
222     GST_QUERY_SEEKING,
223     0
224   };
225
226   return query_types;
227 }
228
229 static GstCaps *
230 gst_ogg_pad_getcaps (GstPad * pad)
231 {
232   return gst_caps_ref (GST_PAD_CAPS (pad));
233 }
234
235 static gboolean
236 gst_ogg_pad_src_query (GstPad * pad, GstQuery * query)
237 {
238   gboolean res = TRUE;
239   GstOggDemux *ogg;
240
241   ogg = GST_OGG_DEMUX (gst_pad_get_parent (pad));
242
243   switch (GST_QUERY_TYPE (query)) {
244     case GST_QUERY_DURATION:
245     {
246       GstFormat format;
247       gint64 total_time = -1;
248
249       gst_query_parse_duration (query, &format, NULL);
250       /* can only get position in time */
251       if (format != GST_FORMAT_TIME)
252         goto wrong_format;
253
254       if (ogg->total_time != -1) {
255         /* we can return the total length */
256         total_time = ogg->total_time;
257       } else {
258         gint bitrate = ogg->bitrate;
259
260         /* try with length and bitrate */
261         if (bitrate > 0) {
262           GstQuery *uquery;
263
264           /* ask upstream for total length in bytes */
265           uquery = gst_query_new_duration (GST_FORMAT_BYTES);
266           if (gst_pad_peer_query (ogg->sinkpad, uquery)) {
267             gint64 length;
268
269             gst_query_parse_duration (uquery, NULL, &length);
270
271             /* estimate using the bitrate */
272             total_time =
273                 gst_util_uint64_scale (length, 8 * GST_SECOND, bitrate);
274
275             GST_LOG_OBJECT (ogg,
276                 "length: %" G_GINT64_FORMAT ", bitrate %d, total_time %"
277                 GST_TIME_FORMAT, length, bitrate, GST_TIME_ARGS (total_time));
278           }
279           gst_query_unref (uquery);
280         }
281       }
282
283       gst_query_set_duration (query, GST_FORMAT_TIME, total_time);
284       break;
285     }
286     case GST_QUERY_SEEKING:
287     {
288       GstFormat format;
289
290       gst_query_parse_seeking (query, &format, NULL, NULL, NULL);
291       if (format == GST_FORMAT_TIME) {
292         gboolean seekable = FALSE;
293         gint64 stop = -1;
294
295         if (ogg->pullmode) {
296           seekable = TRUE;
297           stop = ogg->total_time;
298         } else if (ogg->current_chain->streams->len) {
299           gint i;
300
301           seekable = FALSE;
302           for (i = 0; i < ogg->current_chain->streams->len; i++) {
303             GstOggPad *pad =
304                 g_array_index (ogg->current_chain->streams, GstOggPad *, i);
305
306             seekable |= (pad->map.index != NULL && pad->map.n_index != 0);
307
308             if (pad->map.index != NULL && pad->map.n_index != 0) {
309               GstOggIndex *idx;
310               GstClockTime idx_time;
311
312               idx = &pad->map.index[pad->map.n_index - 1];
313               idx_time =
314                   gst_util_uint64_scale (idx->timestamp, GST_SECOND,
315                   pad->map.kp_denom);
316               if (stop == -1)
317                 stop = idx_time;
318               else
319                 stop = MAX (idx_time, stop);
320             }
321           }
322         }
323
324         gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0, stop);
325       } else {
326         res = FALSE;
327       }
328       break;
329     }
330
331     default:
332       res = gst_pad_query_default (pad, query);
333       break;
334   }
335 done:
336   gst_object_unref (ogg);
337
338   return res;
339
340   /* ERRORS */
341 wrong_format:
342   {
343     GST_DEBUG_OBJECT (ogg, "only query duration on TIME is supported");
344     res = FALSE;
345     goto done;
346   }
347 }
348
349 static gboolean
350 gst_ogg_demux_receive_event (GstElement * element, GstEvent * event)
351 {
352   gboolean res;
353   GstOggDemux *ogg;
354
355   ogg = GST_OGG_DEMUX (element);
356
357   switch (GST_EVENT_TYPE (event)) {
358     case GST_EVENT_SEEK:
359       /* now do the seek */
360       res = gst_ogg_demux_perform_seek (ogg, event);
361       gst_event_unref (event);
362       break;
363     default:
364       GST_DEBUG_OBJECT (ogg, "We only handle seek events here");
365       goto error;
366   }
367
368   return res;
369
370   /* ERRORS */
371 error:
372   {
373     GST_DEBUG_OBJECT (ogg, "error handling event");
374     gst_event_unref (event);
375     return FALSE;
376   }
377 }
378
379 static gboolean
380 gst_ogg_pad_event (GstPad * pad, GstEvent * event)
381 {
382   gboolean res;
383   GstOggDemux *ogg;
384
385   ogg = GST_OGG_DEMUX (gst_pad_get_parent (pad));
386
387   switch (GST_EVENT_TYPE (event)) {
388     case GST_EVENT_SEEK:
389       /* now do the seek */
390       res = gst_ogg_demux_perform_seek (ogg, event);
391       gst_event_unref (event);
392       break;
393     default:
394       res = gst_pad_event_default (pad, event);
395       break;
396   }
397   gst_object_unref (ogg);
398
399   return res;
400 }
401
402 static void
403 gst_ogg_pad_reset (GstOggPad * pad)
404 {
405   ogg_stream_reset (&pad->map.stream);
406
407   GST_DEBUG_OBJECT (pad, "doing reset");
408
409   /* clear continued pages */
410   g_list_foreach (pad->continued, (GFunc) gst_ogg_page_free, NULL);
411   g_list_free (pad->continued);
412   pad->continued = NULL;
413
414   pad->last_ret = GST_FLOW_OK;
415   pad->last_stop = GST_CLOCK_TIME_NONE;
416   pad->current_granule = -1;
417   pad->keyframe_granule = -1;
418   pad->is_eos = FALSE;
419 }
420
421 /* queue data, basically takes the packet, puts it in a buffer and store the
422  * buffer in the queued list.  */
423 static GstFlowReturn
424 gst_ogg_demux_queue_data (GstOggPad * pad, ogg_packet * packet)
425 {
426 #ifndef GST_DISABLE_GST_DEBUG
427   GstOggDemux *ogg = pad->ogg;
428 #endif
429
430   GST_DEBUG_OBJECT (ogg, "%p queueing data serial %08lx", pad,
431       pad->map.serialno);
432
433   pad->map.queued = g_list_append (pad->map.queued, _ogg_packet_copy (packet));
434
435   /* we are ok now */
436   return GST_FLOW_OK;
437 }
438
439 static GstFlowReturn
440 gst_ogg_demux_chain_peer (GstOggPad * pad, ogg_packet * packet,
441     gboolean push_headers)
442 {
443   GstBuffer *buf = NULL;
444   GstFlowReturn ret, cret;
445   GstOggDemux *ogg = pad->ogg;
446   gint64 current_time;
447   GstOggChain *chain;
448   gint64 duration;
449   gint offset;
450   gint trim;
451   GstClockTime out_timestamp, out_duration;
452   guint64 out_offset, out_offset_end;
453   gboolean delta_unit = FALSE;
454
455   cret = GST_FLOW_OK;
456
457   GST_DEBUG_OBJECT (ogg,
458       "%p streaming to peer serial %08lx", pad, pad->map.serialno);
459
460   if (pad->map.is_ogm) {
461     const guint8 *data;
462     long bytes;
463
464     data = packet->packet;
465     bytes = packet->bytes;
466
467     if (bytes < 1)
468       goto empty_packet;
469
470     if ((data[0] & 1) || (data[0] & 3 && pad->map.is_ogm_text)) {
471       /* We don't push header packets for OGM */
472       goto done;
473     }
474
475     offset = 1 + (((data[0] & 0xc0) >> 6) | ((data[0] & 0x02) << 1));
476     delta_unit = (((data[0] & 0x08) >> 3) == 0);
477
478     trim = 0;
479
480     /* Strip trailing \0 for subtitles */
481     if (pad->map.is_ogm_text) {
482       while (bytes && data[bytes - 1] == 0) {
483         trim++;
484         bytes--;
485       }
486     }
487   } else if (pad->map.is_vp8) {
488     if ((packet->bytes >= 7 && memcmp (packet->packet, "OVP80\2 ", 7) == 0) ||
489         packet->b_o_s ||
490         (packet->bytes >= 5 && memcmp (packet->packet, "OVP80", 5) == 0)) {
491       /* We don't push header packets for VP8 */
492       goto done;
493     }
494     offset = 0;
495     trim = 0;
496   } else {
497     offset = 0;
498     trim = 0;
499   }
500
501   /* get timing info for the packet */
502   duration = gst_ogg_stream_get_packet_duration (&pad->map, packet);
503   GST_DEBUG_OBJECT (ogg, "packet duration %" G_GUINT64_FORMAT, duration);
504
505   if (packet->b_o_s) {
506     out_timestamp = GST_CLOCK_TIME_NONE;
507     out_duration = GST_CLOCK_TIME_NONE;
508     out_offset = 0;
509     out_offset_end = -1;
510   } else {
511     if (packet->granulepos != -1) {
512       pad->current_granule = gst_ogg_stream_granulepos_to_granule (&pad->map,
513           packet->granulepos);
514       pad->keyframe_granule =
515           gst_ogg_stream_granulepos_to_key_granule (&pad->map,
516           packet->granulepos);
517       GST_DEBUG_OBJECT (ogg, "new granule %" G_GUINT64_FORMAT,
518           pad->current_granule);
519     } else if (ogg->segment.rate > 0.0 && pad->current_granule != -1) {
520       pad->current_granule += duration;
521       GST_DEBUG_OBJECT (ogg, "interpollating granule %" G_GUINT64_FORMAT,
522           pad->current_granule);
523     }
524     if (ogg->segment.rate < 0.0 && packet->granulepos == -1) {
525       /* negative rates, only set timestamp on the packets with a granulepos */
526       out_timestamp = -1;
527       out_duration = -1;
528       out_offset = -1;
529       out_offset_end = -1;
530     } else {
531       /* we only push buffers after we have a valid granule. This is done so that
532        * we nicely skip packets without a timestamp after a seek. This is ok
533        * because we base or seek on the packet after the page with the smaller
534        * timestamp. */
535       if (pad->current_granule == -1)
536         goto no_timestamp;
537
538       if (pad->map.is_ogm) {
539         out_timestamp = gst_ogg_stream_granule_to_time (&pad->map,
540             pad->current_granule);
541         out_duration = gst_util_uint64_scale (duration,
542             GST_SECOND * pad->map.granulerate_d, pad->map.granulerate_n);
543       } else if (pad->map.is_sparse) {
544         out_timestamp = gst_ogg_stream_granule_to_time (&pad->map,
545             pad->current_granule);
546         if (duration == GST_CLOCK_TIME_NONE) {
547           out_duration = GST_CLOCK_TIME_NONE;
548         } else {
549           out_duration = gst_util_uint64_scale (duration,
550               GST_SECOND * pad->map.granulerate_d, pad->map.granulerate_n);
551         }
552       } else {
553         out_timestamp = gst_ogg_stream_granule_to_time (&pad->map,
554             pad->current_granule - duration);
555         out_duration =
556             gst_ogg_stream_granule_to_time (&pad->map,
557             pad->current_granule) - out_timestamp;
558       }
559       out_offset_end =
560           gst_ogg_stream_granule_to_granulepos (&pad->map,
561           pad->current_granule, pad->keyframe_granule);
562       out_offset =
563           gst_ogg_stream_granule_to_time (&pad->map, pad->current_granule);
564     }
565   }
566
567   if (pad->map.is_ogm_text) {
568     /* check for invalid buffer sizes */
569     if (G_UNLIKELY (offset + trim >= packet->bytes))
570       goto empty_packet;
571   }
572
573   if (!pad->added)
574     goto not_added;
575
576   buf = gst_buffer_new_and_alloc (packet->bytes - offset - trim);
577   gst_buffer_set_caps (buf, GST_PAD_CAPS (pad));
578
579   /* set delta flag for OGM content */
580   if (delta_unit)
581     GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
582
583   /* copy packet in buffer */
584   memcpy (buf->data, packet->packet + offset, packet->bytes - offset - trim);
585
586   GST_BUFFER_TIMESTAMP (buf) = out_timestamp;
587   GST_BUFFER_DURATION (buf) = out_duration;
588   GST_BUFFER_OFFSET (buf) = out_offset;
589   GST_BUFFER_OFFSET_END (buf) = out_offset_end;
590
591   /* Mark discont on the buffer */
592   if (pad->discont) {
593     GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
594     pad->discont = FALSE;
595   }
596
597   pad->last_stop = ogg->segment.last_stop;
598
599   /* don't push the header packets when we are asked to skip them */
600   if (!packet->b_o_s || push_headers) {
601     ret = gst_pad_push (GST_PAD_CAST (pad), buf);
602     buf = NULL;
603
604     /* combine flows */
605     cret = gst_ogg_demux_combine_flows (ogg, pad, ret);
606   }
607
608   /* we're done with skeleton stuff */
609   if (pad->map.is_skeleton)
610     goto done;
611
612   /* check if valid granulepos, then we can calculate the current
613    * position. We know the granule for each packet but we only want to update
614    * the last_stop when we have a valid granulepos on the packet because else
615    * our time jumps around for the different streams. */
616   if (packet->granulepos < 0)
617     goto done;
618
619   /* convert to time */
620   current_time = gst_ogg_stream_get_end_time_for_granulepos (&pad->map,
621       packet->granulepos);
622
623   /* convert to stream time */
624   if ((chain = pad->chain)) {
625     gint64 chain_start = 0;
626
627     if (chain->segment_start != GST_CLOCK_TIME_NONE)
628       chain_start = chain->segment_start;
629
630     current_time = current_time - chain_start + chain->begin_time;
631   }
632
633   /* and store as the current position */
634   gst_segment_set_last_stop (&ogg->segment, GST_FORMAT_TIME, current_time);
635
636   GST_DEBUG_OBJECT (ogg, "ogg current time %" GST_TIME_FORMAT,
637       GST_TIME_ARGS (current_time));
638
639   /* check stream eos */
640   if ((ogg->segment.rate > 0.0 && ogg->segment.stop != GST_CLOCK_TIME_NONE &&
641           current_time > ogg->segment.stop) ||
642       (ogg->segment.rate < 0.0 && ogg->segment.start != GST_CLOCK_TIME_NONE &&
643           current_time < ogg->segment.start)) {
644     GST_DEBUG_OBJECT (ogg, "marking pad %p EOS", pad);
645     pad->is_eos = TRUE;
646   }
647
648 done:
649   if (buf)
650     gst_buffer_unref (buf);
651   /* return combined flow result */
652   return cret;
653
654   /* special cases */
655 empty_packet:
656   {
657     GST_DEBUG_OBJECT (ogg, "Skipping empty packet");
658     goto done;
659   }
660
661 no_timestamp:
662   {
663     GST_DEBUG_OBJECT (ogg, "skipping packet: no valid granule found yet");
664     goto done;
665   }
666 not_added:
667   {
668     GST_DEBUG_OBJECT (ogg, "pad not added yet");
669     goto done;
670   }
671 }
672
673 static guint64
674 gst_ogg_demux_collect_start_time (GstOggDemux * ogg, GstOggChain * chain)
675 {
676   gint i;
677   guint64 start_time = G_MAXUINT64;
678
679   for (i = 0; i < chain->streams->len; i++) {
680     GstOggPad *pad = g_array_index (chain->streams, GstOggPad *, i);
681
682     if (pad->map.is_sparse)
683       continue;
684
685     /*  can do this if the pad start time is not defined */
686     if (pad->start_time == GST_CLOCK_TIME_NONE) {
687       start_time = G_MAXUINT64;
688       break;
689     } else {
690       start_time = MIN (start_time, pad->start_time);
691     }
692   }
693   return start_time;
694 }
695
696 /* submit a packet to the oggpad, this function will run the
697  * typefind code for the pad if this is the first packet for this
698  * stream 
699  */
700 static GstFlowReturn
701 gst_ogg_pad_submit_packet (GstOggPad * pad, ogg_packet * packet)
702 {
703   gint64 granule;
704   GstFlowReturn ret = GST_FLOW_OK;
705
706   GstOggDemux *ogg = pad->ogg;
707
708   GST_DEBUG_OBJECT (ogg, "%p submit packet serial %08lx", pad,
709       pad->map.serialno);
710
711   if (!pad->have_type) {
712     pad->have_type = gst_ogg_stream_setup_map (&pad->map, packet);
713     if (!pad->have_type) {
714       pad->map.caps = gst_caps_new_simple ("application/x-unknown", NULL);
715     }
716     if (pad->map.is_skeleton) {
717       GST_DEBUG_OBJECT (ogg, "we have a fishead");
718       /* copy values over to global ogg level */
719       ogg->basetime = pad->map.basetime;
720       ogg->prestime = pad->map.prestime;
721
722       /* use total time to update the total ogg time */
723       if (ogg->total_time == -1) {
724         ogg->total_time = pad->map.total_time;
725       } else if (pad->map.total_time > 0) {
726         ogg->total_time = MAX (ogg->total_time, pad->map.total_time);
727       }
728     }
729     if (pad->map.caps) {
730       gst_pad_set_caps (GST_PAD (pad), pad->map.caps);
731     } else {
732       GST_WARNING_OBJECT (ogg, "stream parser didn't create src pad caps");
733     }
734   }
735
736   if (pad->map.is_skeleton) {
737     guint32 serialno;
738     GstOggPad *skel_pad;
739     GstOggSkeleton type;
740
741     /* try to parse the serialno first */
742     if (gst_ogg_map_parse_fisbone (&pad->map, packet->packet, packet->bytes,
743             &serialno, &type)) {
744
745       GST_WARNING_OBJECT (pad->ogg,
746           "got skeleton packet for stream 0x%08x", serialno);
747
748       skel_pad = gst_ogg_chain_get_stream (pad->chain, serialno);
749       if (skel_pad) {
750         switch (type) {
751           case GST_OGG_SKELETON_FISBONE:
752             /* parse the remainder of the fisbone in the pad with the serialno,
753              * note that we ignore the start_time as this is usually wrong for
754              * live streams */
755             gst_ogg_map_add_fisbone (&skel_pad->map, &pad->map, packet->packet,
756                 packet->bytes, NULL);
757             break;
758           case GST_OGG_SKELETON_INDEX:
759             gst_ogg_map_add_index (&skel_pad->map, &pad->map, packet->packet,
760                 packet->bytes);
761
762             /* use total time to update the total ogg time */
763             if (ogg->total_time == -1) {
764               ogg->total_time = skel_pad->map.total_time;
765             } else if (skel_pad->map.total_time > 0) {
766               ogg->total_time = MAX (ogg->total_time, skel_pad->map.total_time);
767             }
768             break;
769           default:
770             break;
771         }
772
773       } else {
774         GST_WARNING_OBJECT (pad->ogg,
775             "found skeleton fisbone for an unknown stream 0x%08x", serialno);
776       }
777     }
778   }
779
780   granule = gst_ogg_stream_granulepos_to_granule (&pad->map,
781       packet->granulepos);
782   if (granule != -1) {
783     GST_DEBUG_OBJECT (ogg, "%p has granulepos %" G_GINT64_FORMAT, pad, granule);
784     pad->current_granule = granule;
785   }
786
787   /* restart header packet count when seeing a b_o_s page;
788    * particularly useful following a seek or even following chain finding */
789   if (packet->b_o_s) {
790     GST_DEBUG_OBJECT (ogg, "b_o_s packet, resetting header packet count");
791     pad->map.n_header_packets_seen = 0;
792     if (!pad->map.have_headers) {
793       GST_DEBUG_OBJECT (ogg, "clearing header packets");
794       g_list_foreach (pad->map.headers, (GFunc) _ogg_packet_free, NULL);
795       g_list_free (pad->map.headers);
796       pad->map.headers = NULL;
797     }
798   }
799
800   /* Overload the value of b_o_s in ogg_packet with a flag whether or
801    * not this is a header packet.  Maybe some day this could be cleaned
802    * up.  */
803   packet->b_o_s = gst_ogg_stream_packet_is_header (&pad->map, packet);
804   if (!packet->b_o_s) {
805     GST_DEBUG ("found non-header packet");
806     pad->map.have_headers = TRUE;
807     if (pad->start_time == GST_CLOCK_TIME_NONE) {
808       gint64 duration = gst_ogg_stream_get_packet_duration (&pad->map, packet);
809       GST_DEBUG ("duration %" G_GINT64_FORMAT, duration);
810       if (duration != -1) {
811         pad->map.accumulated_granule += duration;
812         GST_DEBUG ("accumulated granule %" G_GINT64_FORMAT,
813             pad->map.accumulated_granule);
814       }
815
816       if (packet->granulepos != -1) {
817         ogg_int64_t start_granule;
818         gint64 granule;
819
820         granule = gst_ogg_stream_granulepos_to_granule (&pad->map,
821             packet->granulepos);
822
823         if (granule > pad->map.accumulated_granule)
824           start_granule = granule - pad->map.accumulated_granule;
825         else
826           start_granule = 0;
827
828         pad->start_time = gst_ogg_stream_granule_to_time (&pad->map,
829             start_granule);
830         GST_DEBUG ("start time %" G_GINT64_FORMAT, pad->start_time);
831       } else {
832         packet->granulepos = gst_ogg_stream_granule_to_granulepos (&pad->map,
833             pad->map.accumulated_granule, pad->keyframe_granule);
834       }
835     }
836   } else {
837     /* look for tags in header packet (before inc header count) */
838     gst_ogg_stream_extract_tags (&pad->map, packet);
839     pad->map.n_header_packets_seen++;
840     if (!pad->map.have_headers) {
841       pad->map.headers =
842           g_list_append (pad->map.headers, _ogg_packet_copy (packet));
843       GST_DEBUG ("keeping header packet %d", pad->map.n_header_packets_seen);
844     }
845   }
846
847   /* we know the start_time of the pad data, see if we
848    * can activate the complete chain if this is a dynamic
849    * chain. We need all the headers too for this. */
850   if (pad->start_time != GST_CLOCK_TIME_NONE && pad->map.have_headers) {
851     GstOggChain *chain = pad->chain;
852
853     /* check if complete chain has start time */
854     if (chain == ogg->building_chain) {
855       GstEvent *event = NULL;
856
857       if (ogg->resync) {
858         guint64 start_time;
859
860         GST_DEBUG_OBJECT (ogg, "need to resync");
861
862         /* when we need to resync after a seek, we wait until we have received
863          * timestamps on all streams */
864         start_time = gst_ogg_demux_collect_start_time (ogg, chain);
865
866         if (start_time != G_MAXUINT64) {
867           gint64 segment_time;
868
869           GST_DEBUG_OBJECT (ogg, "start_time:  %" GST_TIME_FORMAT,
870               GST_TIME_ARGS (start_time));
871
872           if (chain->segment_start < start_time)
873             segment_time =
874                 (start_time - chain->segment_start) + chain->begin_time;
875           else
876             segment_time = chain->begin_time;
877
878           /* create the newsegment event we are going to send out */
879           event = gst_event_new_new_segment (FALSE, ogg->segment.rate,
880               GST_FORMAT_TIME, start_time, chain->segment_stop, segment_time);
881
882           ogg->resync = FALSE;
883         }
884       } else {
885         /* see if we have enough info to activate the chain, we have enough info
886          * when all streams have a valid start time. */
887         if (gst_ogg_demux_collect_chain_info (ogg, chain)) {
888
889           GST_DEBUG_OBJECT (ogg, "segment_start: %" GST_TIME_FORMAT,
890               GST_TIME_ARGS (chain->segment_start));
891           GST_DEBUG_OBJECT (ogg, "segment_stop:  %" GST_TIME_FORMAT,
892               GST_TIME_ARGS (chain->segment_stop));
893           GST_DEBUG_OBJECT (ogg, "segment_time:  %" GST_TIME_FORMAT,
894               GST_TIME_ARGS (chain->begin_time));
895
896           /* create the newsegment event we are going to send out */
897           event = gst_event_new_new_segment (FALSE, ogg->segment.rate,
898               GST_FORMAT_TIME, chain->segment_start, chain->segment_stop,
899               chain->begin_time);
900         }
901       }
902
903       if (event) {
904         gst_event_set_seqnum (event, ogg->seqnum);
905
906         gst_ogg_demux_activate_chain (ogg, chain, event);
907
908         ogg->building_chain = NULL;
909       }
910     }
911   }
912
913   /* if we are building a chain, store buffer for when we activate
914    * it. This path is taken if we operate in streaming mode. */
915   if (ogg->building_chain) {
916     /* bos packets where stored in the header list so we can discard
917      * them here*/
918     if (!packet->b_o_s)
919       ret = gst_ogg_demux_queue_data (pad, packet);
920   }
921   /* else we are completely streaming to the peer */
922   else {
923     ret = gst_ogg_demux_chain_peer (pad, packet, !ogg->pullmode);
924   }
925   return ret;
926 }
927
928 /* flush at most @npackets from the stream layer. All packets if 
929  * @npackets is 0;
930  */
931 static GstFlowReturn
932 gst_ogg_pad_stream_out (GstOggPad * pad, gint npackets)
933 {
934   GstFlowReturn result = GST_FLOW_OK;
935   gboolean done = FALSE;
936   GstOggDemux *ogg;
937
938   ogg = pad->ogg;
939
940   while (!done) {
941     int ret;
942     ogg_packet packet;
943
944     ret = ogg_stream_packetout (&pad->map.stream, &packet);
945     switch (ret) {
946       case 0:
947         GST_LOG_OBJECT (ogg, "packetout done");
948         done = TRUE;
949         break;
950       case -1:
951         GST_LOG_OBJECT (ogg, "packetout discont");
952         gst_ogg_chain_mark_discont (pad->chain);
953         break;
954       case 1:
955         GST_LOG_OBJECT (ogg, "packetout gave packet of size %ld", packet.bytes);
956         result = gst_ogg_pad_submit_packet (pad, &packet);
957         /* not linked is not a problem, it's possible that we are still
958          * collecting headers and that we don't have exposed the pads yet */
959         if (result == GST_FLOW_NOT_LINKED)
960           break;
961         else if (result <= GST_FLOW_UNEXPECTED)
962           goto could_not_submit;
963         break;
964       default:
965         GST_WARNING_OBJECT (ogg,
966             "invalid return value %d for ogg_stream_packetout, resetting stream",
967             ret);
968         gst_ogg_pad_reset (pad);
969         break;
970     }
971     if (npackets > 0) {
972       npackets--;
973       done = (npackets == 0);
974     }
975   }
976   return result;
977
978   /* ERRORS */
979 could_not_submit:
980   {
981     GST_WARNING_OBJECT (ogg,
982         "could not submit packet for stream %08lx, error: %d",
983         pad->map.serialno, result);
984     gst_ogg_pad_reset (pad);
985     return result;
986   }
987 }
988
989 /* submit a page to an oggpad, this function will then submit all
990  * the packets in the page.
991  */
992 static GstFlowReturn
993 gst_ogg_pad_submit_page (GstOggPad * pad, ogg_page * page)
994 {
995   GstFlowReturn result = GST_FLOW_OK;
996   GstOggDemux *ogg;
997   gboolean continued = FALSE;
998
999   ogg = pad->ogg;
1000
1001   /* for negative rates we read pages backwards and must therefore be carefull
1002    * with continued pages */
1003   if (ogg->segment.rate < 0.0) {
1004     gint npackets;
1005
1006     continued = ogg_page_continued (page);
1007
1008     /* number of completed packets in the page */
1009     npackets = ogg_page_packets (page);
1010     if (!continued) {
1011       /* page is not continued so it contains at least one packet start. It's
1012        * possible that no packet ends on this page (npackets == 0). In that
1013        * case, the next (continued) page(s) we kept contain the remainder of the
1014        * packets. We mark npackets=1 to make us start decoding the pages in the
1015        * remainder of the algorithm. */
1016       if (npackets == 0)
1017         npackets = 1;
1018     }
1019     GST_LOG_OBJECT (ogg, "continued: %d, %d packets", continued, npackets);
1020
1021     if (npackets == 0) {
1022       GST_LOG_OBJECT (ogg, "no decodable packets, we need a previous page");
1023       goto done;
1024     }
1025   }
1026
1027   if (ogg_stream_pagein (&pad->map.stream, page) != 0)
1028     goto choked;
1029
1030   /* flush all packets in the stream layer, this might not give a packet if
1031    * the page had no packets finishing on the page (npackets == 0). */
1032   result = gst_ogg_pad_stream_out (pad, 0);
1033
1034   if (pad->continued) {
1035     ogg_packet packet;
1036
1037     /* now send the continued pages to the stream layer */
1038     while (pad->continued) {
1039       ogg_page *p = (ogg_page *) pad->continued->data;
1040
1041       GST_LOG_OBJECT (ogg, "submitting continued page %p", p);
1042       if (ogg_stream_pagein (&pad->map.stream, p) != 0)
1043         goto choked;
1044
1045       pad->continued = g_list_delete_link (pad->continued, pad->continued);
1046
1047       /* free the page */
1048       gst_ogg_page_free (p);
1049     }
1050
1051     GST_LOG_OBJECT (ogg, "flushing last continued packet");
1052     /* flush 1 continued packet in the stream layer */
1053     result = gst_ogg_pad_stream_out (pad, 1);
1054
1055     /* flush all remaining packets, we pushed them in the previous round.
1056      * We don't use _reset() because we still want to get the discont when
1057      * we submit a next page. */
1058     while (ogg_stream_packetout (&pad->map.stream, &packet) != 0);
1059   }
1060
1061 done:
1062   /* keep continued pages (only in reverse mode) */
1063   if (continued) {
1064     ogg_page *p = gst_ogg_page_copy (page);
1065
1066     GST_LOG_OBJECT (ogg, "keeping continued page %p", p);
1067     pad->continued = g_list_prepend (pad->continued, p);
1068   }
1069
1070   return result;
1071
1072 choked:
1073   {
1074     GST_WARNING_OBJECT (ogg,
1075         "ogg stream choked on page (serial %08lx), resetting stream",
1076         pad->map.serialno);
1077     gst_ogg_pad_reset (pad);
1078     /* we continue to recover */
1079     return GST_FLOW_OK;
1080   }
1081 }
1082
1083
1084 static GstOggChain *
1085 gst_ogg_chain_new (GstOggDemux * ogg)
1086 {
1087   GstOggChain *chain = g_new0 (GstOggChain, 1);
1088
1089   GST_DEBUG_OBJECT (ogg, "creating new chain %p", chain);
1090   chain->ogg = ogg;
1091   chain->offset = -1;
1092   chain->bytes = -1;
1093   chain->have_bos = FALSE;
1094   chain->streams = g_array_new (FALSE, TRUE, sizeof (GstOggPad *));
1095   chain->begin_time = GST_CLOCK_TIME_NONE;
1096   chain->segment_start = GST_CLOCK_TIME_NONE;
1097   chain->segment_stop = GST_CLOCK_TIME_NONE;
1098   chain->total_time = GST_CLOCK_TIME_NONE;
1099
1100   return chain;
1101 }
1102
1103 static void
1104 gst_ogg_chain_free (GstOggChain * chain)
1105 {
1106   gint i;
1107
1108   for (i = 0; i < chain->streams->len; i++) {
1109     GstOggPad *pad = g_array_index (chain->streams, GstOggPad *, i);
1110
1111     gst_object_unref (pad);
1112   }
1113   g_array_free (chain->streams, TRUE);
1114   g_free (chain);
1115 }
1116
1117 static void
1118 gst_ogg_pad_mark_discont (GstOggPad * pad)
1119 {
1120   pad->discont = TRUE;
1121   pad->map.last_size = 0;
1122 }
1123
1124 static void
1125 gst_ogg_chain_mark_discont (GstOggChain * chain)
1126 {
1127   gint i;
1128
1129   for (i = 0; i < chain->streams->len; i++) {
1130     GstOggPad *pad = g_array_index (chain->streams, GstOggPad *, i);
1131
1132     gst_ogg_pad_mark_discont (pad);
1133   }
1134 }
1135
1136 static void
1137 gst_ogg_chain_reset (GstOggChain * chain)
1138 {
1139   gint i;
1140
1141   for (i = 0; i < chain->streams->len; i++) {
1142     GstOggPad *pad = g_array_index (chain->streams, GstOggPad *, i);
1143
1144     gst_ogg_pad_reset (pad);
1145   }
1146 }
1147
1148 static GstOggPad *
1149 gst_ogg_chain_new_stream (GstOggChain * chain, glong serialno)
1150 {
1151   GstOggPad *ret;
1152   GstTagList *list;
1153   gchar *name;
1154
1155   GST_DEBUG_OBJECT (chain->ogg, "creating new stream %08lx in chain %p",
1156       serialno, chain);
1157
1158   ret = g_object_new (GST_TYPE_OGG_PAD, NULL);
1159   /* we own this one */
1160   gst_object_ref_sink (ret);
1161
1162   GST_PAD_DIRECTION (ret) = GST_PAD_SRC;
1163   gst_ogg_pad_mark_discont (ret);
1164
1165   ret->chain = chain;
1166   ret->ogg = chain->ogg;
1167
1168   ret->map.serialno = serialno;
1169   if (ogg_stream_init (&ret->map.stream, serialno) != 0)
1170     goto init_failed;
1171
1172   name = g_strdup_printf ("serial_%08lx", serialno);
1173   gst_object_set_name (GST_OBJECT (ret), name);
1174   g_free (name);
1175
1176   /* FIXME: either do something with it or remove it */
1177   list = gst_tag_list_new ();
1178   gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_SERIAL, serialno,
1179       NULL);
1180   gst_tag_list_free (list);
1181
1182   GST_DEBUG_OBJECT (chain->ogg,
1183       "created new ogg src %p for stream with serial %08lx", ret, serialno);
1184
1185   g_array_append_val (chain->streams, ret);
1186
1187   return ret;
1188
1189   /* ERRORS */
1190 init_failed:
1191   {
1192     GST_ERROR ("Could not initialize ogg_stream struct for serial %08lx.",
1193         serialno);
1194     gst_object_unref (ret);
1195     return NULL;
1196   }
1197 }
1198
1199 static GstOggPad *
1200 gst_ogg_chain_get_stream (GstOggChain * chain, glong serialno)
1201 {
1202   gint i;
1203
1204   for (i = 0; i < chain->streams->len; i++) {
1205     GstOggPad *pad = g_array_index (chain->streams, GstOggPad *, i);
1206
1207     if (pad->map.serialno == serialno)
1208       return pad;
1209   }
1210   return NULL;
1211 }
1212
1213 static gboolean
1214 gst_ogg_chain_has_stream (GstOggChain * chain, glong serialno)
1215 {
1216   return gst_ogg_chain_get_stream (chain, serialno) != NULL;
1217 }
1218
1219 /* signals and args */
1220 enum
1221 {
1222   /* FILL ME */
1223   LAST_SIGNAL
1224 };
1225
1226 enum
1227 {
1228   ARG_0
1229       /* FILL ME */
1230 };
1231
1232 static GstStaticPadTemplate ogg_demux_src_template_factory =
1233 GST_STATIC_PAD_TEMPLATE ("src_%d",
1234     GST_PAD_SRC,
1235     GST_PAD_SOMETIMES,
1236     GST_STATIC_CAPS_ANY);
1237
1238 static GstStaticPadTemplate ogg_demux_sink_template_factory =
1239     GST_STATIC_PAD_TEMPLATE ("sink",
1240     GST_PAD_SINK,
1241     GST_PAD_ALWAYS,
1242     GST_STATIC_CAPS ("application/ogg; application/x-annodex")
1243     );
1244
1245 static void gst_ogg_demux_finalize (GObject * object);
1246
1247 static GstFlowReturn gst_ogg_demux_read_chain (GstOggDemux * ogg,
1248     GstOggChain ** chain);
1249 static GstFlowReturn gst_ogg_demux_read_end_chain (GstOggDemux * ogg,
1250     GstOggChain * chain);
1251
1252 static gboolean gst_ogg_demux_sink_event (GstPad * pad, GstEvent * event);
1253 static void gst_ogg_demux_loop (GstOggPad * pad);
1254 static GstFlowReturn gst_ogg_demux_chain (GstPad * pad, GstBuffer * buffer);
1255 static gboolean gst_ogg_demux_sink_activate (GstPad * sinkpad);
1256 static gboolean gst_ogg_demux_sink_activate_pull (GstPad * sinkpad,
1257     gboolean active);
1258 static gboolean gst_ogg_demux_sink_activate_push (GstPad * sinkpad,
1259     gboolean active);
1260 static GstStateChangeReturn gst_ogg_demux_change_state (GstElement * element,
1261     GstStateChange transition);
1262 static gboolean gst_ogg_demux_send_event (GstOggDemux * ogg, GstEvent * event);
1263
1264 static void gst_ogg_print (GstOggDemux * demux);
1265
1266 GST_BOILERPLATE (GstOggDemux, gst_ogg_demux, GstElement, GST_TYPE_ELEMENT);
1267
1268 static void
1269 gst_ogg_demux_base_init (gpointer g_class)
1270 {
1271   GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
1272
1273   gst_element_class_set_details_simple (element_class,
1274       "Ogg demuxer", "Codec/Demuxer",
1275       "demux ogg streams (info about ogg: http://xiph.org)",
1276       "Wim Taymans <wim@fluendo.com>");
1277
1278   gst_element_class_add_pad_template (element_class,
1279       gst_static_pad_template_get (&ogg_demux_sink_template_factory));
1280   gst_element_class_add_pad_template (element_class,
1281       gst_static_pad_template_get (&ogg_demux_src_template_factory));
1282 }
1283
1284 static void
1285 gst_ogg_demux_class_init (GstOggDemuxClass * klass)
1286 {
1287   GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
1288   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
1289
1290   gstelement_class->change_state = gst_ogg_demux_change_state;
1291   gstelement_class->send_event = gst_ogg_demux_receive_event;
1292
1293   gobject_class->finalize = gst_ogg_demux_finalize;
1294 }
1295
1296 static void
1297 gst_ogg_demux_init (GstOggDemux * ogg, GstOggDemuxClass * g_class)
1298 {
1299   /* create the sink pad */
1300   ogg->sinkpad =
1301       gst_pad_new_from_static_template (&ogg_demux_sink_template_factory,
1302       "sink");
1303
1304   gst_pad_set_event_function (ogg->sinkpad, gst_ogg_demux_sink_event);
1305   gst_pad_set_chain_function (ogg->sinkpad, gst_ogg_demux_chain);
1306   gst_pad_set_activate_function (ogg->sinkpad, gst_ogg_demux_sink_activate);
1307   gst_pad_set_activatepull_function (ogg->sinkpad,
1308       gst_ogg_demux_sink_activate_pull);
1309   gst_pad_set_activatepush_function (ogg->sinkpad,
1310       gst_ogg_demux_sink_activate_push);
1311   gst_element_add_pad (GST_ELEMENT (ogg), ogg->sinkpad);
1312
1313   ogg->chain_lock = g_mutex_new ();
1314   ogg->chains = g_array_new (FALSE, TRUE, sizeof (GstOggChain *));
1315
1316   ogg->newsegment = NULL;
1317 }
1318
1319 static void
1320 gst_ogg_demux_finalize (GObject * object)
1321 {
1322   GstOggDemux *ogg;
1323
1324   ogg = GST_OGG_DEMUX (object);
1325
1326   g_array_free (ogg->chains, TRUE);
1327   g_mutex_free (ogg->chain_lock);
1328   ogg_sync_clear (&ogg->sync);
1329
1330   if (ogg->newsegment)
1331     gst_event_unref (ogg->newsegment);
1332
1333   G_OBJECT_CLASS (parent_class)->finalize (object);
1334 }
1335
1336 static void
1337 gst_ogg_demux_reset_streams (GstOggDemux * ogg)
1338 {
1339   GstOggChain *chain;
1340   guint i;
1341
1342   chain = ogg->current_chain;
1343   if (chain == NULL)
1344     return;
1345
1346   for (i = 0; i < chain->streams->len; i++) {
1347     GstOggPad *stream = g_array_index (chain->streams, GstOggPad *, i);
1348
1349     stream->start_time = -1;
1350     stream->map.accumulated_granule = 0;
1351   }
1352   ogg->building_chain = chain;
1353   ogg->current_chain = NULL;
1354   ogg->resync = TRUE;
1355 }
1356
1357 static gboolean
1358 gst_ogg_demux_sink_event (GstPad * pad, GstEvent * event)
1359 {
1360   gboolean res;
1361   GstOggDemux *ogg;
1362
1363   ogg = GST_OGG_DEMUX (gst_pad_get_parent (pad));
1364
1365   switch (GST_EVENT_TYPE (event)) {
1366     case GST_EVENT_FLUSH_START:
1367       res = gst_ogg_demux_send_event (ogg, event);
1368       break;
1369     case GST_EVENT_FLUSH_STOP:
1370       GST_DEBUG_OBJECT (ogg, "got a flush stop event");
1371       ogg_sync_reset (&ogg->sync);
1372       res = gst_ogg_demux_send_event (ogg, event);
1373       gst_ogg_demux_reset_streams (ogg);
1374       break;
1375     case GST_EVENT_NEWSEGMENT:
1376       GST_DEBUG_OBJECT (ogg, "got a new segment event");
1377       gst_event_unref (event);
1378       res = TRUE;
1379       break;
1380     case GST_EVENT_EOS:
1381     {
1382       GST_DEBUG_OBJECT (ogg, "got an EOS event");
1383       res = gst_ogg_demux_send_event (ogg, event);
1384       if (ogg->current_chain == NULL) {
1385         GST_ELEMENT_ERROR (ogg, STREAM, DEMUX, (NULL),
1386             ("can't get first chain"));
1387       }
1388       break;
1389     }
1390     default:
1391       res = gst_ogg_demux_send_event (ogg, event);
1392       break;
1393   }
1394   gst_object_unref (ogg);
1395
1396   return res;
1397 }
1398
1399 /* submit the given buffer to the ogg sync */
1400 static GstFlowReturn
1401 gst_ogg_demux_submit_buffer (GstOggDemux * ogg, GstBuffer * buffer)
1402 {
1403   gint size;
1404   guint8 *data;
1405   gchar *oggbuffer;
1406   GstFlowReturn ret = GST_FLOW_OK;
1407
1408   size = GST_BUFFER_SIZE (buffer);
1409   data = GST_BUFFER_DATA (buffer);
1410
1411   GST_DEBUG_OBJECT (ogg, "submitting %u bytes", size);
1412   if (G_UNLIKELY (size == 0))
1413     goto done;
1414
1415   oggbuffer = ogg_sync_buffer (&ogg->sync, size);
1416   if (G_UNLIKELY (oggbuffer == NULL))
1417     goto no_buffer;
1418
1419   memcpy (oggbuffer, data, size);
1420   if (G_UNLIKELY (ogg_sync_wrote (&ogg->sync, size) < 0))
1421     goto write_failed;
1422
1423 done:
1424   gst_buffer_unref (buffer);
1425
1426   return ret;
1427
1428   /* ERRORS */
1429 no_buffer:
1430   {
1431     GST_ELEMENT_ERROR (ogg, STREAM, DECODE,
1432         (NULL), ("failed to get ogg sync buffer"));
1433     ret = GST_FLOW_ERROR;
1434     goto done;
1435   }
1436 write_failed:
1437   {
1438     GST_ELEMENT_ERROR (ogg, STREAM, DECODE,
1439         (NULL), ("failed to write %d bytes to the sync buffer", size));
1440     ret = GST_FLOW_ERROR;
1441     goto done;
1442   }
1443 }
1444
1445 /* in random access mode this code updates the current read position
1446  * and resets the ogg sync buffer so that the next read will happen
1447  * from this new location.
1448  */
1449 static void
1450 gst_ogg_demux_seek (GstOggDemux * ogg, gint64 offset)
1451 {
1452   GST_LOG_OBJECT (ogg, "seeking to %" G_GINT64_FORMAT, offset);
1453
1454   ogg->offset = offset;
1455   ogg->read_offset = offset;
1456   ogg_sync_reset (&ogg->sync);
1457 }
1458
1459 /* read more data from the current offset and submit to
1460  * the ogg sync layer.
1461  */
1462 static GstFlowReturn
1463 gst_ogg_demux_get_data (GstOggDemux * ogg, gint64 end_offset)
1464 {
1465   GstFlowReturn ret;
1466   GstBuffer *buffer;
1467
1468   GST_LOG_OBJECT (ogg,
1469       "get data %" G_GINT64_FORMAT " %" G_GINT64_FORMAT " %" G_GINT64_FORMAT,
1470       ogg->read_offset, ogg->length, end_offset);
1471
1472   if (end_offset > 0 && ogg->read_offset >= end_offset)
1473     goto boundary_reached;
1474
1475   if (ogg->read_offset == ogg->length)
1476     goto eos;
1477
1478   ret = gst_pad_pull_range (ogg->sinkpad, ogg->read_offset, CHUNKSIZE, &buffer);
1479   if (ret != GST_FLOW_OK)
1480     goto error;
1481
1482   ogg->read_offset += GST_BUFFER_SIZE (buffer);
1483
1484   ret = gst_ogg_demux_submit_buffer (ogg, buffer);
1485
1486   return ret;
1487
1488   /* ERROR */
1489 boundary_reached:
1490   {
1491     GST_LOG_OBJECT (ogg, "reached boundary");
1492     return GST_FLOW_LIMIT;
1493   }
1494 eos:
1495   {
1496     GST_LOG_OBJECT (ogg, "reached EOS");
1497     return GST_FLOW_UNEXPECTED;
1498   }
1499 error:
1500   {
1501     GST_WARNING_OBJECT (ogg, "got %d (%s) from pull range", ret,
1502         gst_flow_get_name (ret));
1503     return ret;
1504   }
1505 }
1506
1507 /* Read the next page from the current offset.
1508  * boundary: number of bytes ahead we allow looking for;
1509  * -1 if no boundary
1510  *
1511  * @offset will contain the offset the next page starts at when this function
1512  * returns GST_FLOW_OK.
1513  *
1514  * GST_FLOW_UNEXPECTED is returned on EOS.
1515  *
1516  * GST_FLOW_LIMIT is returned when we did not find a page before the
1517  * boundary. If @boundary is -1, this is never returned.
1518  *
1519  * Any other error returned while retrieving data from the peer is returned as
1520  * is.
1521  */
1522 static GstFlowReturn
1523 gst_ogg_demux_get_next_page (GstOggDemux * ogg, ogg_page * og,
1524     gint64 boundary, gint64 * offset)
1525 {
1526   gint64 end_offset = -1;
1527   GstFlowReturn ret;
1528
1529   GST_LOG_OBJECT (ogg,
1530       "get next page, current offset %" G_GINT64_FORMAT ", bytes boundary %"
1531       G_GINT64_FORMAT, ogg->offset, boundary);
1532
1533   if (boundary >= 0)
1534     end_offset = ogg->offset + boundary;
1535
1536   while (TRUE) {
1537     glong more;
1538
1539     if (end_offset > 0 && ogg->offset >= end_offset)
1540       goto boundary_reached;
1541
1542     more = ogg_sync_pageseek (&ogg->sync, og);
1543
1544     GST_LOG_OBJECT (ogg, "pageseek gave %ld", more);
1545
1546     if (more < 0) {
1547       /* skipped n bytes */
1548       ogg->offset -= more;
1549       GST_LOG_OBJECT (ogg, "skipped %ld bytes, offset %" G_GINT64_FORMAT,
1550           more, ogg->offset);
1551     } else if (more == 0) {
1552       /* we need more data */
1553       if (boundary == 0)
1554         goto boundary_reached;
1555
1556       GST_LOG_OBJECT (ogg, "need more data");
1557       ret = gst_ogg_demux_get_data (ogg, end_offset);
1558       if (ret != GST_FLOW_OK)
1559         break;
1560     } else {
1561       gint64 res_offset = ogg->offset;
1562
1563       /* got a page.  Return the offset at the page beginning,
1564          advance the internal offset past the page end */
1565       if (offset)
1566         *offset = res_offset;
1567       ret = GST_FLOW_OK;
1568
1569       ogg->offset += more;
1570
1571       GST_LOG_OBJECT (ogg,
1572           "got page at %" G_GINT64_FORMAT ", serial %08x, end at %"
1573           G_GINT64_FORMAT ", granule %" G_GINT64_FORMAT, res_offset,
1574           ogg_page_serialno (og), ogg->offset,
1575           (gint64) ogg_page_granulepos (og));
1576       break;
1577     }
1578   }
1579   GST_LOG_OBJECT (ogg, "returning %d", ret);
1580
1581   return ret;
1582
1583   /* ERRORS */
1584 boundary_reached:
1585   {
1586     GST_LOG_OBJECT (ogg,
1587         "offset %" G_GINT64_FORMAT " >= end_offset %" G_GINT64_FORMAT,
1588         ogg->offset, end_offset);
1589     return GST_FLOW_LIMIT;
1590   }
1591 }
1592
1593 /* from the current offset, find the previous page, seeking backwards
1594  * until we find the page. 
1595  */
1596 static GstFlowReturn
1597 gst_ogg_demux_get_prev_page (GstOggDemux * ogg, ogg_page * og, gint64 * offset)
1598 {
1599   GstFlowReturn ret;
1600   gint64 begin = ogg->offset;
1601   gint64 end = begin;
1602   gint64 cur_offset = -1;
1603
1604   GST_LOG_OBJECT (ogg, "getting page before %" G_GINT64_FORMAT, begin);
1605
1606   while (cur_offset == -1) {
1607     begin -= CHUNKSIZE;
1608     if (begin < 0)
1609       begin = 0;
1610
1611     /* seek CHUNKSIZE back */
1612     gst_ogg_demux_seek (ogg, begin);
1613
1614     /* now continue reading until we run out of data, if we find a page
1615      * start, we save it. It might not be the final page as there could be
1616      * another page after this one. */
1617     while (ogg->offset < end) {
1618       gint64 new_offset;
1619
1620       ret =
1621           gst_ogg_demux_get_next_page (ogg, og, end - ogg->offset, &new_offset);
1622       /* we hit the upper limit, offset contains the last page start */
1623       if (ret == GST_FLOW_LIMIT) {
1624         GST_LOG_OBJECT (ogg, "hit limit");
1625         break;
1626       }
1627       /* something went wrong */
1628       if (ret == GST_FLOW_UNEXPECTED) {
1629         new_offset = 0;
1630         GST_LOG_OBJECT (ogg, "got unexpected");
1631       } else if (ret != GST_FLOW_OK) {
1632         GST_LOG_OBJECT (ogg, "got error %d", ret);
1633         return ret;
1634       }
1635
1636       GST_LOG_OBJECT (ogg, "found page at %" G_GINT64_FORMAT, new_offset);
1637
1638       /* offset is next page start */
1639       cur_offset = new_offset;
1640     }
1641   }
1642
1643   GST_LOG_OBJECT (ogg, "found previous page at %" G_GINT64_FORMAT, cur_offset);
1644
1645   /* we have the offset.  Actually snork and hold the page now */
1646   gst_ogg_demux_seek (ogg, cur_offset);
1647   ret = gst_ogg_demux_get_next_page (ogg, og, -1, NULL);
1648   if (ret != GST_FLOW_OK) {
1649     GST_WARNING_OBJECT (ogg, "can't get last page at %" G_GINT64_FORMAT,
1650         cur_offset);
1651     /* this shouldn't be possible */
1652     return ret;
1653   }
1654
1655   if (offset)
1656     *offset = cur_offset;
1657
1658   return ret;
1659 }
1660
1661 static gboolean
1662 gst_ogg_demux_deactivate_current_chain (GstOggDemux * ogg)
1663 {
1664   gint i;
1665   GstOggChain *chain = ogg->current_chain;
1666
1667   if (chain == NULL)
1668     return TRUE;
1669
1670   GST_DEBUG_OBJECT (ogg, "deactivating chain %p", chain);
1671
1672   /* send EOS on all the pads */
1673   for (i = 0; i < chain->streams->len; i++) {
1674     GstOggPad *pad = g_array_index (chain->streams, GstOggPad *, i);
1675     GstEvent *event;
1676
1677     if (!pad->added)
1678       continue;
1679
1680     event = gst_event_new_eos ();
1681     gst_event_set_seqnum (event, ogg->seqnum);
1682     gst_pad_push_event (GST_PAD_CAST (pad), event);
1683
1684     GST_DEBUG_OBJECT (ogg, "removing pad %" GST_PTR_FORMAT, pad);
1685
1686     /* deactivate first */
1687     gst_pad_set_active (GST_PAD_CAST (pad), FALSE);
1688
1689     gst_element_remove_pad (GST_ELEMENT (ogg), GST_PAD_CAST (pad));
1690
1691     pad->added = FALSE;
1692   }
1693   /* if we cannot seek back to the chain, we can destroy the chain 
1694    * completely */
1695   if (!ogg->pullmode) {
1696     gst_ogg_chain_free (chain);
1697   }
1698   ogg->current_chain = NULL;
1699
1700   return TRUE;
1701 }
1702
1703 GstCaps *
1704 gst_ogg_demux_set_header_on_caps (GstOggDemux * ogg, GstCaps * caps,
1705     GList * headers)
1706 {
1707   GstStructure *structure;
1708   GValue array = { 0 };
1709
1710   GST_LOG_OBJECT (ogg, "caps: %" GST_PTR_FORMAT, caps);
1711
1712   if (G_UNLIKELY (!caps))
1713     return NULL;
1714   if (G_UNLIKELY (!headers))
1715     return NULL;
1716
1717   caps = gst_caps_make_writable (caps);
1718   structure = gst_caps_get_structure (caps, 0);
1719
1720   g_value_init (&array, GST_TYPE_ARRAY);
1721
1722   while (headers) {
1723     GValue value = { 0 };
1724     GstBuffer *buffer;
1725     ogg_packet *op = headers->data;
1726     g_assert (op);
1727     buffer = gst_buffer_new_and_alloc (op->bytes);
1728     memcpy (GST_BUFFER_DATA (buffer), op->packet, op->bytes);
1729     GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_IN_CAPS);
1730     g_value_init (&value, GST_TYPE_BUFFER);
1731     gst_value_take_buffer (&value, buffer);
1732     gst_value_array_append_value (&array, &value);
1733     g_value_unset (&value);
1734     headers = headers->next;
1735   }
1736
1737   gst_structure_set_value (structure, "streamheader", &array);
1738   g_value_unset (&array);
1739   GST_LOG_OBJECT (ogg, "here are the newly set caps: %" GST_PTR_FORMAT, caps);
1740
1741   return caps;
1742 }
1743
1744 static gboolean
1745 gst_ogg_demux_activate_chain (GstOggDemux * ogg, GstOggChain * chain,
1746     GstEvent * event)
1747 {
1748   gint i;
1749   gint bitrate, idx_bitrate;
1750
1751   g_return_val_if_fail (chain != NULL, FALSE);
1752
1753   if (chain == ogg->current_chain) {
1754     if (event)
1755       gst_event_unref (event);
1756     return TRUE;
1757   }
1758
1759
1760   GST_DEBUG_OBJECT (ogg, "activating chain %p", chain);
1761
1762   bitrate = idx_bitrate = 0;
1763
1764   /* first add the pads */
1765   for (i = 0; i < chain->streams->len; i++) {
1766     GstOggPad *pad;
1767
1768     pad = g_array_index (chain->streams, GstOggPad *, i);
1769
1770     if (pad->map.idx_bitrate)
1771       idx_bitrate = MAX (idx_bitrate, pad->map.idx_bitrate);
1772
1773     bitrate += pad->map.bitrate;
1774
1775     /* mark discont */
1776     gst_ogg_pad_mark_discont (pad);
1777     pad->last_ret = GST_FLOW_OK;
1778
1779     if (pad->map.is_skeleton || pad->added || GST_PAD_CAPS (pad) == NULL)
1780       continue;
1781
1782     GST_DEBUG_OBJECT (ogg, "adding pad %" GST_PTR_FORMAT, pad);
1783
1784     /* activate first */
1785     gst_pad_set_active (GST_PAD_CAST (pad), TRUE);
1786
1787     gst_element_add_pad (GST_ELEMENT (ogg), GST_PAD_CAST (pad));
1788     pad->added = TRUE;
1789   }
1790   /* prefer the index bitrate over the ones encoded in the streams */
1791   ogg->bitrate = (idx_bitrate ? idx_bitrate : bitrate);
1792
1793   /* after adding the new pads, remove the old pads */
1794   gst_ogg_demux_deactivate_current_chain (ogg);
1795
1796   ogg->current_chain = chain;
1797
1798   /* we are finished now */
1799   gst_element_no_more_pads (GST_ELEMENT (ogg));
1800
1801   /* FIXME, must be sent from the streaming thread */
1802   if (event) {
1803     gst_ogg_demux_send_event (ogg, event);
1804
1805     gst_element_found_tags (GST_ELEMENT_CAST (ogg),
1806         gst_tag_list_new_full (GST_TAG_CONTAINER_FORMAT, "Ogg", NULL));
1807   }
1808
1809   GST_DEBUG_OBJECT (ogg, "starting chain");
1810
1811   /* then send out any headers and queued packets */
1812   for (i = 0; i < chain->streams->len; i++) {
1813     GList *walk;
1814     GstOggPad *pad;
1815
1816     pad = g_array_index (chain->streams, GstOggPad *, i);
1817
1818     /* FIXME also streaming thread */
1819     if (pad->map.taglist) {
1820       GST_DEBUG_OBJECT (ogg, "pushing tags");
1821       gst_element_found_tags_for_pad (GST_ELEMENT_CAST (ogg),
1822           GST_PAD_CAST (pad), pad->map.taglist);
1823       pad->map.taglist = NULL;
1824     }
1825
1826     /* Set headers on caps */
1827     pad->map.caps =
1828         gst_ogg_demux_set_header_on_caps (ogg, pad->map.caps, pad->map.headers);
1829     gst_pad_set_caps (GST_PAD_CAST (pad), pad->map.caps);
1830
1831     GST_DEBUG_OBJECT (ogg, "pushing headers");
1832     /* push headers */
1833     for (walk = pad->map.headers; walk; walk = g_list_next (walk)) {
1834       ogg_packet *p = walk->data;
1835
1836       gst_ogg_demux_chain_peer (pad, p, TRUE);
1837     }
1838
1839     GST_DEBUG_OBJECT (ogg, "pushing queued buffers");
1840     /* push queued packets */
1841     for (walk = pad->map.queued; walk; walk = g_list_next (walk)) {
1842       ogg_packet *p = walk->data;
1843
1844       gst_ogg_demux_chain_peer (pad, p, TRUE);
1845       _ogg_packet_free (p);
1846     }
1847     /* and free the queued buffers */
1848     g_list_free (pad->map.queued);
1849     pad->map.queued = NULL;
1850   }
1851   return TRUE;
1852 }
1853
1854 static gboolean
1855 do_binary_search (GstOggDemux * ogg, GstOggChain * chain, gint64 begin,
1856     gint64 end, gint64 begintime, gint64 endtime, gint64 target,
1857     gint64 * offset)
1858 {
1859   gint64 best;
1860   GstFlowReturn ret;
1861   gint64 result = 0;
1862
1863   best = begin;
1864
1865   GST_DEBUG_OBJECT (ogg,
1866       "chain offset %" G_GINT64_FORMAT ", end offset %" G_GINT64_FORMAT,
1867       begin, end);
1868   GST_DEBUG_OBJECT (ogg,
1869       "chain begin time %" GST_TIME_FORMAT ", end time %" GST_TIME_FORMAT,
1870       GST_TIME_ARGS (begintime), GST_TIME_ARGS (endtime));
1871   GST_DEBUG_OBJECT (ogg, "target %" GST_TIME_FORMAT, GST_TIME_ARGS (target));
1872
1873   /* perform the seek */
1874   while (begin < end) {
1875     gint64 bisect;
1876
1877     if ((end - begin < CHUNKSIZE) || (endtime == begintime)) {
1878       bisect = begin;
1879     } else {
1880       /* take a (pretty decent) guess, avoiding overflow */
1881       gint64 rate = (end - begin) * GST_MSECOND / (endtime - begintime);
1882
1883       bisect = (target - begintime) / GST_MSECOND * rate + begin - CHUNKSIZE;
1884
1885       if (bisect <= begin)
1886         bisect = begin;
1887       GST_DEBUG_OBJECT (ogg, "Initial guess: %" G_GINT64_FORMAT, bisect);
1888     }
1889     gst_ogg_demux_seek (ogg, bisect);
1890
1891     while (begin < end) {
1892       ogg_page og;
1893
1894       GST_DEBUG_OBJECT (ogg,
1895           "after seek, bisect %" G_GINT64_FORMAT ", begin %" G_GINT64_FORMAT
1896           ", end %" G_GINT64_FORMAT, bisect, begin, end);
1897
1898       ret = gst_ogg_demux_get_next_page (ogg, &og, end - ogg->offset, &result);
1899       GST_LOG_OBJECT (ogg, "looking for next page returned %" G_GINT64_FORMAT,
1900           result);
1901
1902       if (ret == GST_FLOW_LIMIT) {
1903         /* we hit the upper limit, go back a bit */
1904         if (bisect <= begin + 1) {
1905           end = begin;          /* found it */
1906         } else {
1907           if (bisect == 0)
1908             goto seek_error;
1909
1910           bisect -= CHUNKSIZE;
1911           if (bisect <= begin)
1912             bisect = begin + 1;
1913
1914           gst_ogg_demux_seek (ogg, bisect);
1915         }
1916       } else if (ret == GST_FLOW_OK) {
1917         /* found offset of next ogg page */
1918         gint64 granulepos;
1919         GstClockTime granuletime;
1920         GstOggPad *pad;
1921
1922         /* get the granulepos */
1923         GST_LOG_OBJECT (ogg, "found next ogg page at %" G_GINT64_FORMAT,
1924             result);
1925         granulepos = ogg_page_granulepos (&og);
1926         if (granulepos == -1) {
1927           GST_LOG_OBJECT (ogg, "granulepos of next page is -1");
1928           continue;
1929         }
1930
1931         /* get the stream */
1932         pad = gst_ogg_chain_get_stream (chain, ogg_page_serialno (&og));
1933         if (pad == NULL || pad->map.is_skeleton)
1934           continue;
1935
1936         /* convert granulepos to time */
1937         granuletime = gst_ogg_stream_get_end_time_for_granulepos (&pad->map,
1938             granulepos);
1939         if (granuletime < pad->start_time)
1940           continue;
1941
1942         GST_LOG_OBJECT (ogg, "granulepos %" G_GINT64_FORMAT " maps to time %"
1943             GST_TIME_FORMAT, granulepos, GST_TIME_ARGS (granuletime));
1944
1945         granuletime -= pad->start_time;
1946         granuletime += chain->begin_time;
1947
1948         GST_DEBUG_OBJECT (ogg,
1949             "found page with granule %" G_GINT64_FORMAT " and time %"
1950             GST_TIME_FORMAT, granulepos, GST_TIME_ARGS (granuletime));
1951
1952         if (granuletime < target) {
1953           best = result;        /* raw offset of packet with granulepos */
1954           begin = ogg->offset;  /* raw offset of next page */
1955           begintime = granuletime;
1956
1957           bisect = begin;       /* *not* begin + 1 */
1958         } else {
1959           if (bisect <= begin + 1) {
1960             end = begin;        /* found it */
1961           } else {
1962             if (end == ogg->offset) {   /* we're pretty close - we'd be stuck in */
1963               end = result;
1964               bisect -= CHUNKSIZE;      /* an endless loop otherwise. */
1965               if (bisect <= begin)
1966                 bisect = begin + 1;
1967               gst_ogg_demux_seek (ogg, bisect);
1968             } else {
1969               end = result;
1970               endtime = granuletime;
1971               break;
1972             }
1973           }
1974         }
1975       } else
1976         goto seek_error;
1977     }
1978   }
1979   GST_DEBUG_OBJECT (ogg, "seeking to %" G_GINT64_FORMAT, best);
1980   gst_ogg_demux_seek (ogg, best);
1981   *offset = best;
1982
1983   return TRUE;
1984
1985   /* ERRORS */
1986 seek_error:
1987   {
1988     GST_DEBUG_OBJECT (ogg, "got a seek error");
1989     return FALSE;
1990   }
1991 }
1992
1993 static gboolean
1994 do_index_search (GstOggDemux * ogg, GstOggChain * chain, gint64 begin,
1995     gint64 end, gint64 begintime, gint64 endtime, gint64 target,
1996     gint64 * p_offset, gint64 * p_timestamp)
1997 {
1998   guint i;
1999   guint64 timestamp, offset;
2000   guint64 r_timestamp, r_offset;
2001   gboolean result = FALSE;
2002
2003   target -= begintime;
2004
2005   r_offset = -1;
2006   r_timestamp = -1;
2007
2008   for (i = 0; i < chain->streams->len; i++) {
2009     GstOggPad *pad = g_array_index (chain->streams, GstOggPad *, i);
2010
2011     timestamp = target;
2012     if (gst_ogg_map_search_index (&pad->map, TRUE, &timestamp, &offset)) {
2013       GST_INFO ("found %" G_GUINT64_FORMAT " at offset %" G_GUINT64_FORMAT,
2014           timestamp, offset);
2015
2016       if (r_offset == -1 || offset < r_offset) {
2017         r_offset = offset;
2018         r_timestamp = timestamp;
2019       }
2020       result |= TRUE;
2021     }
2022   }
2023
2024   if (p_timestamp)
2025     *p_timestamp = r_timestamp;
2026   if (p_offset)
2027     *p_offset = r_offset;
2028
2029   return result;
2030 }
2031
2032 /*
2033  * do seek to time @position, return FALSE or chain and TRUE
2034  */
2035 static gboolean
2036 gst_ogg_demux_do_seek (GstOggDemux * ogg, GstSegment * segment,
2037     gboolean accurate, gboolean keyframe, GstOggChain ** rchain)
2038 {
2039   guint64 position;
2040   GstOggChain *chain = NULL;
2041   gint64 begin, end;
2042   gint64 begintime, endtime;
2043   gint64 target, keytarget;
2044   gint64 best;
2045   gint64 total;
2046   gint64 result = 0;
2047   GstFlowReturn ret;
2048   gint i, pending, len;
2049   gboolean first_parsed_page = TRUE;
2050
2051   position = segment->last_stop;
2052
2053   /* first find the chain to search in */
2054   total = ogg->total_time;
2055   if (ogg->chains->len == 0)
2056     goto no_chains;
2057
2058   for (i = ogg->chains->len - 1; i >= 0; i--) {
2059     chain = g_array_index (ogg->chains, GstOggChain *, i);
2060     total -= chain->total_time;
2061     if (position >= total)
2062       break;
2063   }
2064
2065   /* first step, locate page containing the required data */
2066   begin = chain->offset;
2067   end = chain->end_offset;
2068   begintime = chain->begin_time;
2069   endtime = begintime + chain->total_time;
2070   target = position - total + begintime;
2071
2072   if (!do_binary_search (ogg, chain, begin, end, begintime, endtime, target,
2073           &best))
2074     goto seek_error;
2075
2076   /* second step: find pages for all streams, we use the keyframe_granule to keep
2077    * track of which ones we saw. If we have seen a page for each stream we can
2078    * calculate the positions of each keyframe. */
2079   GST_DEBUG_OBJECT (ogg, "find keyframes");
2080   len = pending = chain->streams->len;
2081
2082   /* figure out where the keyframes are */
2083   keytarget = target;
2084
2085   while (TRUE) {
2086     ogg_page og;
2087     gint64 granulepos;
2088     GstOggPad *pad;
2089     GstClockTime keyframe_time, granule_time;
2090
2091     ret = gst_ogg_demux_get_next_page (ogg, &og, end - ogg->offset, &result);
2092     GST_LOG_OBJECT (ogg, "looking for next page returned %" G_GINT64_FORMAT,
2093         result);
2094     if (ret == GST_FLOW_LIMIT) {
2095       GST_LOG_OBJECT (ogg, "reached limit");
2096       break;
2097     } else if (ret != GST_FLOW_OK)
2098       goto seek_error;
2099
2100     /* get the stream */
2101     pad = gst_ogg_chain_get_stream (chain, ogg_page_serialno (&og));
2102     if (pad == NULL)
2103       continue;
2104
2105     if (pad->map.is_skeleton)
2106       goto next;
2107
2108     granulepos = ogg_page_granulepos (&og);
2109     if (granulepos == -1 || granulepos == 0) {
2110       GST_LOG_OBJECT (ogg, "granulepos of next page is -1");
2111       continue;
2112     }
2113
2114     /* we only do this the first time we pass here */
2115     if (first_parsed_page) {
2116       /* Now that we have a time reference from the page, we can check
2117        * whether all streams still have pages from here on.
2118        *
2119        * This would be more elegant before the loop, but getting the page from
2120        * there without breaking anything would be more costly */
2121       granule_time = gst_ogg_stream_get_end_time_for_granulepos (&pad->map,
2122           granulepos);
2123       for (i = 0; i < len; i++) {
2124         GstOggPad *stream = g_array_index (chain->streams, GstOggPad *, i);
2125
2126         if (stream == pad)
2127           /* we already know we have at least one page (the current one)
2128            * for this stream */
2129           continue;
2130
2131         if (granule_time > stream->map.total_time)
2132           /* we won't encounter any more pages of this stream, so we don't
2133            * try finding a key frame for it */
2134           pending--;
2135       }
2136       first_parsed_page = FALSE;
2137     }
2138
2139
2140     /* in reverse we want to go past the page with the lower timestamp */
2141     if (segment->rate < 0.0) {
2142       /* get time for this pad */
2143       granule_time = gst_ogg_stream_get_end_time_for_granulepos (&pad->map,
2144           granulepos);
2145
2146       GST_LOG_OBJECT (ogg,
2147           "looking at page with ts %" GST_TIME_FORMAT ", target %"
2148           GST_TIME_FORMAT, GST_TIME_ARGS (granule_time),
2149           GST_TIME_ARGS (target));
2150       if (granule_time < target)
2151         continue;
2152     }
2153
2154     /* we've seen this pad before */
2155     if (pad->keyframe_granule != -1)
2156       continue;
2157
2158     /* convert granule of this pad to the granule of the keyframe */
2159     pad->keyframe_granule =
2160         gst_ogg_stream_granulepos_to_key_granule (&pad->map, granulepos);
2161     GST_LOG_OBJECT (ogg, "marking stream granule %" G_GINT64_FORMAT,
2162         pad->keyframe_granule);
2163
2164     /* get time of the keyframe */
2165     keyframe_time =
2166         gst_ogg_stream_granule_to_time (&pad->map, pad->keyframe_granule);
2167     GST_LOG_OBJECT (ogg, "stream %08lx granule time %" GST_TIME_FORMAT,
2168         pad->map.serialno, GST_TIME_ARGS (keyframe_time));
2169
2170     /* collect smallest value */
2171     if (keyframe_time != -1) {
2172       keyframe_time += begintime;
2173       if (keyframe_time < keytarget)
2174         keytarget = keyframe_time;
2175     }
2176
2177   next:
2178     pending--;
2179     if (pending == 0)
2180       break;
2181   }
2182
2183   /* for negative rates we will get to the keyframe backwards */
2184   if (segment->rate < 0.0)
2185     goto done;
2186
2187   if (keytarget != target) {
2188     GST_LOG_OBJECT (ogg, "final seek to target %" GST_TIME_FORMAT,
2189         GST_TIME_ARGS (keytarget));
2190
2191     /* last step, seek to the location of the keyframe */
2192     if (!do_binary_search (ogg, chain, begin, end, begintime, endtime,
2193             keytarget, &best))
2194       goto seek_error;
2195   } else {
2196     /* seek back to previous position */
2197     GST_LOG_OBJECT (ogg, "keyframe on target");
2198     gst_ogg_demux_seek (ogg, best);
2199   }
2200
2201 done:
2202   if (keyframe) {
2203     if (segment->rate > 0.0)
2204       segment->time = keytarget;
2205     segment->last_stop = keytarget - begintime;
2206   }
2207
2208   *rchain = chain;
2209
2210   return TRUE;
2211
2212 no_chains:
2213   {
2214     GST_DEBUG_OBJECT (ogg, "no chains");
2215     return FALSE;
2216   }
2217 seek_error:
2218   {
2219     GST_DEBUG_OBJECT (ogg, "got a seek error");
2220     return FALSE;
2221   }
2222 }
2223
2224 /* does not take ownership of the event */
2225 static gboolean
2226 gst_ogg_demux_perform_seek_pull (GstOggDemux * ogg, GstEvent * event)
2227 {
2228   GstOggChain *chain = NULL;
2229   gboolean res;
2230   gboolean flush, accurate, keyframe;
2231   GstFormat format;
2232   gdouble rate;
2233   GstSeekFlags flags;
2234   GstSeekType cur_type, stop_type;
2235   gint64 cur, stop;
2236   gboolean update;
2237   guint32 seqnum;
2238   GstEvent *tevent;
2239
2240   if (event) {
2241     GST_DEBUG_OBJECT (ogg, "seek with event");
2242
2243     gst_event_parse_seek (event, &rate, &format, &flags,
2244         &cur_type, &cur, &stop_type, &stop);
2245
2246     /* we can only seek on time */
2247     if (format != GST_FORMAT_TIME) {
2248       GST_DEBUG_OBJECT (ogg, "can only seek on TIME");
2249       goto error;
2250     }
2251     seqnum = gst_event_get_seqnum (event);
2252   } else {
2253     GST_DEBUG_OBJECT (ogg, "seek without event");
2254
2255     flags = 0;
2256     rate = 1.0;
2257     seqnum = gst_util_seqnum_next ();
2258   }
2259
2260   GST_DEBUG_OBJECT (ogg, "seek, rate %g", rate);
2261
2262   flush = flags & GST_SEEK_FLAG_FLUSH;
2263   accurate = flags & GST_SEEK_FLAG_ACCURATE;
2264   keyframe = flags & GST_SEEK_FLAG_KEY_UNIT;
2265
2266   /* first step is to unlock the streaming thread if it is
2267    * blocked in a chain call, we do this by starting the flush. because
2268    * we cannot yet hold any streaming lock, we have to protect the chains
2269    * with their own lock. */
2270   if (flush) {
2271     gint i;
2272
2273     tevent = gst_event_new_flush_start ();
2274     gst_event_set_seqnum (tevent, seqnum);
2275
2276     gst_event_ref (tevent);
2277     gst_pad_push_event (ogg->sinkpad, tevent);
2278
2279     GST_CHAIN_LOCK (ogg);
2280     for (i = 0; i < ogg->chains->len; i++) {
2281       GstOggChain *chain = g_array_index (ogg->chains, GstOggChain *, i);
2282       gint j;
2283
2284       for (j = 0; j < chain->streams->len; j++) {
2285         GstOggPad *pad = g_array_index (chain->streams, GstOggPad *, j);
2286
2287         gst_event_ref (tevent);
2288         gst_pad_push_event (GST_PAD (pad), tevent);
2289       }
2290     }
2291     GST_CHAIN_UNLOCK (ogg);
2292
2293     gst_event_unref (tevent);
2294   } else {
2295     gst_pad_pause_task (ogg->sinkpad);
2296   }
2297
2298   /* now grab the stream lock so that streaming cannot continue, for
2299    * non flushing seeks when the element is in PAUSED this could block
2300    * forever. */
2301   GST_PAD_STREAM_LOCK (ogg->sinkpad);
2302
2303   if (ogg->segment_running && !flush) {
2304     /* create the segment event to close the current segment */
2305     if ((chain = ogg->current_chain)) {
2306       GstEvent *newseg;
2307       gint64 chain_start = 0;
2308
2309       if (chain->segment_start != GST_CLOCK_TIME_NONE)
2310         chain_start = chain->segment_start;
2311
2312       newseg = gst_event_new_new_segment (TRUE, ogg->segment.rate,
2313           GST_FORMAT_TIME, ogg->segment.start + chain_start,
2314           ogg->segment.last_stop + chain_start, ogg->segment.time);
2315       /* set the seqnum of the running segment */
2316       gst_event_set_seqnum (newseg, ogg->seqnum);
2317
2318       /* send segment on old chain, FIXME, must be sent from streaming thread. */
2319       gst_ogg_demux_send_event (ogg, newseg);
2320     }
2321   }
2322
2323   if (event) {
2324     gst_segment_set_seek (&ogg->segment, rate, format, flags,
2325         cur_type, cur, stop_type, stop, &update);
2326   }
2327
2328   GST_DEBUG_OBJECT (ogg, "segment positions set to %" GST_TIME_FORMAT "-%"
2329       GST_TIME_FORMAT, GST_TIME_ARGS (ogg->segment.start),
2330       GST_TIME_ARGS (ogg->segment.stop));
2331
2332   /* we need to stop flushing on the srcpad as we're going to use it
2333    * next. We can do this as we have the STREAM lock now. */
2334   if (flush) {
2335     tevent = gst_event_new_flush_stop ();
2336     gst_event_set_seqnum (tevent, seqnum);
2337     gst_pad_push_event (ogg->sinkpad, tevent);
2338   }
2339
2340   {
2341     gint i;
2342
2343     /* reset all ogg streams now, need to do this from within the lock to
2344      * make sure the streaming thread is not messing with the stream */
2345     for (i = 0; i < ogg->chains->len; i++) {
2346       GstOggChain *chain = g_array_index (ogg->chains, GstOggChain *, i);
2347
2348       gst_ogg_chain_reset (chain);
2349     }
2350   }
2351
2352   /* for reverse we will already seek accurately */
2353   res = gst_ogg_demux_do_seek (ogg, &ogg->segment, accurate, keyframe, &chain);
2354
2355   /* seek failed, make sure we continue the current chain */
2356   if (!res) {
2357     GST_DEBUG_OBJECT (ogg, "seek failed");
2358     chain = ogg->current_chain;
2359   } else {
2360     GST_DEBUG_OBJECT (ogg, "seek success");
2361   }
2362
2363   if (!chain)
2364     goto no_chain;
2365
2366   /* now we have a new position, prepare for streaming again */
2367   {
2368     GstEvent *event;
2369     gint64 stop;
2370     gint64 start;
2371     gint64 last_stop, begin_time;
2372
2373     /* we have to send the flush to the old chain, not the new one */
2374     if (flush) {
2375       tevent = gst_event_new_flush_stop ();
2376       gst_event_set_seqnum (tevent, seqnum);
2377       gst_ogg_demux_send_event (ogg, tevent);
2378     }
2379
2380     /* we need this to see how far inside the chain we need to start */
2381     if (chain->begin_time != GST_CLOCK_TIME_NONE)
2382       begin_time = chain->begin_time;
2383     else
2384       begin_time = 0;
2385
2386     /* segment.start gives the start over all chains, we calculate the amount
2387      * of time into this chain we need to start */
2388     start = ogg->segment.start - begin_time;
2389     if (chain->segment_start != GST_CLOCK_TIME_NONE)
2390       start += chain->segment_start;
2391
2392     if ((stop = ogg->segment.stop) == -1)
2393       stop = ogg->segment.duration;
2394
2395     /* segment.stop gives the stop time over all chains, calculate the amount of
2396      * time we need to stop in this chain */
2397     if (stop != -1) {
2398       if (stop > begin_time)
2399         stop -= begin_time;
2400       else
2401         stop = 0;
2402       stop += chain->segment_start;
2403       /* we must stop when this chain ends and switch to the next chain to play
2404        * the remainder of the segment. */
2405       stop = MIN (stop, chain->segment_stop);
2406     }
2407
2408     last_stop = ogg->segment.last_stop;
2409     if (chain->segment_start != GST_CLOCK_TIME_NONE)
2410       last_stop += chain->segment_start;
2411
2412     /* create the segment event we are going to send out */
2413     if (ogg->segment.rate >= 0.0)
2414       event = gst_event_new_new_segment (FALSE, ogg->segment.rate,
2415           ogg->segment.format, last_stop, stop, ogg->segment.time);
2416     else
2417       event = gst_event_new_new_segment (FALSE, ogg->segment.rate,
2418           ogg->segment.format, start, last_stop, ogg->segment.time);
2419
2420     gst_event_set_seqnum (event, seqnum);
2421
2422     if (chain != ogg->current_chain) {
2423       /* switch to different chain, send segment on new chain */
2424       gst_ogg_demux_activate_chain (ogg, chain, event);
2425     } else {
2426       /* mark discont and send segment on current chain */
2427       gst_ogg_chain_mark_discont (chain);
2428       /* This event should be sent from the streaming thread (sink pad task) */
2429       if (ogg->newsegment)
2430         gst_event_unref (ogg->newsegment);
2431       ogg->newsegment = event;
2432     }
2433
2434     /* notify start of new segment */
2435     if (ogg->segment.flags & GST_SEEK_FLAG_SEGMENT) {
2436       GstMessage *message;
2437
2438       message = gst_message_new_segment_start (GST_OBJECT (ogg),
2439           GST_FORMAT_TIME, ogg->segment.last_stop);
2440       gst_message_set_seqnum (message, seqnum);
2441
2442       gst_element_post_message (GST_ELEMENT (ogg), message);
2443     }
2444
2445     ogg->segment_running = TRUE;
2446     ogg->seqnum = seqnum;
2447     /* restart our task since it might have been stopped when we did the 
2448      * flush. */
2449     gst_pad_start_task (ogg->sinkpad, (GstTaskFunction) gst_ogg_demux_loop,
2450         ogg->sinkpad);
2451   }
2452
2453   /* streaming can continue now */
2454   GST_PAD_STREAM_UNLOCK (ogg->sinkpad);
2455
2456   return res;
2457
2458   /* ERRORS */
2459 error:
2460   {
2461     GST_DEBUG_OBJECT (ogg, "seek failed");
2462     return FALSE;
2463   }
2464 no_chain:
2465   {
2466     GST_DEBUG_OBJECT (ogg, "no chain to seek in");
2467     GST_PAD_STREAM_UNLOCK (ogg->sinkpad);
2468     return FALSE;
2469   }
2470 }
2471
2472 static gboolean
2473 gst_ogg_demux_perform_seek_push (GstOggDemux * ogg, GstEvent * event)
2474 {
2475   gint bitrate;
2476   gboolean res = TRUE;
2477   GstFormat format;
2478   gdouble rate;
2479   GstSeekFlags flags;
2480   GstSeekType start_type, stop_type;
2481   gint64 start, stop;
2482   GstEvent *sevent;
2483   GstOggChain *chain;
2484   gint64 best, best_time;
2485
2486   gst_event_parse_seek (event, &rate, &format, &flags,
2487       &start_type, &start, &stop_type, &stop);
2488
2489   if (format != GST_FORMAT_TIME) {
2490     GST_DEBUG_OBJECT (ogg, "can only seek on TIME");
2491     goto error;
2492   }
2493
2494   chain = ogg->current_chain;
2495   if (!chain)
2496     return FALSE;
2497
2498   if (do_index_search (ogg, chain, 0, -1, 0, -1, start, &best, &best_time)) {
2499     /* the index gave some result */
2500     GST_DEBUG_OBJECT (ogg,
2501         "found offset %" G_GINT64_FORMAT " with time %" G_GUINT64_FORMAT,
2502         best, best_time);
2503     start = best;
2504   } else if ((bitrate = ogg->bitrate) > 0) {
2505     /* try with bitrate convert the seek positions to bytes */
2506     if (start_type != GST_SEEK_TYPE_NONE) {
2507       start = gst_util_uint64_scale (start, bitrate, 8 * GST_SECOND);
2508     }
2509     if (stop_type != GST_SEEK_TYPE_NONE) {
2510       stop = gst_util_uint64_scale (stop, bitrate, 8 * GST_SECOND);
2511     }
2512   } else {
2513     /* we don't know */
2514     res = FALSE;
2515   }
2516
2517   if (res) {
2518     GST_DEBUG_OBJECT (ogg,
2519         "seeking to %" G_GINT64_FORMAT " - %" G_GINT64_FORMAT, start, stop);
2520     /* do seek */
2521     sevent = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags,
2522         start_type, start, stop_type, stop);
2523
2524     res = gst_pad_push_event (ogg->sinkpad, sevent);
2525   }
2526
2527   return res;
2528
2529   /* ERRORS */
2530 error:
2531   {
2532     GST_DEBUG_OBJECT (ogg, "seek failed");
2533     return FALSE;
2534   }
2535 }
2536
2537 static gboolean
2538 gst_ogg_demux_perform_seek (GstOggDemux * ogg, GstEvent * event)
2539 {
2540   gboolean res;
2541
2542   if (ogg->pullmode) {
2543     res = gst_ogg_demux_perform_seek_pull (ogg, event);
2544   } else {
2545     res = gst_ogg_demux_perform_seek_push (ogg, event);
2546   }
2547   return res;
2548 }
2549
2550
2551 /* finds each bitstream link one at a time using a bisection search
2552  * (has to begin by knowing the offset of the lb's initial page).
2553  * Recurses for each link so it can alloc the link storage after
2554  * finding them all, then unroll and fill the cache at the same time
2555  */
2556 static GstFlowReturn
2557 gst_ogg_demux_bisect_forward_serialno (GstOggDemux * ogg,
2558     gint64 begin, gint64 searched, gint64 end, GstOggChain * chain, glong m)
2559 {
2560   gint64 endsearched = end;
2561   gint64 next = end;
2562   ogg_page og;
2563   GstFlowReturn ret;
2564   gint64 offset;
2565   GstOggChain *nextchain;
2566
2567   GST_LOG_OBJECT (ogg,
2568       "bisect begin: %" G_GINT64_FORMAT ", searched: %" G_GINT64_FORMAT
2569       ", end %" G_GINT64_FORMAT ", chain: %p", begin, searched, end, chain);
2570
2571   /* the below guards against garbage seperating the last and
2572    * first pages of two links. */
2573   while (searched < endsearched) {
2574     gint64 bisect;
2575
2576     if (endsearched - searched < CHUNKSIZE) {
2577       bisect = searched;
2578     } else {
2579       bisect = (searched + endsearched) / 2;
2580     }
2581
2582     gst_ogg_demux_seek (ogg, bisect);
2583     ret = gst_ogg_demux_get_next_page (ogg, &og, -1, &offset);
2584
2585     if (ret == GST_FLOW_UNEXPECTED) {
2586       endsearched = bisect;
2587     } else if (ret == GST_FLOW_OK) {
2588       glong serial = ogg_page_serialno (&og);
2589
2590       if (!gst_ogg_chain_has_stream (chain, serial)) {
2591         endsearched = bisect;
2592         next = offset;
2593       } else {
2594         searched = offset + og.header_len + og.body_len;
2595       }
2596     } else
2597       return ret;
2598   }
2599
2600   GST_LOG_OBJECT (ogg, "current chain ends at %" G_GINT64_FORMAT, searched);
2601
2602   chain->end_offset = searched;
2603   ret = gst_ogg_demux_read_end_chain (ogg, chain);
2604   if (ret != GST_FLOW_OK)
2605     return ret;
2606
2607   GST_LOG_OBJECT (ogg, "found begin at %" G_GINT64_FORMAT, next);
2608
2609   gst_ogg_demux_seek (ogg, next);
2610   ret = gst_ogg_demux_read_chain (ogg, &nextchain);
2611   if (ret == GST_FLOW_UNEXPECTED) {
2612     nextchain = NULL;
2613     ret = GST_FLOW_OK;
2614     GST_LOG_OBJECT (ogg, "no next chain");
2615   } else if (ret != GST_FLOW_OK)
2616     goto done;
2617
2618   if (searched < end && nextchain != NULL) {
2619     ret = gst_ogg_demux_bisect_forward_serialno (ogg, next, ogg->offset,
2620         end, nextchain, m + 1);
2621     if (ret != GST_FLOW_OK)
2622       goto done;
2623   }
2624   GST_LOG_OBJECT (ogg, "adding chain %p", chain);
2625
2626   g_array_insert_val (ogg->chains, 0, chain);
2627
2628 done:
2629   return ret;
2630 }
2631
2632 /* read a chain from the ogg file. This code will
2633  * read all BOS pages and will create and return a GstOggChain 
2634  * structure with the results. 
2635  * 
2636  * This function will also read N pages from each stream in the
2637  * chain and submit them to the decoders. When the decoder has
2638  * decoded the first buffer, we know the timestamp of the first
2639  * page in the chain.
2640  */
2641 static GstFlowReturn
2642 gst_ogg_demux_read_chain (GstOggDemux * ogg, GstOggChain ** res_chain)
2643 {
2644   GstFlowReturn ret;
2645   GstOggChain *chain = NULL;
2646   gint64 offset = ogg->offset;
2647   ogg_page op;
2648   gboolean done;
2649   gint i;
2650
2651   GST_LOG_OBJECT (ogg, "reading chain at %" G_GINT64_FORMAT, offset);
2652
2653   /* first read the BOS pages, do typefind on them, create
2654    * the decoders, send data to the decoders. */
2655   while (TRUE) {
2656     GstOggPad *pad;
2657     glong serial;
2658
2659     ret = gst_ogg_demux_get_next_page (ogg, &op, -1, NULL);
2660     if (ret != GST_FLOW_OK) {
2661       GST_WARNING_OBJECT (ogg, "problem reading BOS page: ret=%d", ret);
2662       break;
2663     }
2664     if (!ogg_page_bos (&op)) {
2665       GST_WARNING_OBJECT (ogg, "page is not BOS page");
2666       /* if we did not find a chain yet, assume this is a bogus stream and
2667        * ignore it */
2668       if (!chain)
2669         ret = GST_FLOW_UNEXPECTED;
2670       break;
2671     }
2672
2673     if (chain == NULL) {
2674       chain = gst_ogg_chain_new (ogg);
2675       chain->offset = offset;
2676     }
2677
2678     serial = ogg_page_serialno (&op);
2679     if (gst_ogg_chain_get_stream (chain, serial) != NULL) {
2680       GST_WARNING_OBJECT (ogg, "found serial %08lx BOS page twice, ignoring",
2681           serial);
2682       continue;
2683     }
2684
2685     pad = gst_ogg_chain_new_stream (chain, serial);
2686     gst_ogg_pad_submit_page (pad, &op);
2687   }
2688
2689   if (ret != GST_FLOW_OK || chain == NULL) {
2690     if (ret == GST_FLOW_OK) {
2691       GST_WARNING_OBJECT (ogg, "no chain was found");
2692       ret = GST_FLOW_ERROR;
2693     } else if (ret != GST_FLOW_UNEXPECTED) {
2694       GST_WARNING_OBJECT (ogg, "failed to read chain");
2695     } else {
2696       GST_DEBUG_OBJECT (ogg, "done reading chains");
2697     }
2698     if (chain) {
2699       gst_ogg_chain_free (chain);
2700     }
2701     if (res_chain)
2702       *res_chain = NULL;
2703     return ret;
2704   }
2705
2706   chain->have_bos = TRUE;
2707   GST_LOG_OBJECT (ogg, "read bos pages, init decoder now");
2708
2709   /* now read pages until we receive a buffer from each of the
2710    * stream decoders, this will tell us the timestamp of the
2711    * first packet in the chain then */
2712
2713   /* save the offset to the first non bos page in the chain: if searching for
2714    * pad->first_time we read past the end of the chain, we'll seek back to this
2715    * position
2716    */
2717   offset = ogg->offset;
2718
2719   done = FALSE;
2720   while (!done) {
2721     glong serial;
2722     gboolean known_serial = FALSE;
2723     GstFlowReturn ret;
2724
2725     serial = ogg_page_serialno (&op);
2726     done = TRUE;
2727     for (i = 0; i < chain->streams->len; i++) {
2728       GstOggPad *pad = g_array_index (chain->streams, GstOggPad *, i);
2729
2730       GST_LOG_OBJECT (ogg, "serial %08lx time %" GST_TIME_FORMAT,
2731           pad->map.serialno, GST_TIME_ARGS (pad->start_time));
2732
2733       if (pad->map.serialno == serial) {
2734         known_serial = TRUE;
2735
2736         /* submit the page now, this will fill in the start_time when the
2737          * internal decoder finds it */
2738         gst_ogg_pad_submit_page (pad, &op);
2739
2740         if (!pad->map.is_skeleton && pad->start_time == -1
2741             && ogg_page_eos (&op)) {
2742           /* got EOS on a pad before we could find its start_time.
2743            * We have no chance of finding a start_time for every pad so
2744            * stop searching for the other start_time(s).
2745            */
2746           done = TRUE;
2747           break;
2748         }
2749       }
2750       /* the timestamp will be filled in when we submit the pages */
2751       if (!pad->map.is_sparse)
2752         done &= (pad->start_time != GST_CLOCK_TIME_NONE);
2753
2754       GST_LOG_OBJECT (ogg, "done %08lx now %d", pad->map.serialno, done);
2755     }
2756
2757     /* we read a page not belonging to the current chain: seek back to the
2758      * beginning of the chain
2759      */
2760     if (!known_serial) {
2761       GST_LOG_OBJECT (ogg, "unknown serial %08lx", serial);
2762       gst_ogg_demux_seek (ogg, offset);
2763       break;
2764     }
2765
2766     if (!done) {
2767       ret = gst_ogg_demux_get_next_page (ogg, &op, -1, NULL);
2768       if (ret != GST_FLOW_OK)
2769         break;
2770     }
2771   }
2772   GST_LOG_OBJECT (ogg, "done reading chain");
2773   /* now we can fill in the missing info using queries */
2774   for (i = 0; i < chain->streams->len; i++) {
2775     GstOggPad *pad = g_array_index (chain->streams, GstOggPad *, i);
2776
2777     if (pad->map.is_skeleton)
2778       continue;
2779
2780     pad->mode = GST_OGG_PAD_MODE_STREAMING;
2781   }
2782
2783   if (res_chain)
2784     *res_chain = chain;
2785
2786   return GST_FLOW_OK;
2787 }
2788
2789 /* read the last pages from the ogg stream to get the final
2790  * page end_offsets.
2791  */
2792 static GstFlowReturn
2793 gst_ogg_demux_read_end_chain (GstOggDemux * ogg, GstOggChain * chain)
2794 {
2795   gint64 begin = chain->end_offset;
2796   gint64 end = begin;
2797   gint64 last_granule = -1;
2798   GstOggPad *last_pad = NULL;
2799   GstFlowReturn ret;
2800   gboolean done = FALSE;
2801   ogg_page og;
2802   gint i;
2803
2804   while (!done) {
2805     begin -= CHUNKSIZE;
2806     if (begin < 0)
2807       begin = 0;
2808
2809     gst_ogg_demux_seek (ogg, begin);
2810
2811     /* now continue reading until we run out of data, if we find a page
2812      * start, we save it. It might not be the final page as there could be
2813      * another page after this one. */
2814     while (ogg->offset < end) {
2815       ret = gst_ogg_demux_get_next_page (ogg, &og, end - ogg->offset, NULL);
2816
2817       if (ret == GST_FLOW_LIMIT)
2818         break;
2819       if (ret != GST_FLOW_OK)
2820         return ret;
2821
2822       for (i = 0; i < chain->streams->len; i++) {
2823         GstOggPad *pad = g_array_index (chain->streams, GstOggPad *, i);
2824
2825         if (pad->map.is_sparse)
2826           continue;
2827
2828         if (pad->map.serialno == ogg_page_serialno (&og)) {
2829           gint64 granulepos = ogg_page_granulepos (&og);
2830
2831           if (granulepos != -1) {
2832             last_granule = granulepos;
2833             last_pad = pad;
2834             done = TRUE;
2835           }
2836           break;
2837         }
2838       }
2839     }
2840   }
2841
2842   if (last_pad) {
2843     chain->segment_stop =
2844         gst_ogg_stream_get_end_time_for_granulepos (&last_pad->map,
2845         last_granule);
2846   } else {
2847     chain->segment_stop = GST_CLOCK_TIME_NONE;
2848   }
2849
2850   GST_INFO ("segment stop %" G_GUINT64_FORMAT, chain->segment_stop);
2851
2852   return GST_FLOW_OK;
2853 }
2854
2855 /* find a pad with a given serial number
2856  */
2857 static GstOggPad *
2858 gst_ogg_demux_find_pad (GstOggDemux * ogg, glong serialno)
2859 {
2860   GstOggPad *pad;
2861   gint i;
2862
2863   /* first look in building chain if any */
2864   if (ogg->building_chain) {
2865     pad = gst_ogg_chain_get_stream (ogg->building_chain, serialno);
2866     if (pad)
2867       return pad;
2868   }
2869
2870   /* then look in current chain if any */
2871   if (ogg->current_chain) {
2872     pad = gst_ogg_chain_get_stream (ogg->current_chain, serialno);
2873     if (pad)
2874       return pad;
2875   }
2876
2877   for (i = 0; i < ogg->chains->len; i++) {
2878     GstOggChain *chain = g_array_index (ogg->chains, GstOggChain *, i);
2879
2880     pad = gst_ogg_chain_get_stream (chain, serialno);
2881     if (pad)
2882       return pad;
2883   }
2884   return NULL;
2885 }
2886
2887 /* find a chain with a given serial number
2888  */
2889 static GstOggChain *
2890 gst_ogg_demux_find_chain (GstOggDemux * ogg, glong serialno)
2891 {
2892   GstOggPad *pad;
2893
2894   pad = gst_ogg_demux_find_pad (ogg, serialno);
2895   if (pad) {
2896     return pad->chain;
2897   }
2898   return NULL;
2899 }
2900
2901 /* returns TRUE if all streams have valid start time */
2902 static gboolean
2903 gst_ogg_demux_collect_chain_info (GstOggDemux * ogg, GstOggChain * chain)
2904 {
2905   gboolean res = TRUE;
2906
2907   chain->total_time = GST_CLOCK_TIME_NONE;
2908   GST_DEBUG_OBJECT (ogg, "trying to collect chain info");
2909
2910   /* see if we have a start time on all streams */
2911   chain->segment_start = gst_ogg_demux_collect_start_time (ogg, chain);
2912
2913   if (chain->segment_start == G_MAXUINT64) {
2914     /* not yet, stream some more data */
2915     res = FALSE;
2916   } else if (chain->segment_stop != GST_CLOCK_TIME_NONE) {
2917     /* we can calculate a total time */
2918     chain->total_time = chain->segment_stop - chain->segment_start;
2919   }
2920
2921   GST_DEBUG ("total time %" G_GUINT64_FORMAT, chain->total_time);
2922
2923   GST_DEBUG_OBJECT (ogg, "return %d", res);
2924
2925   return res;
2926 }
2927
2928 static void
2929 gst_ogg_demux_collect_info (GstOggDemux * ogg)
2930 {
2931   gint i;
2932
2933   /* collect all info */
2934   ogg->total_time = 0;
2935
2936   for (i = 0; i < ogg->chains->len; i++) {
2937     GstOggChain *chain = g_array_index (ogg->chains, GstOggChain *, i);
2938
2939     chain->begin_time = ogg->total_time;
2940
2941     gst_ogg_demux_collect_chain_info (ogg, chain);
2942
2943     ogg->total_time += chain->total_time;
2944   }
2945   gst_segment_set_duration (&ogg->segment, GST_FORMAT_TIME, ogg->total_time);
2946 }
2947
2948 /* find all the chains in the ogg file, this reads the first and
2949  * last page of the ogg stream, if they match then the ogg file has
2950  * just one chain, else we do a binary search for all chains.
2951  */
2952 static GstFlowReturn
2953 gst_ogg_demux_find_chains (GstOggDemux * ogg)
2954 {
2955   ogg_page og;
2956   GstPad *peer;
2957   GstFormat format;
2958   gboolean res;
2959   gulong serialno;
2960   GstOggChain *chain;
2961   GstFlowReturn ret;
2962
2963   /* get peer to figure out length */
2964   if ((peer = gst_pad_get_peer (ogg->sinkpad)) == NULL)
2965     goto no_peer;
2966
2967   /* find length to read last page, we store this for later use. */
2968   format = GST_FORMAT_BYTES;
2969   res = gst_pad_query_duration (peer, &format, &ogg->length);
2970   gst_object_unref (peer);
2971   if (!res || ogg->length <= 0)
2972     goto no_length;
2973
2974   GST_DEBUG_OBJECT (ogg, "file length %" G_GINT64_FORMAT, ogg->length);
2975
2976   /* read chain from offset 0, this is the first chain of the
2977    * ogg file. */
2978   gst_ogg_demux_seek (ogg, 0);
2979   ret = gst_ogg_demux_read_chain (ogg, &chain);
2980   if (ret != GST_FLOW_OK)
2981     goto no_first_chain;
2982
2983   /* read page from end offset, we use this page to check if its serial
2984    * number is contained in the first chain. If this is the case then
2985    * this ogg is not a chained ogg and we can skip the scanning. */
2986   gst_ogg_demux_seek (ogg, ogg->length);
2987   ret = gst_ogg_demux_get_prev_page (ogg, &og, NULL);
2988   if (ret != GST_FLOW_OK)
2989     goto no_last_page;
2990
2991   serialno = ogg_page_serialno (&og);
2992
2993   if (!gst_ogg_chain_has_stream (chain, serialno)) {
2994     /* the last page is not in the first stream, this means we should
2995      * find all the chains in this chained ogg. */
2996     ret =
2997         gst_ogg_demux_bisect_forward_serialno (ogg, 0, 0, ogg->length, chain,
2998         0);
2999   } else {
3000     /* we still call this function here but with an empty range so that
3001      * we can reuse the setup code in this routine. */
3002     ret =
3003         gst_ogg_demux_bisect_forward_serialno (ogg, 0, ogg->length,
3004         ogg->length, chain, 0);
3005   }
3006   if (ret != GST_FLOW_OK)
3007     goto done;
3008
3009   /* all fine, collect and print */
3010   gst_ogg_demux_collect_info (ogg);
3011
3012   /* dump our chains and streams */
3013   gst_ogg_print (ogg);
3014
3015 done:
3016   return ret;
3017
3018   /*** error cases ***/
3019 no_peer:
3020   {
3021     GST_ELEMENT_ERROR (ogg, STREAM, DEMUX, (NULL), ("we don't have a peer"));
3022     return GST_FLOW_NOT_LINKED;
3023   }
3024 no_length:
3025   {
3026     GST_ELEMENT_ERROR (ogg, STREAM, DEMUX, (NULL), ("can't get file length"));
3027     return GST_FLOW_NOT_SUPPORTED;
3028   }
3029 no_first_chain:
3030   {
3031     GST_ELEMENT_ERROR (ogg, STREAM, DEMUX, (NULL), ("can't get first chain"));
3032     return GST_FLOW_ERROR;
3033   }
3034 no_last_page:
3035   {
3036     GST_DEBUG_OBJECT (ogg, "can't get last page");
3037     if (chain)
3038       gst_ogg_chain_free (chain);
3039     return ret;
3040   }
3041 }
3042
3043 static GstFlowReturn
3044 gst_ogg_demux_handle_page (GstOggDemux * ogg, ogg_page * page)
3045 {
3046   GstOggPad *pad;
3047   gint64 granule;
3048   glong serialno;
3049   GstFlowReturn result = GST_FLOW_OK;
3050
3051   serialno = ogg_page_serialno (page);
3052   granule = ogg_page_granulepos (page);
3053
3054   GST_LOG_OBJECT (ogg,
3055       "processing ogg page (serial %08lx, pageno %ld, granulepos %"
3056       G_GINT64_FORMAT ", bos %d)",
3057       serialno, ogg_page_pageno (page), granule, ogg_page_bos (page));
3058
3059   if (ogg_page_bos (page)) {
3060     GstOggChain *chain;
3061
3062     /* first page */
3063     /* see if we know about the chain already */
3064     chain = gst_ogg_demux_find_chain (ogg, serialno);
3065     if (chain) {
3066       GstEvent *event;
3067       gint64 start = 0;
3068
3069       if (chain->segment_start != GST_CLOCK_TIME_NONE)
3070         start = chain->segment_start;
3071
3072       /* create the newsegment event we are going to send out */
3073       event = gst_event_new_new_segment (FALSE, ogg->segment.rate,
3074           GST_FORMAT_TIME, start, chain->segment_stop, chain->begin_time);
3075       gst_event_set_seqnum (event, ogg->seqnum);
3076
3077       GST_DEBUG_OBJECT (ogg,
3078           "segment: start %" GST_TIME_FORMAT ", stop %" GST_TIME_FORMAT
3079           ", time %" GST_TIME_FORMAT, GST_TIME_ARGS (start),
3080           GST_TIME_ARGS (chain->segment_stop),
3081           GST_TIME_ARGS (chain->begin_time));
3082
3083       /* activate it as it means we have a non-header, this will also deactivate
3084        * the currently running chain. */
3085       gst_ogg_demux_activate_chain (ogg, chain, event);
3086       pad = gst_ogg_demux_find_pad (ogg, serialno);
3087     } else {
3088       GstClockTime chain_time;
3089       GstOggChain *current_chain;
3090       gint64 current_time;
3091
3092       /* this can only happen in push mode */
3093       if (ogg->pullmode)
3094         goto unknown_chain;
3095
3096       current_chain = ogg->current_chain;
3097       current_time = ogg->segment.last_stop;
3098
3099       /* time of new chain is current time */
3100       chain_time = current_time;
3101
3102       if (ogg->building_chain == NULL) {
3103         GstOggChain *newchain;
3104
3105         newchain = gst_ogg_chain_new (ogg);
3106         newchain->offset = 0;
3107         /* set new chain begin time aligned with end time of old chain */
3108         newchain->begin_time = chain_time;
3109         GST_DEBUG_OBJECT (ogg, "new chain, begin time %" GST_TIME_FORMAT,
3110             GST_TIME_ARGS (chain_time));
3111
3112         /* and this is the one we are building now */
3113         ogg->building_chain = newchain;
3114       }
3115       pad = gst_ogg_chain_new_stream (ogg->building_chain, serialno);
3116     }
3117   } else {
3118     pad = gst_ogg_demux_find_pad (ogg, serialno);
3119   }
3120   if (pad) {
3121     result = gst_ogg_pad_submit_page (pad, page);
3122   } else {
3123     /* no pad. This means an ogg page without bos has been seen for this
3124      * serialno. we just ignore it but post a warning... */
3125     GST_ELEMENT_WARNING (ogg, STREAM, DECODE,
3126         (NULL), ("unknown ogg pad for serial %08lx detected", serialno));
3127     return GST_FLOW_OK;
3128   }
3129   return result;
3130
3131   /* ERRORS */
3132 unknown_chain:
3133   {
3134     GST_ELEMENT_ERROR (ogg, STREAM, DECODE,
3135         (NULL), ("unknown ogg chain for serial %08lx detected", serialno));
3136     return GST_FLOW_ERROR;
3137   }
3138 }
3139
3140 /* streaming mode, receive a buffer, parse it, create pads for
3141  * the serialno, submit pages and packets to the oggpads
3142  */
3143 static GstFlowReturn
3144 gst_ogg_demux_chain (GstPad * pad, GstBuffer * buffer)
3145 {
3146   GstOggDemux *ogg;
3147   gint ret = 0;
3148   GstFlowReturn result = GST_FLOW_OK;
3149
3150   ogg = GST_OGG_DEMUX (GST_OBJECT_PARENT (pad));
3151
3152   GST_DEBUG_OBJECT (ogg, "chain");
3153   result = gst_ogg_demux_submit_buffer (ogg, buffer);
3154
3155   while (result == GST_FLOW_OK) {
3156     ogg_page page;
3157
3158     ret = ogg_sync_pageout (&ogg->sync, &page);
3159     if (ret == 0)
3160       /* need more data */
3161       break;
3162     if (ret == -1) {
3163       /* discontinuity in the pages */
3164       GST_DEBUG_OBJECT (ogg, "discont in page found, continuing");
3165     } else {
3166       result = gst_ogg_demux_handle_page (ogg, &page);
3167     }
3168   }
3169   if (ret == 0 || result == GST_FLOW_OK) {
3170     gst_ogg_demux_sync_streams (ogg);
3171   }
3172   return result;
3173 }
3174
3175 static gboolean
3176 gst_ogg_demux_send_event (GstOggDemux * ogg, GstEvent * event)
3177 {
3178   GstOggChain *chain = ogg->current_chain;
3179   gboolean res = TRUE;
3180
3181   if (chain) {
3182     gint i;
3183
3184     for (i = 0; i < chain->streams->len; i++) {
3185       GstOggPad *pad = g_array_index (chain->streams, GstOggPad *, i);
3186
3187       gst_event_ref (event);
3188       GST_DEBUG_OBJECT (pad, "Pushing event %" GST_PTR_FORMAT, event);
3189       res &= gst_pad_push_event (GST_PAD (pad), event);
3190     }
3191   }
3192   gst_event_unref (event);
3193
3194   return res;
3195 }
3196
3197 static GstFlowReturn
3198 gst_ogg_demux_combine_flows (GstOggDemux * ogg, GstOggPad * pad,
3199     GstFlowReturn ret)
3200 {
3201   GstOggChain *chain;
3202
3203   /* store the value */
3204   pad->last_ret = ret;
3205
3206   /* any other error that is not-linked can be returned right
3207    * away */
3208   if (ret != GST_FLOW_NOT_LINKED)
3209     goto done;
3210
3211   /* only return NOT_LINKED if all other pads returned NOT_LINKED */
3212   chain = ogg->current_chain;
3213   if (chain) {
3214     gint i;
3215
3216     for (i = 0; i < chain->streams->len; i++) {
3217       GstOggPad *opad = g_array_index (chain->streams, GstOggPad *, i);
3218
3219       ret = opad->last_ret;
3220       /* some other return value (must be SUCCESS but we can return
3221        * other values as well) */
3222       if (ret != GST_FLOW_NOT_LINKED)
3223         goto done;
3224     }
3225     /* if we get here, all other pads were unlinked and we return
3226      * NOT_LINKED then */
3227   }
3228 done:
3229   return ret;
3230 }
3231
3232 /* returns TRUE if all streams in current chain reached EOS, FALSE otherwise */
3233 static gboolean
3234 gst_ogg_demux_check_eos (GstOggDemux * ogg)
3235 {
3236   GstOggChain *chain;
3237   gboolean eos = TRUE;
3238
3239   chain = ogg->current_chain;
3240   if (G_LIKELY (chain)) {
3241     gint i;
3242
3243     for (i = 0; i < chain->streams->len; i++) {
3244       GstOggPad *opad = g_array_index (chain->streams, GstOggPad *, i);
3245
3246       eos = eos && opad->is_eos;
3247     }
3248   } else {
3249     eos = FALSE;
3250   }
3251
3252   return eos;
3253 }
3254
3255 static GstFlowReturn
3256 gst_ogg_demux_loop_forward (GstOggDemux * ogg)
3257 {
3258   GstFlowReturn ret;
3259   GstBuffer *buffer;
3260
3261   if (ogg->offset == ogg->length) {
3262     GST_LOG_OBJECT (ogg, "no more data to pull %" G_GINT64_FORMAT
3263         " == %" G_GINT64_FORMAT, ogg->offset, ogg->length);
3264     ret = GST_FLOW_UNEXPECTED;
3265     goto done;
3266   }
3267
3268   GST_LOG_OBJECT (ogg, "pull data %" G_GINT64_FORMAT, ogg->offset);
3269   ret = gst_pad_pull_range (ogg->sinkpad, ogg->offset, CHUNKSIZE, &buffer);
3270   if (ret != GST_FLOW_OK) {
3271     GST_LOG_OBJECT (ogg, "Failed pull_range");
3272     goto done;
3273   }
3274
3275   ogg->offset += GST_BUFFER_SIZE (buffer);
3276
3277   if (G_UNLIKELY (ogg->newsegment)) {
3278     gst_ogg_demux_send_event (ogg, ogg->newsegment);
3279     ogg->newsegment = NULL;
3280   }
3281
3282   ret = gst_ogg_demux_chain (ogg->sinkpad, buffer);
3283   if (ret != GST_FLOW_OK) {
3284     GST_LOG_OBJECT (ogg, "Failed demux_chain");
3285     goto done;
3286   }
3287
3288   /* check for the end of the segment */
3289   if (gst_ogg_demux_check_eos (ogg)) {
3290     GST_LOG_OBJECT (ogg, "got EOS");
3291     ret = GST_FLOW_UNEXPECTED;
3292     goto done;
3293   }
3294 done:
3295   return ret;
3296 }
3297
3298 /* reverse mode.
3299  *
3300  * We read the pages backwards and send the packets forwards. The first packet
3301  * in the page will be pushed with the DISCONT flag set.
3302  *
3303  * Special care has to be taken for continued pages, which we can only decode
3304  * when we have the previous page(s).
3305  */
3306 static GstFlowReturn
3307 gst_ogg_demux_loop_reverse (GstOggDemux * ogg)
3308 {
3309   GstFlowReturn ret;
3310   ogg_page page;
3311   gint64 offset;
3312
3313   if (ogg->offset == 0) {
3314     GST_LOG_OBJECT (ogg, "no more data to pull %" G_GINT64_FORMAT
3315         " == 0", ogg->offset);
3316     ret = GST_FLOW_UNEXPECTED;
3317     goto done;
3318   }
3319
3320   GST_LOG_OBJECT (ogg, "read page from %" G_GINT64_FORMAT, ogg->offset);
3321   ret = gst_ogg_demux_get_prev_page (ogg, &page, &offset);
3322   if (ret != GST_FLOW_OK)
3323     goto done;
3324
3325   ogg->offset = offset;
3326
3327   if (G_UNLIKELY (ogg->newsegment)) {
3328     gst_ogg_demux_send_event (ogg, ogg->newsegment);
3329     ogg->newsegment = NULL;
3330   }
3331
3332   ret = gst_ogg_demux_handle_page (ogg, &page);
3333   if (ret != GST_FLOW_OK)
3334     goto done;
3335
3336   /* check for the end of the segment */
3337   if (gst_ogg_demux_check_eos (ogg)) {
3338     GST_LOG_OBJECT (ogg, "got EOS");
3339     ret = GST_FLOW_UNEXPECTED;
3340     goto done;
3341   }
3342 done:
3343   return ret;
3344 }
3345
3346 static void
3347 gst_ogg_demux_sync_streams (GstOggDemux * ogg)
3348 {
3349   GstClockTime cur;
3350   GstOggChain *chain;
3351   guint i;
3352
3353   chain = ogg->current_chain;
3354   cur = ogg->segment.last_stop;
3355   if (chain == NULL || cur == -1)
3356     return;
3357
3358   for (i = 0; i < chain->streams->len; i++) {
3359     GstOggPad *stream = g_array_index (chain->streams, GstOggPad *, i);
3360
3361     /* Theoretically, we should be doing this for all streams, but we're only
3362      * doing it for known-to-be-sparse streams at the moment in order not to
3363      * break things for wrongly-muxed streams (like we used to produce once) */
3364     if (stream->map.is_sparse && stream->last_stop != GST_CLOCK_TIME_NONE) {
3365
3366       /* Does this stream lag? Random threshold of 2 seconds */
3367       if (GST_CLOCK_DIFF (stream->last_stop, cur) > (2 * GST_SECOND)) {
3368         GST_DEBUG_OBJECT (stream, "synchronizing stream with others by "
3369             "advancing time from %" GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
3370             GST_TIME_ARGS (stream->last_stop), GST_TIME_ARGS (cur));
3371         stream->last_stop = cur;
3372         /* advance stream time (FIXME: is this right, esp. time_pos?) */
3373         gst_pad_push_event (GST_PAD_CAST (stream),
3374             gst_event_new_new_segment (TRUE, ogg->segment.rate,
3375                 GST_FORMAT_TIME, stream->last_stop, -1, stream->last_stop));
3376       }
3377     }
3378   }
3379 }
3380
3381 /* random access code
3382  *
3383  * - first find all the chains and streams by scanning the file.
3384  * - then get and chain buffers, just like the streaming case.
3385  * - when seeking, we can use the chain info to perform the seek.
3386  */
3387 static void
3388 gst_ogg_demux_loop (GstOggPad * pad)
3389 {
3390   GstOggDemux *ogg;
3391   GstFlowReturn ret;
3392   GstEvent *event;
3393
3394   ogg = GST_OGG_DEMUX (GST_OBJECT_PARENT (pad));
3395
3396   if (ogg->need_chains) {
3397     gboolean res;
3398
3399     /* this is the only place where we write chains and thus need to lock. */
3400     GST_CHAIN_LOCK (ogg);
3401     ret = gst_ogg_demux_find_chains (ogg);
3402     GST_CHAIN_UNLOCK (ogg);
3403     if (ret != GST_FLOW_OK)
3404       goto chain_read_failed;
3405
3406     ogg->need_chains = FALSE;
3407
3408     GST_OBJECT_LOCK (ogg);
3409     ogg->running = TRUE;
3410     event = ogg->event;
3411     ogg->event = NULL;
3412     GST_OBJECT_UNLOCK (ogg);
3413
3414     /* and seek to configured positions without FLUSH */
3415     res = gst_ogg_demux_perform_seek_pull (ogg, event);
3416     if (event)
3417       gst_event_unref (event);
3418
3419     if (!res)
3420       goto seek_failed;
3421   }
3422
3423   if (ogg->segment.rate >= 0.0)
3424     ret = gst_ogg_demux_loop_forward (ogg);
3425   else
3426     ret = gst_ogg_demux_loop_reverse (ogg);
3427
3428   if (ret != GST_FLOW_OK)
3429     goto pause;
3430
3431   gst_ogg_demux_sync_streams (ogg);
3432   return;
3433
3434   /* ERRORS */
3435 chain_read_failed:
3436   {
3437     /* error was posted */
3438     goto pause;
3439   }
3440 seek_failed:
3441   {
3442     GST_ELEMENT_ERROR (ogg, STREAM, DEMUX, (NULL),
3443         ("failed to start demuxing ogg"));
3444     ret = GST_FLOW_ERROR;
3445     goto pause;
3446   }
3447 pause:
3448   {
3449     const gchar *reason = gst_flow_get_name (ret);
3450     GstEvent *event = NULL;
3451
3452     GST_LOG_OBJECT (ogg, "pausing task, reason %s", reason);
3453     ogg->segment_running = FALSE;
3454     gst_pad_pause_task (ogg->sinkpad);
3455
3456     if (ret == GST_FLOW_UNEXPECTED) {
3457       /* perform EOS logic */
3458       if (ogg->segment.flags & GST_SEEK_FLAG_SEGMENT) {
3459         gint64 stop;
3460         GstMessage *message;
3461
3462         /* for segment playback we need to post when (in stream time)
3463          * we stopped, this is either stop (when set) or the duration. */
3464         if ((stop = ogg->segment.stop) == -1)
3465           stop = ogg->segment.duration;
3466
3467         GST_LOG_OBJECT (ogg, "Sending segment done, at end of segment");
3468         message =
3469             gst_message_new_segment_done (GST_OBJECT (ogg), GST_FORMAT_TIME,
3470             stop);
3471         gst_message_set_seqnum (message, ogg->seqnum);
3472
3473         gst_element_post_message (GST_ELEMENT (ogg), message);
3474       } else {
3475         /* normal playback, send EOS to all linked pads */
3476         GST_LOG_OBJECT (ogg, "Sending EOS, at end of stream");
3477         event = gst_event_new_eos ();
3478       }
3479     } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_UNEXPECTED) {
3480       GST_ELEMENT_ERROR (ogg, STREAM, FAILED,
3481           (_("Internal data stream error.")),
3482           ("stream stopped, reason %s", reason));
3483       event = gst_event_new_eos ();
3484     }
3485
3486     /* For wrong-state we still want to pause the task and stop
3487      * but no error message or other things are necessary.
3488      * wrong-state is no real error and will be caused by flushing,
3489      * e.g. because of a flushing seek.
3490      */
3491     if (event) {
3492       gst_event_set_seqnum (event, ogg->seqnum);
3493       gst_ogg_demux_send_event (ogg, event);
3494     }
3495     return;
3496   }
3497 }
3498
3499 static void
3500 gst_ogg_demux_clear_chains (GstOggDemux * ogg)
3501 {
3502   gint i;
3503
3504   gst_ogg_demux_deactivate_current_chain (ogg);
3505
3506   GST_CHAIN_LOCK (ogg);
3507   for (i = 0; i < ogg->chains->len; i++) {
3508     GstOggChain *chain = g_array_index (ogg->chains, GstOggChain *, i);
3509
3510     gst_ogg_chain_free (chain);
3511   }
3512   ogg->chains = g_array_set_size (ogg->chains, 0);
3513   GST_CHAIN_UNLOCK (ogg);
3514 }
3515
3516 /* this function is called when the pad is activated and should start
3517  * processing data.
3518  *
3519  * We check if we can do random access to decide if we work push or
3520  * pull based.
3521  */
3522 static gboolean
3523 gst_ogg_demux_sink_activate (GstPad * sinkpad)
3524 {
3525   if (gst_pad_check_pull_range (sinkpad)) {
3526     GST_DEBUG_OBJECT (sinkpad, "activating pull");
3527     return gst_pad_activate_pull (sinkpad, TRUE);
3528   } else {
3529     GST_DEBUG_OBJECT (sinkpad, "activating push");
3530     return gst_pad_activate_push (sinkpad, TRUE);
3531   }
3532 }
3533
3534 /* this function gets called when we activate ourselves in push mode.
3535  * We cannot seek (ourselves) in the stream */
3536 static gboolean
3537 gst_ogg_demux_sink_activate_push (GstPad * sinkpad, gboolean active)
3538 {
3539   GstOggDemux *ogg;
3540
3541   ogg = GST_OGG_DEMUX (GST_OBJECT_PARENT (sinkpad));
3542
3543   ogg->pullmode = FALSE;
3544   ogg->resync = FALSE;
3545
3546   return TRUE;
3547 }
3548
3549 /* this function gets called when we activate ourselves in pull mode.
3550  * We can perform  random access to the resource and we start a task
3551  * to start reading */
3552 static gboolean
3553 gst_ogg_demux_sink_activate_pull (GstPad * sinkpad, gboolean active)
3554 {
3555   GstOggDemux *ogg;
3556
3557   ogg = GST_OGG_DEMUX (GST_OBJECT_PARENT (sinkpad));
3558
3559   if (active) {
3560     ogg->need_chains = TRUE;
3561     ogg->pullmode = TRUE;
3562
3563     return gst_pad_start_task (sinkpad, (GstTaskFunction) gst_ogg_demux_loop,
3564         sinkpad);
3565   } else {
3566     return gst_pad_stop_task (sinkpad);
3567   }
3568 }
3569
3570 static GstStateChangeReturn
3571 gst_ogg_demux_change_state (GstElement * element, GstStateChange transition)
3572 {
3573   GstOggDemux *ogg;
3574   GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
3575
3576   ogg = GST_OGG_DEMUX (element);
3577
3578   switch (transition) {
3579     case GST_STATE_CHANGE_NULL_TO_READY:
3580       ogg->basetime = 0;
3581       ogg_sync_init (&ogg->sync);
3582       break;
3583     case GST_STATE_CHANGE_READY_TO_PAUSED:
3584       ogg_sync_reset (&ogg->sync);
3585       ogg->running = FALSE;
3586       ogg->bitrate = 0;
3587       ogg->segment_running = FALSE;
3588       ogg->total_time = -1;
3589       gst_segment_init (&ogg->segment, GST_FORMAT_TIME);
3590       break;
3591     case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
3592       break;
3593     default:
3594       break;
3595   }
3596
3597   result = parent_class->change_state (element, transition);
3598
3599   switch (transition) {
3600     case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
3601       break;
3602     case GST_STATE_CHANGE_PAUSED_TO_READY:
3603       gst_ogg_demux_clear_chains (ogg);
3604       GST_OBJECT_LOCK (ogg);
3605       ogg->running = FALSE;
3606       ogg->segment_running = FALSE;
3607       GST_OBJECT_UNLOCK (ogg);
3608       break;
3609     case GST_STATE_CHANGE_READY_TO_NULL:
3610       ogg_sync_clear (&ogg->sync);
3611       break;
3612     default:
3613       break;
3614   }
3615   return result;
3616 }
3617
3618 gboolean
3619 gst_ogg_demux_plugin_init (GstPlugin * plugin)
3620 {
3621   GST_DEBUG_CATEGORY_INIT (gst_ogg_demux_debug, "oggdemux", 0, "ogg demuxer");
3622   GST_DEBUG_CATEGORY_INIT (gst_ogg_demux_setup_debug, "oggdemux_setup", 0,
3623       "ogg demuxer setup stage when parsing pipeline");
3624
3625 #ifdef ENABLE_NLS
3626   GST_DEBUG ("binding text domain %s to locale dir %s", GETTEXT_PACKAGE,
3627       LOCALEDIR);
3628   bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
3629   bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
3630 #endif
3631
3632   return gst_element_register (plugin, "oggdemux", GST_RANK_PRIMARY,
3633       GST_TYPE_OGG_DEMUX);
3634 }
3635
3636 /* prints all info about the element */
3637 #undef GST_CAT_DEFAULT
3638 #define GST_CAT_DEFAULT gst_ogg_demux_setup_debug
3639
3640 #ifdef GST_DISABLE_GST_DEBUG
3641
3642 static void
3643 gst_ogg_print (GstOggDemux * ogg)
3644 {
3645   /* NOP */
3646 }
3647
3648 #else /* !GST_DISABLE_GST_DEBUG */
3649
3650 static void
3651 gst_ogg_print (GstOggDemux * ogg)
3652 {
3653   guint j, i;
3654
3655   GST_INFO_OBJECT (ogg, "%u chains", ogg->chains->len);
3656   GST_INFO_OBJECT (ogg, " total time: %" GST_TIME_FORMAT,
3657       GST_TIME_ARGS (ogg->total_time));
3658
3659   for (i = 0; i < ogg->chains->len; i++) {
3660     GstOggChain *chain = g_array_index (ogg->chains, GstOggChain *, i);
3661
3662     GST_INFO_OBJECT (ogg, " chain %d (%u streams):", i, chain->streams->len);
3663     GST_INFO_OBJECT (ogg,
3664         "  offset: %" G_GINT64_FORMAT " - %" G_GINT64_FORMAT, chain->offset,
3665         chain->end_offset);
3666     GST_INFO_OBJECT (ogg, "  begin time: %" GST_TIME_FORMAT,
3667         GST_TIME_ARGS (chain->begin_time));
3668     GST_INFO_OBJECT (ogg, "  total time: %" GST_TIME_FORMAT,
3669         GST_TIME_ARGS (chain->total_time));
3670     GST_INFO_OBJECT (ogg, "  segment start: %" GST_TIME_FORMAT,
3671         GST_TIME_ARGS (chain->segment_start));
3672     GST_INFO_OBJECT (ogg, "  segment stop:  %" GST_TIME_FORMAT,
3673         GST_TIME_ARGS (chain->segment_stop));
3674
3675     for (j = 0; j < chain->streams->len; j++) {
3676       GstOggPad *stream = g_array_index (chain->streams, GstOggPad *, j);
3677
3678       GST_INFO_OBJECT (ogg, "  stream %08lx:", stream->map.serialno);
3679       GST_INFO_OBJECT (ogg, "   start time:       %" GST_TIME_FORMAT,
3680           GST_TIME_ARGS (stream->start_time));
3681     }
3682   }
3683 }
3684 #endif /* GST_DISABLE_GST_DEBUG */