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