Merge branch 'master' into 0.11
[platform/upstream/gstreamer.git] / ext / ogg / gstoggmux.c
1 /* OGG muxer plugin for GStreamer
2  * Copyright (C) 2004 Wim Taymans <wim@fluendo.com>
3  * Copyright (C) 2006 Thomas Vander Stichele <thomas at apestaart dot org>
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public
16  * License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18  * Boston, MA 02111-1307, USA.
19  */
20
21 /**
22  * SECTION:element-oggmux
23  * @see_also: <link linkend="gst-plugins-base-plugins-oggdemux">oggdemux</link>
24  *
25  * This element merges streams (audio and video) into ogg files.
26  *
27  * <refsect2>
28  * <title>Example pipelines</title>
29  * |[
30  * gst-launch v4l2src num-buffers=500 ! video/x-raw,width=320,height=240 ! videoconvert ! theoraenc ! oggmux ! filesink location=video.ogg
31  * ]| Encodes a video stream captured from a v4l2-compatible camera to Ogg/Theora
32  * (the encoding will stop automatically after 500 frames)
33  * </refsect2>
34  *
35  * Last reviewed on 2008-02-06 (0.10.17)
36  */
37
38 #ifdef HAVE_CONFIG_H
39 #include "config.h"
40 #endif
41
42 #include <gst/gst.h>
43 #include <gst/base/gstbytewriter.h>
44 #include <gst/tag/tag.h>
45
46 #include "gstoggmux.h"
47
48 /* memcpy - if someone knows a way to get rid of it, please speak up
49  * note: the ogg docs even say you need this... */
50 #include <string.h>
51 #include <time.h>
52 #include <stdlib.h>             /* rand, srand, atoi */
53
54 GST_DEBUG_CATEGORY_STATIC (gst_ogg_mux_debug);
55 #define GST_CAT_DEFAULT gst_ogg_mux_debug
56
57 /* This isn't generally what you'd want with an end-time macro, because
58    technically the end time of a buffer with invalid duration is invalid. But
59    for sorting ogg pages this is what we want. */
60 #define GST_BUFFER_END_TIME(buf) \
61     (GST_BUFFER_DURATION_IS_VALID (buf) \
62     ? GST_BUFFER_TIMESTAMP (buf) + GST_BUFFER_DURATION (buf) \
63     : GST_BUFFER_TIMESTAMP (buf))
64
65 #define GST_GP_FORMAT "[gp %8" G_GINT64_FORMAT "]"
66 #define GST_GP_CAST(_gp) ((gint64) _gp)
67
68 typedef enum
69 {
70   GST_OGG_FLAG_BOS = GST_ELEMENT_FLAG_LAST,
71   GST_OGG_FLAG_EOS
72 }
73 GstOggFlag;
74
75 /* OggMux signals and args */
76 enum
77 {
78   /* FILL ME */
79   LAST_SIGNAL
80 };
81
82 /* set to 0.5 seconds by default */
83 #define DEFAULT_MAX_DELAY       G_GINT64_CONSTANT(500000000)
84 #define DEFAULT_MAX_PAGE_DELAY  G_GINT64_CONSTANT(500000000)
85 #define DEFAULT_MAX_TOLERANCE   G_GINT64_CONSTANT(40000000)
86 #define DEFAULT_SKELETON        FALSE
87
88 enum
89 {
90   ARG_0,
91   ARG_MAX_DELAY,
92   ARG_MAX_PAGE_DELAY,
93   ARG_MAX_TOLERANCE,
94   ARG_SKELETON
95 };
96
97 static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
98     GST_PAD_SRC,
99     GST_PAD_ALWAYS,
100     GST_STATIC_CAPS ("application/ogg")
101     );
102
103 static GstStaticPadTemplate video_sink_factory =
104     GST_STATIC_PAD_TEMPLATE ("video_%u",
105     GST_PAD_SINK,
106     GST_PAD_REQUEST,
107     GST_STATIC_CAPS ("video/x-theora; "
108         "application/x-ogm-video; video/x-dirac; "
109         "video/x-smoke; video/x-vp8; ")
110     );
111
112 static GstStaticPadTemplate audio_sink_factory =
113     GST_STATIC_PAD_TEMPLATE ("audio_%u",
114     GST_PAD_SINK,
115     GST_PAD_REQUEST,
116     GST_STATIC_CAPS
117     ("audio/x-vorbis; audio/x-flac; audio/x-speex; audio/x-celt; "
118         "application/x-ogm-audio; audio/x-opus")
119     );
120
121 static GstStaticPadTemplate subtitle_sink_factory =
122     GST_STATIC_PAD_TEMPLATE ("subtitle_%u",
123     GST_PAD_SINK,
124     GST_PAD_REQUEST,
125     GST_STATIC_CAPS ("text/x-cmml, encoded = (boolean) TRUE; "
126         "subtitle/x-kate; application/x-kate")
127     );
128
129 static void gst_ogg_mux_finalize (GObject * object);
130
131 static GstFlowReturn
132 gst_ogg_mux_collected (GstCollectPads2 * pads, GstOggMux * ogg_mux);
133 static gboolean gst_ogg_mux_handle_src_event (GstPad * pad, GstObject * parent,
134     GstEvent * event);
135 static GstPad *gst_ogg_mux_request_new_pad (GstElement * element,
136     GstPadTemplate * templ, const gchar * name, const GstCaps * caps);
137 static void gst_ogg_mux_release_pad (GstElement * element, GstPad * pad);
138
139 static void gst_ogg_mux_set_property (GObject * object,
140     guint prop_id, const GValue * value, GParamSpec * pspec);
141 static void gst_ogg_mux_get_property (GObject * object,
142     guint prop_id, GValue * value, GParamSpec * pspec);
143 static GstStateChangeReturn gst_ogg_mux_change_state (GstElement * element,
144     GstStateChange transition);
145
146 /*static guint gst_ogg_mux_signals[LAST_SIGNAL] = { 0 }; */
147 #define gst_ogg_mux_parent_class parent_class
148 G_DEFINE_TYPE_WITH_CODE (GstOggMux, gst_ogg_mux, GST_TYPE_ELEMENT,
149     G_IMPLEMENT_INTERFACE (GST_TYPE_PRESET, NULL));
150
151 static void
152 gst_ogg_mux_class_init (GstOggMuxClass * klass)
153 {
154   GObjectClass *gobject_class;
155   GstElementClass *gstelement_class;
156
157   gobject_class = (GObjectClass *) klass;
158   gstelement_class = (GstElementClass *) klass;
159
160   gobject_class->finalize = gst_ogg_mux_finalize;
161   gobject_class->get_property = gst_ogg_mux_get_property;
162   gobject_class->set_property = gst_ogg_mux_set_property;
163
164   gst_element_class_add_pad_template (gstelement_class,
165       gst_static_pad_template_get (&src_factory));
166   gst_element_class_add_pad_template (gstelement_class,
167       gst_static_pad_template_get (&video_sink_factory));
168   gst_element_class_add_pad_template (gstelement_class,
169       gst_static_pad_template_get (&audio_sink_factory));
170   gst_element_class_add_pad_template (gstelement_class,
171       gst_static_pad_template_get (&subtitle_sink_factory));
172
173   gst_element_class_set_details_simple (gstelement_class,
174       "Ogg muxer", "Codec/Muxer",
175       "mux ogg streams (info about ogg: http://xiph.org)",
176       "Wim Taymans <wim@fluendo.com>");
177
178   gstelement_class->request_new_pad = gst_ogg_mux_request_new_pad;
179   gstelement_class->release_pad = gst_ogg_mux_release_pad;
180
181   g_object_class_install_property (gobject_class, ARG_MAX_DELAY,
182       g_param_spec_uint64 ("max-delay", "Max delay",
183           "Maximum delay in multiplexing streams", 0, G_MAXUINT64,
184           DEFAULT_MAX_DELAY,
185           (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
186   g_object_class_install_property (gobject_class, ARG_MAX_PAGE_DELAY,
187       g_param_spec_uint64 ("max-page-delay", "Max page delay",
188           "Maximum delay for sending out a page", 0, G_MAXUINT64,
189           DEFAULT_MAX_PAGE_DELAY,
190           (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
191   g_object_class_install_property (gobject_class, ARG_MAX_TOLERANCE,
192       g_param_spec_uint64 ("max-tolerance", "Max time tolerance",
193           "Maximum timestamp difference for maintaining perfect granules",
194           0, G_MAXUINT64, DEFAULT_MAX_TOLERANCE,
195           (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
196   g_object_class_install_property (gobject_class, ARG_SKELETON,
197       g_param_spec_boolean ("skeleton", "Skeleton",
198           "Whether to include a Skeleton track",
199           DEFAULT_SKELETON,
200           (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
201
202   gstelement_class->change_state = gst_ogg_mux_change_state;
203
204 }
205
206 #if 0
207 static const GstEventMask *
208 gst_ogg_mux_get_sink_event_masks (GstPad * pad)
209 {
210   static const GstEventMask gst_ogg_mux_sink_event_masks[] = {
211     {GST_EVENT_EOS, 0},
212     {GST_EVENT_DISCONTINUOUS, 0},
213     {0,}
214   };
215
216   return gst_ogg_mux_sink_event_masks;
217 }
218 #endif
219
220 static void
221 gst_ogg_mux_clear (GstOggMux * ogg_mux)
222 {
223   ogg_mux->pulling = NULL;
224   ogg_mux->need_headers = TRUE;
225   ogg_mux->delta_pad = NULL;
226   ogg_mux->offset = 0;
227   ogg_mux->next_ts = 0;
228   ogg_mux->last_ts = GST_CLOCK_TIME_NONE;
229 }
230
231 static void
232 gst_ogg_mux_init (GstOggMux * ogg_mux)
233 {
234   GstElementClass *klass = GST_ELEMENT_GET_CLASS (ogg_mux);
235
236   ogg_mux->srcpad =
237       gst_pad_new_from_template (gst_element_class_get_pad_template (klass,
238           "src"), "src");
239   gst_pad_set_event_function (ogg_mux->srcpad, gst_ogg_mux_handle_src_event);
240   gst_element_add_pad (GST_ELEMENT (ogg_mux), ogg_mux->srcpad);
241
242   GST_OBJECT_FLAG_SET (GST_ELEMENT (ogg_mux), GST_OGG_FLAG_BOS);
243
244   /* seed random number generator for creation of serial numbers */
245   srand (time (NULL));
246
247   ogg_mux->collect = gst_collect_pads2_new ();
248   gst_collect_pads2_set_function (ogg_mux->collect,
249       (GstCollectPads2Function) GST_DEBUG_FUNCPTR (gst_ogg_mux_collected),
250       ogg_mux);
251
252   ogg_mux->max_delay = DEFAULT_MAX_DELAY;
253   ogg_mux->max_page_delay = DEFAULT_MAX_PAGE_DELAY;
254   ogg_mux->max_tolerance = DEFAULT_MAX_TOLERANCE;
255
256   gst_ogg_mux_clear (ogg_mux);
257 }
258
259 static void
260 gst_ogg_mux_finalize (GObject * object)
261 {
262   GstOggMux *ogg_mux;
263
264   ogg_mux = GST_OGG_MUX (object);
265
266   if (ogg_mux->collect) {
267     gst_object_unref (ogg_mux->collect);
268     ogg_mux->collect = NULL;
269   }
270
271   G_OBJECT_CLASS (parent_class)->finalize (object);
272 }
273
274 static void
275 gst_ogg_mux_ogg_pad_destroy_notify (GstCollectData2 * data)
276 {
277   GstOggPadData *oggpad = (GstOggPadData *) data;
278   GstBuffer *buf;
279
280   ogg_stream_clear (&oggpad->map.stream);
281   gst_caps_replace (&oggpad->map.caps, NULL);
282
283   if (oggpad->pagebuffers) {
284     while ((buf = g_queue_pop_head (oggpad->pagebuffers)) != NULL) {
285       gst_buffer_unref (buf);
286     }
287     g_queue_free (oggpad->pagebuffers);
288     oggpad->pagebuffers = NULL;
289   }
290 }
291
292 static GstPadLinkReturn
293 gst_ogg_mux_sinkconnect (GstPad * pad, GstPad * peer)
294 {
295   GstOggMux *ogg_mux;
296
297   ogg_mux = GST_OGG_MUX (gst_pad_get_parent (pad));
298
299   GST_DEBUG_OBJECT (ogg_mux, "sinkconnect triggered on %s", GST_PAD_NAME (pad));
300
301   gst_object_unref (ogg_mux);
302
303   return GST_PAD_LINK_OK;
304 }
305
306 static gboolean
307 gst_ogg_mux_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
308 {
309   GstOggMux *ogg_mux = GST_OGG_MUX (parent);
310   GstOggPadData *ogg_pad = (GstOggPadData *) gst_pad_get_element_private (pad);
311   gboolean ret = FALSE;
312
313   GST_DEBUG_OBJECT (pad, "Got %s event", GST_EVENT_TYPE_NAME (event));
314
315   switch (GST_EVENT_TYPE (event)) {
316     case GST_EVENT_SEGMENT:
317     {
318       const GstSegment *segment;
319
320       gst_event_parse_segment (event, &segment);
321
322       /* We don't support non time NEWSEGMENT events */
323       if (segment->format != GST_FORMAT_TIME) {
324         gst_event_unref (event);
325         event = NULL;
326         break;
327       }
328
329       gst_segment_copy_into (segment, &ogg_pad->segment);
330       break;
331     }
332     case GST_EVENT_FLUSH_STOP:{
333       gst_segment_init (&ogg_pad->segment, GST_FORMAT_TIME);
334       break;
335     }
336     case GST_EVENT_TAG:{
337       GstTagList *tags;
338
339       gst_event_parse_tag (event, &tags);
340       tags = gst_tag_list_merge (ogg_pad->tags, tags, GST_TAG_MERGE_APPEND);
341       if (ogg_pad->tags)
342         gst_tag_list_free (ogg_pad->tags);
343       ogg_pad->tags = tags;
344
345       GST_DEBUG_OBJECT (ogg_mux, "Got tags %" GST_PTR_FORMAT, ogg_pad->tags);
346       break;
347     }
348     default:
349       break;
350   }
351
352   /* now GstCollectPads can take care of the rest, e.g. EOS */
353   if (event != NULL)
354     ret = ogg_pad->collect_event (pad, parent, event);
355
356   return ret;
357 }
358
359 static gboolean
360 gst_ogg_mux_is_serialno_present (GstOggMux * ogg_mux, guint32 serialno)
361 {
362   GSList *walk;
363
364   walk = ogg_mux->collect->data;
365   while (walk) {
366     GstOggPadData *pad = (GstOggPadData *) walk->data;
367     if (pad->map.serialno == serialno)
368       return TRUE;
369     walk = walk->next;
370   }
371
372   return FALSE;
373 }
374
375 static guint32
376 gst_ogg_mux_generate_serialno (GstOggMux * ogg_mux)
377 {
378   guint32 serialno;
379
380   do {
381     serialno = g_random_int_range (0, G_MAXINT32);
382   } while (gst_ogg_mux_is_serialno_present (ogg_mux, serialno));
383
384   return serialno;
385 }
386
387 static GstPad *
388 gst_ogg_mux_request_new_pad (GstElement * element,
389     GstPadTemplate * templ, const gchar * req_name, const GstCaps * caps)
390 {
391   GstOggMux *ogg_mux;
392   GstPad *newpad;
393   GstElementClass *klass;
394
395   g_return_val_if_fail (templ != NULL, NULL);
396
397   if (templ->direction != GST_PAD_SINK)
398     goto wrong_direction;
399
400   g_return_val_if_fail (GST_IS_OGG_MUX (element), NULL);
401   ogg_mux = GST_OGG_MUX (element);
402
403   klass = GST_ELEMENT_GET_CLASS (element);
404
405   if (templ != gst_element_class_get_pad_template (klass, "video_%u") &&
406       templ != gst_element_class_get_pad_template (klass, "audio_%u") &&
407       templ != gst_element_class_get_pad_template (klass, "subtitle_%u")) {
408     goto wrong_template;
409   }
410
411   {
412     guint32 serial;
413     gchar *name = NULL;
414
415     if (req_name == NULL || strlen (req_name) < 6) {
416       /* no name given when requesting the pad, use random serial number */
417       serial = gst_ogg_mux_generate_serialno (ogg_mux);
418     } else {
419       /* parse serial number from requested padname */
420       unsigned long long_serial;
421       char *endptr = NULL;
422       long_serial = strtoul (&req_name[5], &endptr, 10);
423       if ((endptr && *endptr) || (long_serial & ~0xffffffff)) {
424         GST_WARNING_OBJECT (ogg_mux, "Invalid serial number specification: %s",
425             req_name + 5);
426         return NULL;
427       }
428       serial = (guint32) long_serial;
429     }
430     /* create new pad with the name */
431     GST_DEBUG_OBJECT (ogg_mux, "Creating new pad for serial %d", serial);
432
433     if (templ == gst_element_class_get_pad_template (klass, "video_%u")) {
434       name = g_strdup_printf ("video_%u", serial);
435     } else if (templ == gst_element_class_get_pad_template (klass, "audio_%u")) {
436       name = g_strdup_printf ("audio_%u", serial);
437     } else if (templ == gst_element_class_get_pad_template (klass,
438             "subtitle_%u")) {
439       name = g_strdup_printf ("subtitle_%u", serial);
440     }
441     newpad = gst_pad_new_from_template (templ, name);
442     g_free (name);
443
444     /* construct our own wrapper data structure for the pad to
445      * keep track of its status */
446     {
447       GstOggPadData *oggpad;
448
449       oggpad = (GstOggPadData *)
450           gst_collect_pads2_add_pad_full (ogg_mux->collect, newpad,
451           sizeof (GstOggPadData), gst_ogg_mux_ogg_pad_destroy_notify, TRUE);
452       ogg_mux->active_pads++;
453
454       oggpad->map.serialno = serial;
455       ogg_stream_init (&oggpad->map.stream, oggpad->map.serialno);
456       oggpad->packetno = 0;
457       oggpad->pageno = 0;
458       oggpad->eos = FALSE;
459       /* we assume there will be some control data first for this pad */
460       oggpad->state = GST_OGG_PAD_STATE_CONTROL;
461       oggpad->new_page = TRUE;
462       oggpad->first_delta = FALSE;
463       oggpad->prev_delta = FALSE;
464       oggpad->data_pushed = FALSE;
465       oggpad->pagebuffers = g_queue_new ();
466       oggpad->map.headers = NULL;
467       oggpad->map.queued = NULL;
468       oggpad->next_granule = 0;
469       oggpad->keyframe_granule = -1;
470
471       gst_segment_init (&oggpad->segment, GST_FORMAT_TIME);
472
473       oggpad->collect_event = (GstPadEventFunction) GST_PAD_EVENTFUNC (newpad);
474       gst_pad_set_event_function (newpad,
475           GST_DEBUG_FUNCPTR (gst_ogg_mux_sink_event));
476     }
477   }
478
479   /* setup some pad functions */
480   gst_pad_set_link_function (newpad, gst_ogg_mux_sinkconnect);
481
482   /* dd the pad to the element */
483   gst_element_add_pad (element, newpad);
484
485   return newpad;
486
487   /* ERRORS */
488 wrong_direction:
489   {
490     g_warning ("ogg_mux: request pad that is not a SINK pad\n");
491     return NULL;
492   }
493 wrong_template:
494   {
495     g_warning ("ogg_mux: this is not our template!\n");
496     return NULL;
497   }
498 }
499
500 static void
501 gst_ogg_mux_release_pad (GstElement * element, GstPad * pad)
502 {
503   GstOggMux *ogg_mux;
504
505   ogg_mux = GST_OGG_MUX (gst_pad_get_parent (pad));
506
507   gst_collect_pads2_remove_pad (ogg_mux->collect, pad);
508   gst_element_remove_pad (element, pad);
509
510   gst_object_unref (ogg_mux);
511 }
512
513 /* handle events */
514 static gboolean
515 gst_ogg_mux_handle_src_event (GstPad * pad, GstObject * parent,
516     GstEvent * event)
517 {
518   GstEventType type;
519
520   type = event ? GST_EVENT_TYPE (event) : GST_EVENT_UNKNOWN;
521
522   switch (type) {
523     case GST_EVENT_SEEK:
524       /* disable seeking for now */
525       return FALSE;
526     default:
527       break;
528   }
529
530   return gst_pad_event_default (pad, parent, event);
531 }
532
533 static GstBuffer *
534 gst_ogg_mux_buffer_from_page (GstOggMux * mux, ogg_page * page, gboolean delta)
535 {
536   GstBuffer *buffer;
537
538   /* allocate space for header and body */
539   buffer = gst_buffer_new_and_alloc (page->header_len + page->body_len);
540   gst_buffer_fill (buffer, 0, page->header, page->header_len);
541   gst_buffer_fill (buffer, page->header_len, page->body, page->body_len);
542
543   /* Here we set granulepos as our OFFSET_END to give easy direct access to
544    * this value later. Before we push it, we reset this to OFFSET + SIZE
545    * (see gst_ogg_mux_push_buffer). */
546   GST_BUFFER_OFFSET_END (buffer) = ogg_page_granulepos (page);
547   if (delta)
548     GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DELTA_UNIT);
549
550   GST_LOG_OBJECT (mux, GST_GP_FORMAT
551       " created buffer %p from ogg page",
552       GST_GP_CAST (ogg_page_granulepos (page)), buffer);
553
554   return buffer;
555 }
556
557 static GstFlowReturn
558 gst_ogg_mux_push_buffer (GstOggMux * mux, GstBuffer * buffer,
559     GstOggPadData * oggpad)
560 {
561   /* fix up OFFSET and OFFSET_END again */
562   GST_BUFFER_OFFSET (buffer) = mux->offset;
563   mux->offset += gst_buffer_get_size (buffer);
564   GST_BUFFER_OFFSET_END (buffer) = mux->offset;
565
566   /* Ensure we have monotonically increasing timestamps in the output. */
567   if (GST_BUFFER_TIMESTAMP_IS_VALID (buffer)) {
568     gint64 run_time = GST_BUFFER_TIMESTAMP (buffer);
569     if (mux->last_ts != GST_CLOCK_TIME_NONE && run_time < mux->last_ts)
570       GST_BUFFER_TIMESTAMP (buffer) = mux->last_ts;
571     else
572       mux->last_ts = run_time;
573   }
574
575   return gst_pad_push (mux->srcpad, buffer);
576 }
577
578 /* if all queues have at least one page, dequeue the page with the lowest
579  * timestamp */
580 static gboolean
581 gst_ogg_mux_dequeue_page (GstOggMux * mux, GstFlowReturn * flowret)
582 {
583   GSList *walk;
584   GstOggPadData *opad = NULL;   /* "oldest" pad */
585   GstClockTime oldest = GST_CLOCK_TIME_NONE;
586   GstBuffer *buf = NULL;
587   gboolean ret = FALSE;
588
589   *flowret = GST_FLOW_OK;
590
591   walk = mux->collect->data;
592   while (walk) {
593     GstOggPadData *pad = (GstOggPadData *) walk->data;
594
595     /* We need each queue to either be at EOS, or have one or more pages
596      * available with a set granulepos (i.e. not -1), otherwise we don't have
597      * enough data yet to determine which stream needs to go next for correct
598      * time ordering. */
599     if (pad->pagebuffers->length == 0) {
600       if (pad->eos) {
601         GST_LOG_OBJECT (pad->collect.pad,
602             "pad is EOS, skipping for dequeue decision");
603       } else {
604         GST_LOG_OBJECT (pad->collect.pad,
605             "no pages in this queue, can't dequeue");
606         return FALSE;
607       }
608     } else {
609       /* We then need to check for a non-negative granulepos */
610       int i;
611       gboolean valid = FALSE;
612
613       for (i = 0; i < pad->pagebuffers->length; i++) {
614         buf = g_queue_peek_nth (pad->pagebuffers, i);
615         /* Here we check the OFFSET_END, which is actually temporarily the
616          * granulepos value for this buffer */
617         if (GST_BUFFER_OFFSET_END (buf) != -1) {
618           valid = TRUE;
619           break;
620         }
621       }
622       if (!valid) {
623         GST_LOG_OBJECT (pad->collect.pad,
624             "No page timestamps in queue, can't dequeue");
625         return FALSE;
626       }
627     }
628
629     walk = g_slist_next (walk);
630   }
631
632   walk = mux->collect->data;
633   while (walk) {
634     GstOggPadData *pad = (GstOggPadData *) walk->data;
635
636     /* any page with a granulepos of -1 can be pushed immediately.
637      * TODO: it CAN be, but it seems silly to do so? */
638     buf = g_queue_peek_head (pad->pagebuffers);
639     while (buf && GST_BUFFER_OFFSET_END (buf) == -1) {
640       GST_LOG_OBJECT (pad->collect.pad, "[gp        -1] pushing page");
641       g_queue_pop_head (pad->pagebuffers);
642       *flowret = gst_ogg_mux_push_buffer (mux, buf, pad);
643       buf = g_queue_peek_head (pad->pagebuffers);
644       ret = TRUE;
645     }
646
647     if (buf) {
648       /* if no oldest buffer yet, take this one */
649       if (oldest == GST_CLOCK_TIME_NONE) {
650         GST_LOG_OBJECT (mux, "no oldest yet, taking buffer %p from pad %"
651             GST_PTR_FORMAT " with gp time %" GST_TIME_FORMAT,
652             buf, pad->collect.pad, GST_TIME_ARGS (GST_BUFFER_OFFSET (buf)));
653         oldest = GST_BUFFER_OFFSET (buf);
654         opad = pad;
655       } else {
656         /* if we have an oldest, compare with this one */
657         if (GST_BUFFER_OFFSET (buf) < oldest) {
658           GST_LOG_OBJECT (mux, "older buffer %p, taking from pad %"
659               GST_PTR_FORMAT " with gp time %" GST_TIME_FORMAT,
660               buf, pad->collect.pad, GST_TIME_ARGS (GST_BUFFER_OFFSET (buf)));
661           oldest = GST_BUFFER_OFFSET (buf);
662           opad = pad;
663         }
664       }
665     }
666     walk = g_slist_next (walk);
667   }
668
669   if (oldest != GST_CLOCK_TIME_NONE) {
670     g_assert (opad);
671     buf = g_queue_pop_head (opad->pagebuffers);
672     GST_LOG_OBJECT (opad->collect.pad,
673         GST_GP_FORMAT " pushing oldest page buffer %p (granulepos time %"
674         GST_TIME_FORMAT ")", GST_BUFFER_OFFSET_END (buf), buf,
675         GST_TIME_ARGS (GST_BUFFER_OFFSET (buf)));
676     *flowret = gst_ogg_mux_push_buffer (mux, buf, opad);
677     ret = TRUE;
678   }
679
680   return ret;
681 }
682
683 /* put the given ogg page on a per-pad queue, timestamping it correctly.
684  * after that, dequeue and push as many pages as possible.
685  * Caller should make sure:
686  * pad->timestamp     was set with the timestamp of the first packet put
687  *                    on the page
688  * pad->timestamp_end was set with the timestamp + duration of the last packet
689  *                    put on the page
690  * pad->gp_time       was set with the time matching the gp of the last
691  *                    packet put on the page
692  *
693  * will also reset timestamp and timestamp_end, so caller func can restart
694  * counting.
695  */
696 static GstFlowReturn
697 gst_ogg_mux_pad_queue_page (GstOggMux * mux, GstOggPadData * pad,
698     ogg_page * page, gboolean delta)
699 {
700   GstFlowReturn ret;
701   GstBuffer *buffer = gst_ogg_mux_buffer_from_page (mux, page, delta);
702
703   /* take the timestamp of the first packet on this page */
704   GST_BUFFER_TIMESTAMP (buffer) = pad->timestamp;
705   GST_BUFFER_DURATION (buffer) = pad->timestamp_end - pad->timestamp;
706   /* take the gp time of the last completed packet on this page */
707   GST_BUFFER_OFFSET (buffer) = pad->gp_time;
708
709   /* the next page will start where the current page's end time leaves off */
710   pad->timestamp = pad->timestamp_end;
711
712   g_queue_push_tail (pad->pagebuffers, buffer);
713   GST_LOG_OBJECT (pad->collect.pad, GST_GP_FORMAT
714       " queued buffer page %p (gp time %"
715       GST_TIME_FORMAT ", timestamp %" GST_TIME_FORMAT
716       "), %d page buffers queued", GST_GP_CAST (ogg_page_granulepos (page)),
717       buffer, GST_TIME_ARGS (GST_BUFFER_OFFSET (buffer)),
718       GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)),
719       g_queue_get_length (pad->pagebuffers));
720
721   while (gst_ogg_mux_dequeue_page (mux, &ret)) {
722     if (ret != GST_FLOW_OK)
723       break;
724   }
725
726   return ret;
727 }
728
729 /*
730  * Given two pads, compare the buffers queued on it.
731  * Returns:
732  *  0 if they have an equal priority
733  * -1 if the first is better
734  *  1 if the second is better
735  * Priority decided by: a) validity, b) older timestamp, c) smaller number
736  * of muxed pages
737  */
738 static gint
739 gst_ogg_mux_compare_pads (GstOggMux * ogg_mux, GstOggPadData * first,
740     GstOggPadData * second)
741 {
742   guint64 firsttime, secondtime;
743
744   /* if the first pad doesn't contain anything or is even NULL, return
745    * the second pad as best candidate and vice versa */
746   if (first == NULL)
747     return 1;
748   if (second == NULL)
749     return -1;
750
751   /* no timestamp on first buffer, it must go first */
752   firsttime = GST_BUFFER_TIMESTAMP (first->buffer);
753   if (firsttime == GST_CLOCK_TIME_NONE)
754     return -1;
755
756   /* no timestamp on second buffer, it must go first */
757   secondtime = GST_BUFFER_TIMESTAMP (second->buffer);
758   if (secondtime == GST_CLOCK_TIME_NONE)
759     return 1;
760
761   /* first buffer has higher timestamp, second one should go first */
762   if (secondtime < firsttime)
763     return 1;
764   /* second buffer has higher timestamp, first one should go first */
765   else if (secondtime > firsttime)
766     return -1;
767   else {
768     /* buffers with equal timestamps, prefer the pad that has the
769      * least number of pages muxed */
770     if (second->pageno < first->pageno)
771       return 1;
772     else if (second->pageno > first->pageno)
773       return -1;
774   }
775
776   /* same priority if all of the above failed */
777   return 0;
778 }
779
780 static GstBuffer *
781 gst_ogg_mux_decorate_buffer (GstOggMux * ogg_mux, GstOggPadData * pad,
782     GstBuffer * buf)
783 {
784   GstClockTime time;
785   gint64 duration, granule, limit;
786   GstClockTime next_time;
787   GstClockTimeDiff diff;
788   ogg_packet packet;
789   gsize size;
790
791   /* ensure messing with metadata is ok */
792   buf = gst_buffer_make_writable (buf);
793
794   /* convert time to running time, so we need no longer bother about that */
795   time = GST_BUFFER_TIMESTAMP (buf);
796   if (G_LIKELY (GST_CLOCK_TIME_IS_VALID (time))) {
797     time = gst_segment_to_running_time (&pad->segment, GST_FORMAT_TIME, time);
798     if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (time))) {
799       gst_buffer_unref (buf);
800       return NULL;
801     } else {
802       GST_BUFFER_TIMESTAMP (buf) = time;
803     }
804   }
805
806   /* now come up with granulepos stuff corresponding to time */
807   if (!pad->have_type ||
808       pad->map.granulerate_n <= 0 || pad->map.granulerate_d <= 0)
809     goto no_granule;
810
811   packet.packet = gst_buffer_map (buf, &size, NULL, GST_MAP_READ);
812   packet.bytes = size;
813   duration = gst_ogg_stream_get_packet_duration (&pad->map, &packet);
814   gst_buffer_unmap (buf, packet.packet, size);
815
816   /* give up if no duration can be determined, relying on upstream */
817   if (G_UNLIKELY (duration < 0)) {
818     /* well, if some day we really could handle sparse input ... */
819     if (pad->map.is_sparse) {
820       limit = 1;
821       diff = 2;
822       goto resync;
823     }
824     GST_WARNING_OBJECT (pad->collect.pad,
825         "failed to determine packet duration");
826     goto no_granule;
827   }
828
829   GST_LOG_OBJECT (pad->collect.pad, "buffer ts %" GST_TIME_FORMAT
830       ", duration %" GST_TIME_FORMAT ", granule duration %" G_GINT64_FORMAT,
831       GST_TIME_ARGS (time), GST_TIME_ARGS (GST_BUFFER_DURATION (buf)),
832       duration);
833
834   /* determine granule corresponding to time,
835    * using the inverse of oggdemux' granule -> time */
836
837   /* see if interpolated granule matches good enough */
838   granule = pad->next_granule;
839   next_time = gst_ogg_stream_granule_to_time (&pad->map, pad->next_granule);
840   diff = GST_CLOCK_DIFF (next_time, time);
841
842   /* we tolerate deviation up to configured or within granule granularity */
843   limit = gst_ogg_stream_granule_to_time (&pad->map, 1) / 2;
844   limit = MAX (limit, ogg_mux->max_tolerance);
845
846   GST_LOG_OBJECT (pad->collect.pad, "expected granule %" G_GINT64_FORMAT " == "
847       "time %" GST_TIME_FORMAT " --> ts diff %" GST_TIME_FORMAT
848       " < tolerance %" GST_TIME_FORMAT " (?)",
849       granule, GST_TIME_ARGS (next_time), GST_TIME_ARGS (ABS (diff)),
850       GST_TIME_ARGS (limit));
851
852 resync:
853   /* if not good enough, determine granule based on time */
854   if (diff > limit || diff < -limit) {
855     granule = gst_util_uint64_scale_round (time, pad->map.granulerate_n,
856         GST_SECOND * pad->map.granulerate_d);
857     GST_DEBUG_OBJECT (pad->collect.pad,
858         "resyncing to determined granule %" G_GINT64_FORMAT, granule);
859   }
860
861   if (pad->map.is_ogm || pad->map.is_sparse) {
862     pad->next_granule = granule;
863   } else {
864     granule += duration;
865     pad->next_granule = granule;
866   }
867
868   /* track previous keyframe */
869   if (!GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT))
870     pad->keyframe_granule = granule;
871
872   /* determine corresponding time and granulepos */
873   GST_BUFFER_OFFSET (buf) = gst_ogg_stream_granule_to_time (&pad->map, granule);
874   GST_BUFFER_OFFSET_END (buf) =
875       gst_ogg_stream_granule_to_granulepos (&pad->map, granule,
876       pad->keyframe_granule);
877
878   return buf;
879
880   /* ERRORS */
881 no_granule:
882   {
883     GST_DEBUG_OBJECT (pad->collect.pad, "could not determine granulepos, "
884         "falling back to upstream provided metadata");
885     return buf;
886   }
887 }
888
889
890 /* make sure at least one buffer is queued on all pads, two if possible
891  * 
892  * if pad->buffer == NULL, pad->next_buffer !=  NULL, then
893  *   we do not know if the buffer is the last or not
894  * if pad->buffer != NULL, pad->next_buffer != NULL, then
895  *   pad->buffer is not the last buffer for the pad
896  * if pad->buffer != NULL, pad->next_buffer == NULL, then
897  *   pad->buffer if the last buffer for the pad
898  * 
899  * returns a pointer to an oggpad that holds the best buffer, or
900  * NULL when no pad was usable. "best" means the buffer marked
901  * with the lowest timestamp. If best->buffer == NULL then either
902  * we're at EOS (popped = FALSE), or a buffer got dropped, so retry. */
903 static GstOggPadData *
904 gst_ogg_mux_queue_pads (GstOggMux * ogg_mux, gboolean * popped)
905 {
906   GstOggPadData *bestpad = NULL;
907   GSList *walk;
908
909   *popped = FALSE;
910
911   /* try to make sure we have a buffer from each usable pad first */
912   walk = ogg_mux->collect->data;
913   while (walk) {
914     GstOggPadData *pad;
915     GstCollectData2 *data;
916
917     data = (GstCollectData2 *) walk->data;
918     pad = (GstOggPadData *) data;
919
920     walk = g_slist_next (walk);
921
922     GST_LOG_OBJECT (data->pad, "looking at pad for buffer");
923
924     /* try to get a new buffer for this pad if needed and possible */
925     if (pad->buffer == NULL) {
926       GstBuffer *buf;
927
928       buf = gst_collect_pads2_pop (ogg_mux->collect, data);
929       GST_LOG_OBJECT (data->pad, "popped buffer %" GST_PTR_FORMAT, buf);
930
931       /* On EOS we get a NULL buffer */
932       if (buf != NULL) {
933         *popped = TRUE;
934
935         if (ogg_mux->delta_pad == NULL &&
936             GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT))
937           ogg_mux->delta_pad = pad;
938
939         /* if we need headers */
940         if (pad->state == GST_OGG_PAD_STATE_CONTROL) {
941           /* and we have one */
942           ogg_packet packet;
943           gboolean is_header;
944           gsize size;
945
946           packet.packet = gst_buffer_map (buf, &size, NULL, GST_MAP_READ);
947           packet.bytes = size;
948
949           /* if we're not yet in data mode, ensure we're setup on the first packet */
950           if (!pad->have_type) {
951             GstCaps *caps;
952
953             /* Use headers in caps, if any; this will allow us to be resilient
954              * to starting streams on the fly, and some streams (like VP8
955              * at least) do not send headers packets, as other muxers don't
956              * expect/need them. */
957             caps = gst_pad_get_current_caps (GST_PAD_CAST (data->pad));
958             pad->have_type =
959                 gst_ogg_stream_setup_map_from_caps_headers (&pad->map, caps);
960
961             if (!pad->have_type) {
962               /* fallback on the packet */
963               pad->have_type = gst_ogg_stream_setup_map (&pad->map, &packet);
964             }
965             if (!pad->have_type) {
966               GST_ERROR_OBJECT (pad, "mapper didn't recognise input stream "
967                   "(pad caps: %" GST_PTR_FORMAT ")", caps);
968             } else {
969               GST_DEBUG_OBJECT (pad, "caps detected: %" GST_PTR_FORMAT,
970                   pad->map.caps);
971             }
972             if (caps)
973               gst_caps_unref (caps);
974           }
975
976           if (pad->have_type)
977             is_header = gst_ogg_stream_packet_is_header (&pad->map, &packet);
978           else                  /* fallback (FIXME 0.11: remove IN_CAPS hack) */
979             is_header = GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_IN_CAPS);
980
981           gst_buffer_unmap (buf, packet.packet, size);
982
983           if (is_header) {
984             GST_DEBUG_OBJECT (ogg_mux,
985                 "got header buffer in control state, ignoring");
986             /* just ignore */
987             pad->map.n_header_packets_seen++;
988             gst_buffer_unref (buf);
989             buf = NULL;
990           } else {
991             GST_DEBUG_OBJECT (ogg_mux,
992                 "got data buffer in control state, switching to data mode");
993             /* this is a data buffer so switch to data state */
994             pad->state = GST_OGG_PAD_STATE_DATA;
995
996             /* check if this type of stream allows generating granulepos
997              * metadata here, if not, upstream will have to provide */
998             if (gst_ogg_stream_granule_to_granulepos (&pad->map, 1, 1) < 0) {
999               GST_WARNING_OBJECT (data->pad, "can not generate metadata; "
1000                   "relying on upstream");
1001               /* disable metadata code path, otherwise not used anyway */
1002               pad->map.granulerate_n = 0;
1003             }
1004           }
1005         }
1006
1007         /* so now we should have a real data packet;
1008          * see that it is properly decorated */
1009         if (G_LIKELY (buf)) {
1010           buf = gst_ogg_mux_decorate_buffer (ogg_mux, pad, buf);
1011           if (G_UNLIKELY (!buf))
1012             GST_DEBUG_OBJECT (data->pad, "buffer clipped");
1013         }
1014       }
1015
1016       pad->buffer = buf;
1017     }
1018
1019     /* we should have a buffer now, see if it is the best pad to
1020      * pull on */
1021     if (pad->buffer) {
1022       if (gst_ogg_mux_compare_pads (ogg_mux, bestpad, pad) > 0) {
1023         GST_LOG_OBJECT (data->pad,
1024             "new best pad, with buffer %" GST_PTR_FORMAT, pad->buffer);
1025
1026         bestpad = pad;
1027       }
1028     }
1029   }
1030
1031   return bestpad;
1032 }
1033
1034 static GList *
1035 gst_ogg_mux_get_headers (GstOggPadData * pad)
1036 {
1037   GList *res = NULL;
1038   GstStructure *structure;
1039   GstCaps *caps;
1040   GstPad *thepad;
1041
1042   thepad = pad->collect.pad;
1043
1044   GST_LOG_OBJECT (thepad, "getting headers");
1045
1046   caps = gst_pad_get_current_caps (thepad);
1047   if (caps != NULL) {
1048     const GValue *streamheader;
1049
1050     structure = gst_caps_get_structure (caps, 0);
1051     streamheader = gst_structure_get_value (structure, "streamheader");
1052     if (streamheader != NULL) {
1053       GST_LOG_OBJECT (thepad, "got header");
1054       if (G_VALUE_TYPE (streamheader) == GST_TYPE_ARRAY) {
1055         GArray *bufarr = g_value_peek_pointer (streamheader);
1056         gint i;
1057
1058         GST_LOG_OBJECT (thepad, "got fixed list");
1059
1060         for (i = 0; i < bufarr->len; i++) {
1061           GValue *bufval = &g_array_index (bufarr, GValue, i);
1062
1063           GST_LOG_OBJECT (thepad, "item %d", i);
1064           if (G_VALUE_TYPE (bufval) == GST_TYPE_BUFFER) {
1065             GstBuffer *buf = g_value_peek_pointer (bufval);
1066
1067             GST_LOG_OBJECT (thepad, "adding item %d to header list", i);
1068
1069             gst_buffer_ref (buf);
1070             res = g_list_append (res, buf);
1071           }
1072         }
1073       } else {
1074         GST_LOG_OBJECT (thepad, "streamheader is not fixed list");
1075       }
1076
1077     } else if (gst_structure_has_name (structure, "video/x-dirac")) {
1078       res = g_list_append (res, pad->buffer);
1079       pad->buffer = NULL;
1080     } else {
1081       GST_LOG_OBJECT (thepad, "caps don't have streamheader");
1082     }
1083     gst_caps_unref (caps);
1084   } else {
1085     GST_LOG_OBJECT (thepad, "got empty caps as negotiated format");
1086   }
1087   return res;
1088 }
1089
1090 static GstCaps *
1091 gst_ogg_mux_set_header_on_caps (GstCaps * caps, GList * buffers)
1092 {
1093   GstStructure *structure;
1094   GValue array = { 0 };
1095   GList *walk = buffers;
1096
1097   caps = gst_caps_make_writable (caps);
1098
1099   structure = gst_caps_get_structure (caps, 0);
1100
1101   /* put buffers in a fixed list */
1102   g_value_init (&array, GST_TYPE_ARRAY);
1103
1104   while (walk) {
1105     GstBuffer *buf = GST_BUFFER (walk->data);
1106     GstBuffer *copy;
1107     GValue value = { 0 };
1108
1109     walk = walk->next;
1110
1111     /* mark buffer */
1112     GST_LOG ("Setting IN_CAPS on buffer of length %" G_GSIZE_FORMAT,
1113         gst_buffer_get_size (buf));
1114     GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_IN_CAPS);
1115
1116     g_value_init (&value, GST_TYPE_BUFFER);
1117     copy = gst_buffer_copy (buf);
1118     gst_value_set_buffer (&value, copy);
1119     gst_buffer_unref (copy);
1120     gst_value_array_append_value (&array, &value);
1121     g_value_unset (&value);
1122   }
1123   gst_structure_set_value (structure, "streamheader", &array);
1124   g_value_unset (&array);
1125
1126   return caps;
1127 }
1128
1129 static void
1130 gst_ogg_mux_create_header_packet_with_flags (ogg_packet * packet,
1131     gboolean bos, gboolean eos)
1132 {
1133   packet->granulepos = 0;
1134   /* mark BOS and packet number */
1135   packet->b_o_s = bos;
1136   /* mark EOS */
1137   packet->e_o_s = eos;
1138 }
1139
1140 static void
1141 gst_ogg_mux_create_header_packet (ogg_packet * packet, GstOggPadData * pad)
1142 {
1143   gst_ogg_mux_create_header_packet_with_flags (packet, pad->packetno == 0, 0);
1144   packet->packetno = pad->packetno++;
1145 }
1146
1147 static void
1148 gst_ogg_mux_submit_skeleton_header_packet (GstOggMux * mux,
1149     ogg_stream_state * os, GstBuffer * buf, gboolean bos, gboolean eos)
1150 {
1151   ogg_packet packet;
1152   gsize size;
1153
1154   packet.packet = gst_buffer_map (buf, &size, NULL, GST_MAP_READ);
1155   packet.bytes = size;
1156   gst_ogg_mux_create_header_packet_with_flags (&packet, bos, eos);
1157   ogg_stream_packetin (os, &packet);
1158   gst_buffer_unref (buf);
1159 }
1160
1161 static void
1162 gst_ogg_mux_make_fishead (GstOggMux * mux, ogg_stream_state * os)
1163 {
1164   GstByteWriter bw;
1165   GstBuffer *fishead;
1166
1167   GST_DEBUG_OBJECT (mux, "Creating fishead");
1168
1169   gst_byte_writer_init_with_size (&bw, 64, TRUE);
1170   gst_byte_writer_put_string_utf8 (&bw, "fishead");
1171   gst_byte_writer_put_int16_le (&bw, 3);        /* version major */
1172   gst_byte_writer_put_int16_le (&bw, 0);        /* version minor */
1173   gst_byte_writer_put_int64_le (&bw, 0);        /* presentation time numerator */
1174   gst_byte_writer_put_int64_le (&bw, 1000);     /* ...and denominator */
1175   gst_byte_writer_put_int64_le (&bw, 0);        /* base time numerator */
1176   gst_byte_writer_put_int64_le (&bw, 1000);     /* ...and denominator */
1177   gst_byte_writer_fill (&bw, ' ', 20);  /* UTC time */
1178   g_assert (gst_byte_writer_get_pos (&bw) == 64);
1179   fishead = gst_byte_writer_reset_and_get_buffer (&bw);
1180   gst_ogg_mux_submit_skeleton_header_packet (mux, os, fishead, 1, 0);
1181 }
1182
1183 static void
1184 gst_ogg_mux_byte_writer_put_string_utf8 (GstByteWriter * bw, const char *s)
1185 {
1186   gst_byte_writer_put_data (bw, (const guint8 *) s, strlen (s));
1187 }
1188
1189 static void
1190 gst_ogg_mux_add_fisbone_message_header (GstOggMux * mux, GstByteWriter * bw,
1191     const char *tag, const char *value)
1192 {
1193   /* It is valid to pass NULL as the value to omit the tag */
1194   if (!value)
1195     return;
1196   GST_DEBUG_OBJECT (mux, "Adding fisbone message header %s: %s", tag, value);
1197   gst_ogg_mux_byte_writer_put_string_utf8 (bw, tag);
1198   gst_ogg_mux_byte_writer_put_string_utf8 (bw, ": ");
1199   gst_ogg_mux_byte_writer_put_string_utf8 (bw, value);
1200   gst_ogg_mux_byte_writer_put_string_utf8 (bw, "\r\n");
1201 }
1202
1203 static void
1204 gst_ogg_mux_add_fisbone_message_header_from_tags (GstOggMux * mux,
1205     GstByteWriter * bw, const char *header, const char *tag,
1206     const GstTagList * tags)
1207 {
1208   GString *s;
1209   guint size = gst_tag_list_get_tag_size (tags, tag), n;
1210   GST_DEBUG_OBJECT (mux, "Found %u tags for name %s", size, tag);
1211   if (size == 0)
1212     return;
1213   s = g_string_new ("");
1214   for (n = 0; n < size; ++n) {
1215     gchar *tmp;
1216     if (n)
1217       g_string_append (s, ", ");
1218     gst_tag_list_get_string_index (tags, tag, n, &tmp);
1219     g_string_append (s, tmp);
1220     g_free (tmp);
1221   }
1222   gst_ogg_mux_add_fisbone_message_header (mux, bw, header, s->str);
1223   g_string_free (s, TRUE);
1224 }
1225
1226 /* This is a basic placeholder to generate roles for the tracks.
1227    For tracks with more than one video, both video tracks will get
1228    tagged with a "video/main" role, but we have no way of knowing
1229    which one is the main one, if any. We could just pick one. For
1230    audio, it's more complicated as we don't know which is music,
1231    which is dubbing, etc. For kate, we could take a pretty good
1232    guess based on the category, as role essentially is category.
1233    For now, leave this as is. */
1234 static const char *
1235 gst_ogg_mux_get_default_role (GstOggPadData * pad)
1236 {
1237   const char *type = gst_ogg_stream_get_media_type (&pad->map);
1238   if (type) {
1239     if (!strncmp (type, "video/", strlen ("video/")))
1240       return "video/main";
1241     if (!strncmp (type, "audio/", strlen ("audio/")))
1242       return "audio/main";
1243     if (!strcmp (type + strlen (type) - strlen ("kate"), "kate"))
1244       return "text/caption";
1245   }
1246   return NULL;
1247 }
1248
1249 static void
1250 gst_ogg_mux_make_fisbone (GstOggMux * mux, ogg_stream_state * os,
1251     GstOggPadData * pad)
1252 {
1253   GstByteWriter bw;
1254
1255   GST_DEBUG_OBJECT (mux,
1256       "Creating %s fisbone for serial %08x",
1257       gst_ogg_stream_get_media_type (&pad->map), pad->map.serialno);
1258
1259   gst_byte_writer_init (&bw);
1260   gst_byte_writer_put_string_utf8 (&bw, "fisbone");
1261   gst_byte_writer_put_int32_le (&bw, 44);       /* offset to message headers */
1262   gst_byte_writer_put_uint32_le (&bw, pad->map.serialno);
1263   gst_byte_writer_put_uint32_le (&bw, pad->map.n_header_packets);
1264   gst_byte_writer_put_uint64_le (&bw, pad->map.granulerate_n);
1265   gst_byte_writer_put_uint64_le (&bw, pad->map.granulerate_d);
1266   gst_byte_writer_put_uint64_le (&bw, 0);       /* base granule */
1267   gst_byte_writer_put_uint32_le (&bw, pad->map.preroll);
1268   gst_byte_writer_put_uint8 (&bw, pad->map.granuleshift);
1269   gst_byte_writer_fill (&bw, 0, 3);     /* padding */
1270   /* message header fields - MIME type for now */
1271   gst_ogg_mux_add_fisbone_message_header (mux, &bw, "Content-Type",
1272       gst_ogg_stream_get_media_type (&pad->map));
1273   gst_ogg_mux_add_fisbone_message_header (mux, &bw, "Role",
1274       gst_ogg_mux_get_default_role (pad));
1275   gst_ogg_mux_add_fisbone_message_header_from_tags (mux, &bw, "Language",
1276       GST_TAG_LANGUAGE_CODE, pad->tags);
1277   gst_ogg_mux_add_fisbone_message_header_from_tags (mux, &bw, "Title",
1278       GST_TAG_TITLE, pad->tags);
1279
1280   gst_ogg_mux_submit_skeleton_header_packet (mux, os,
1281       gst_byte_writer_reset_and_get_buffer (&bw), 0, 0);
1282 }
1283
1284 static void
1285 gst_ogg_mux_make_fistail (GstOggMux * mux, ogg_stream_state * os)
1286 {
1287   GST_DEBUG_OBJECT (mux, "Creating fistail");
1288
1289   gst_ogg_mux_submit_skeleton_header_packet (mux, os,
1290       gst_buffer_new_and_alloc (0), 0, 1);
1291 }
1292
1293 /*
1294  * For each pad we need to write out one (small) header in one
1295  * page that allows decoders to identify the type of the stream.
1296  * After that we need to write out all extra info for the decoders.
1297  * In the case of a codec that also needs data as configuration, we can
1298  * find that info in the streamcaps. 
1299  * After writing the headers we must start a new page for the data.
1300  */
1301 static GstFlowReturn
1302 gst_ogg_mux_send_headers (GstOggMux * mux)
1303 {
1304   GSList *walk;
1305   GList *hbufs, *hwalk;
1306   GstCaps *caps;
1307   GstFlowReturn ret;
1308   ogg_page page;
1309   ogg_stream_state skeleton_stream;
1310
1311   hbufs = NULL;
1312   ret = GST_FLOW_OK;
1313
1314   GST_LOG_OBJECT (mux, "collecting headers");
1315
1316   walk = mux->collect->data;
1317   while (walk) {
1318     GstOggPadData *pad;
1319     GstPad *thepad;
1320
1321     pad = (GstOggPadData *) walk->data;
1322     thepad = pad->collect.pad;
1323
1324     walk = g_slist_next (walk);
1325
1326     GST_LOG_OBJECT (mux, "looking at pad %s:%s", GST_DEBUG_PAD_NAME (thepad));
1327
1328     /* if the pad has no buffer, we don't care */
1329     if (pad->buffer == NULL)
1330       continue;
1331
1332     /* now figure out the headers */
1333     pad->map.headers = gst_ogg_mux_get_headers (pad);
1334   }
1335
1336   GST_LOG_OBJECT (mux, "creating BOS pages");
1337   walk = mux->collect->data;
1338   while (walk) {
1339     GstOggPadData *pad;
1340     GstBuffer *buf;
1341     ogg_packet packet;
1342     GstPad *thepad;
1343     GstCaps *caps;
1344     GstStructure *structure;
1345     GstBuffer *hbuf;
1346     gsize size;
1347
1348     pad = (GstOggPadData *) walk->data;
1349     thepad = pad->collect.pad;
1350     caps = gst_pad_get_current_caps (thepad);
1351     structure = gst_caps_get_structure (caps, 0);
1352
1353     walk = walk->next;
1354
1355     pad->packetno = 0;
1356
1357     GST_LOG_OBJECT (thepad, "looping over headers");
1358
1359     if (pad->map.headers) {
1360       buf = GST_BUFFER (pad->map.headers->data);
1361       pad->map.headers = g_list_remove (pad->map.headers, buf);
1362     } else if (pad->buffer) {
1363       buf = pad->buffer;
1364       gst_buffer_ref (buf);
1365     } else {
1366       /* fixme -- should be caught in the previous list traversal. */
1367       GST_OBJECT_LOCK (thepad);
1368       g_critical ("No headers or buffers on pad %s:%s",
1369           GST_DEBUG_PAD_NAME (thepad));
1370       GST_OBJECT_UNLOCK (thepad);
1371       continue;
1372     }
1373
1374     /* create a packet from the buffer */
1375     packet.packet = gst_buffer_map (buf, &size, NULL, GST_MAP_READ);
1376     packet.bytes = size;
1377
1378     gst_ogg_mux_create_header_packet (&packet, pad);
1379
1380     /* swap the packet in */
1381     ogg_stream_packetin (&pad->map.stream, &packet);
1382
1383     gst_buffer_unmap (buf, packet.packet, size);
1384     gst_buffer_unref (buf);
1385
1386     GST_LOG_OBJECT (thepad, "flushing out BOS page");
1387     if (!ogg_stream_flush (&pad->map.stream, &page))
1388       g_critical ("Could not flush BOS page");
1389
1390     hbuf = gst_ogg_mux_buffer_from_page (mux, &page, FALSE);
1391
1392     GST_LOG_OBJECT (mux, "swapped out page with mime type %s",
1393         gst_structure_get_name (structure));
1394
1395     /* quick hack: put video pages at the front.
1396      * Ideally, we would have a settable enum for which Ogg
1397      * profile we work with, and order based on that.
1398      * (FIXME: if there is more than one video stream, shouldn't we only put
1399      * one's BOS into the first page, followed by an audio stream's BOS, and
1400      * only then followed by the remaining video and audio streams?) */
1401     if (pad->map.is_video) {
1402       GST_DEBUG_OBJECT (thepad, "putting %s page at the front",
1403           gst_structure_get_name (structure));
1404       hbufs = g_list_prepend (hbufs, hbuf);
1405     } else {
1406       hbufs = g_list_append (hbufs, hbuf);
1407     }
1408
1409     gst_caps_unref (caps);
1410   }
1411
1412   /* The Skeleton BOS goes first - even before the video that went first before */
1413   if (mux->use_skeleton) {
1414     ogg_stream_init (&skeleton_stream, gst_ogg_mux_generate_serialno (mux));
1415     gst_ogg_mux_make_fishead (mux, &skeleton_stream);
1416     while (ogg_stream_flush (&skeleton_stream, &page) > 0) {
1417       GstBuffer *hbuf = gst_ogg_mux_buffer_from_page (mux, &page, FALSE);
1418       hbufs = g_list_append (hbufs, hbuf);
1419     }
1420   }
1421
1422   GST_LOG_OBJECT (mux, "creating next headers");
1423   walk = mux->collect->data;
1424   while (walk) {
1425     GstOggPadData *pad;
1426     GstPad *thepad;
1427
1428     pad = (GstOggPadData *) walk->data;
1429     thepad = pad->collect.pad;
1430
1431     walk = walk->next;
1432
1433     if (mux->use_skeleton)
1434       gst_ogg_mux_make_fisbone (mux, &skeleton_stream, pad);
1435
1436     GST_LOG_OBJECT (mux, "looping over headers for pad %s:%s",
1437         GST_DEBUG_PAD_NAME (thepad));
1438
1439     hwalk = pad->map.headers;
1440     while (hwalk) {
1441       GstBuffer *buf = GST_BUFFER (hwalk->data);
1442       ogg_packet packet;
1443       ogg_page page;
1444       gsize size;
1445
1446       hwalk = hwalk->next;
1447
1448       /* create a packet from the buffer */
1449       packet.packet = gst_buffer_map (buf, &size, NULL, GST_MAP_READ);
1450       packet.bytes = size;
1451
1452       gst_ogg_mux_create_header_packet (&packet, pad);
1453
1454       /* swap the packet in */
1455       ogg_stream_packetin (&pad->map.stream, &packet);
1456       gst_buffer_unmap (buf, packet.packet, size);
1457       gst_buffer_unref (buf);
1458
1459       /* if last header, flush page */
1460       if (hwalk == NULL) {
1461         GST_LOG_OBJECT (mux,
1462             "flushing page as packet %" G_GUINT64_FORMAT " is first or "
1463             "last packet", (guint64) packet.packetno);
1464         while (ogg_stream_flush (&pad->map.stream, &page)) {
1465           GstBuffer *hbuf = gst_ogg_mux_buffer_from_page (mux, &page, FALSE);
1466
1467           GST_LOG_OBJECT (mux, "swapped out page");
1468           hbufs = g_list_append (hbufs, hbuf);
1469         }
1470       } else {
1471         GST_LOG_OBJECT (mux, "try to swap out page");
1472         /* just try to swap out a page then */
1473         while (ogg_stream_pageout (&pad->map.stream, &page) > 0) {
1474           GstBuffer *hbuf = gst_ogg_mux_buffer_from_page (mux, &page, FALSE);
1475
1476           GST_LOG_OBJECT (mux, "swapped out page");
1477           hbufs = g_list_append (hbufs, hbuf);
1478         }
1479       }
1480     }
1481     g_list_free (pad->map.headers);
1482     pad->map.headers = NULL;
1483   }
1484
1485   if (mux->use_skeleton) {
1486     /* flush accumulated fisbones, the fistail must be on a separate page */
1487     while (ogg_stream_flush (&skeleton_stream, &page) > 0) {
1488       GstBuffer *hbuf = gst_ogg_mux_buffer_from_page (mux, &page, FALSE);
1489       hbufs = g_list_append (hbufs, hbuf);
1490     }
1491     gst_ogg_mux_make_fistail (mux, &skeleton_stream);
1492     while (ogg_stream_flush (&skeleton_stream, &page) > 0) {
1493       GstBuffer *hbuf = gst_ogg_mux_buffer_from_page (mux, &page, FALSE);
1494       hbufs = g_list_append (hbufs, hbuf);
1495     }
1496     ogg_stream_clear (&skeleton_stream);
1497   }
1498
1499   /* hbufs holds all buffers for the headers now */
1500
1501   /* create caps with the buffers */
1502   caps = gst_pad_query_caps (mux->srcpad, NULL);
1503   if (caps) {
1504     caps = gst_ogg_mux_set_header_on_caps (caps, hbufs);
1505     gst_pad_set_caps (mux->srcpad, caps);
1506     gst_caps_unref (caps);
1507   }
1508   /* and send the buffers */
1509   while (hbufs != NULL) {
1510     GstBuffer *buf = GST_BUFFER (hbufs->data);
1511
1512     hbufs = g_list_delete_link (hbufs, hbufs);
1513
1514     if ((ret = gst_ogg_mux_push_buffer (mux, buf, NULL)) != GST_FLOW_OK)
1515       break;
1516   }
1517   /* free any remaining nodes/buffers in case we couldn't push them */
1518   g_list_foreach (hbufs, (GFunc) gst_mini_object_unref, NULL);
1519   g_list_free (hbufs);
1520
1521   return ret;
1522 }
1523
1524 /* this function is called to process data on the best pending pad.
1525  *
1526  * basic idea:
1527  *
1528  * 1) store the selected pad and keep on pulling until we fill a
1529  *    complete ogg page or the ogg page is filled above the max-delay
1530  *    threshold. This is needed because the ogg spec says that
1531  *    you should fill a complete page with data from the same logical
1532  *    stream. When the page is filled, go back to 1).
1533  * 2) before filling a page, read ahead one more buffer to see if this
1534  *    packet is the last of the stream. We need to do this because the ogg
1535  *    spec mandates that the last packet should have the EOS flag set before
1536  *    sending it to ogg. if pad->buffer is NULL we need to wait to find out
1537  *    whether there are any more buffers.
1538  * 3) pages get queued on a per-pad queue. Every time a page is queued, a
1539  *    dequeue is called, which will dequeue the oldest page on any pad, provided
1540  *    that ALL pads have at least one marked page in the queue (or remaining
1541  *    pads are at EOS)
1542  */
1543 static GstFlowReturn
1544 gst_ogg_mux_process_best_pad (GstOggMux * ogg_mux, GstOggPadData * best)
1545 {
1546   GstFlowReturn ret = GST_FLOW_OK;
1547   gboolean delta_unit;
1548   gint64 granulepos = 0;
1549   GstClockTime timestamp, gp_time;
1550   GstBuffer *next_buf;
1551
1552   GST_LOG_OBJECT (ogg_mux, "best pad %" GST_PTR_FORMAT
1553       ", currently pulling from %" GST_PTR_FORMAT, best->collect.pad,
1554       ogg_mux->pulling ? ogg_mux->pulling->collect.pad : NULL);
1555
1556   if (ogg_mux->pulling) {
1557     next_buf = gst_collect_pads2_peek (ogg_mux->collect,
1558         &ogg_mux->pulling->collect);
1559     if (next_buf) {
1560       ogg_mux->pulling->eos = FALSE;
1561       gst_buffer_unref (next_buf);
1562     } else {
1563       GST_DEBUG_OBJECT (ogg_mux->pulling->collect.pad, "setting eos to true");
1564       ogg_mux->pulling->eos = TRUE;
1565     }
1566   }
1567
1568   /* We could end up pushing from the best pad instead, so check that
1569    * as well */
1570   if (best && best != ogg_mux->pulling) {
1571     next_buf = gst_collect_pads2_peek (ogg_mux->collect, &best->collect);
1572     if (next_buf) {
1573       best->eos = FALSE;
1574       gst_buffer_unref (next_buf);
1575     } else {
1576       GST_DEBUG_OBJECT (best->collect.pad, "setting eos to true");
1577       best->eos = TRUE;
1578     }
1579   }
1580
1581   /* if we were already pulling from one pad, but the new "best" buffer is
1582    * from another pad, we need to check if we have reason to flush a page
1583    * for the pad we were pulling from before */
1584   if (ogg_mux->pulling && best &&
1585       ogg_mux->pulling != best && ogg_mux->pulling->buffer) {
1586     GstOggPadData *pad = ogg_mux->pulling;
1587     GstClockTime last_ts = GST_BUFFER_END_TIME (pad->buffer);
1588
1589     /* if the next packet in the current page is going to make the page
1590      * too long, we need to flush */
1591     if (last_ts > ogg_mux->next_ts + ogg_mux->max_delay) {
1592       ogg_page page;
1593
1594       GST_LOG_OBJECT (pad->collect.pad,
1595           GST_GP_FORMAT " stored packet %" G_GINT64_FORMAT
1596           " will make page too long, flushing",
1597           GST_BUFFER_OFFSET_END (pad->buffer),
1598           (gint64) pad->map.stream.packetno);
1599
1600       while (ogg_stream_flush (&pad->map.stream, &page)) {
1601         /* end time of this page is the timestamp of the next buffer */
1602         ogg_mux->pulling->timestamp_end = GST_BUFFER_TIMESTAMP (pad->buffer);
1603         /* Place page into the per-pad queue */
1604         ret = gst_ogg_mux_pad_queue_page (ogg_mux, pad, &page,
1605             pad->first_delta);
1606         /* increment the page number counter */
1607         pad->pageno++;
1608         /* mark other pages as delta */
1609         pad->first_delta = TRUE;
1610       }
1611       pad->new_page = TRUE;
1612       ogg_mux->pulling = NULL;
1613     }
1614   }
1615
1616   /* if we don't know which pad to pull on, use the best one */
1617   if (ogg_mux->pulling == NULL) {
1618     ogg_mux->pulling = best;
1619     GST_LOG_OBJECT (ogg_mux->pulling->collect.pad, "pulling from best pad");
1620
1621     /* remember timestamp and gp time of first buffer for this new pad */
1622     if (ogg_mux->pulling != NULL) {
1623       ogg_mux->next_ts = GST_BUFFER_TIMESTAMP (ogg_mux->pulling->buffer);
1624       GST_LOG_OBJECT (ogg_mux->pulling->collect.pad, "updated times, next ts %"
1625           GST_TIME_FORMAT, GST_TIME_ARGS (ogg_mux->next_ts));
1626     } else {
1627       /* no pad to pull on, send EOS */
1628       gst_pad_push_event (ogg_mux->srcpad, gst_event_new_eos ());
1629       return GST_FLOW_WRONG_STATE;
1630     }
1631   }
1632
1633   if (ogg_mux->need_headers) {
1634     ret = gst_ogg_mux_send_headers (ogg_mux);
1635     ogg_mux->need_headers = FALSE;
1636   }
1637
1638   /* we are pulling from a pad, continue to do so until a page
1639    * has been filled and queued */
1640   if (ogg_mux->pulling != NULL) {
1641     ogg_packet packet;
1642     ogg_page page;
1643     GstBuffer *buf, *tmpbuf;
1644     GstOggPadData *pad = ogg_mux->pulling;
1645     gint64 duration;
1646     gboolean force_flush;
1647     gsize size;
1648
1649     GST_LOG_OBJECT (ogg_mux->pulling->collect.pad, "pulling from pad");
1650
1651     /* now see if we have a buffer */
1652     buf = pad->buffer;
1653     if (buf == NULL) {
1654       GST_DEBUG_OBJECT (ogg_mux, "pad was EOS");
1655       ogg_mux->pulling = NULL;
1656       return GST_FLOW_OK;
1657     }
1658
1659     delta_unit = GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
1660     duration = GST_BUFFER_DURATION (buf);
1661
1662     /* if the current "next timestamp" on the pad is unset, then this is the
1663      * first packet on the new page.  Update our pad's page timestamp */
1664     if (ogg_mux->pulling->timestamp == GST_CLOCK_TIME_NONE) {
1665       ogg_mux->pulling->timestamp = GST_BUFFER_TIMESTAMP (buf);
1666       GST_LOG_OBJECT (ogg_mux->pulling->collect.pad,
1667           "updated pad timestamp to %" GST_TIME_FORMAT,
1668           GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)));
1669     }
1670     /* create a packet from the buffer */
1671     packet.packet = gst_buffer_map (buf, &size, NULL, GST_MAP_READ);
1672     packet.bytes = size;
1673     packet.granulepos = GST_BUFFER_OFFSET_END (buf);
1674     if (packet.granulepos == -1)
1675       packet.granulepos = 0;
1676     /* mark BOS and packet number */
1677     packet.b_o_s = (pad->packetno == 0);
1678     packet.packetno = pad->packetno++;
1679     GST_LOG_OBJECT (pad->collect.pad, GST_GP_FORMAT
1680         " packet %" G_GINT64_FORMAT " (%ld bytes) created from buffer",
1681         GST_GP_CAST (packet.granulepos), (gint64) packet.packetno,
1682         packet.bytes);
1683
1684     packet.e_o_s = ogg_mux->pulling->eos ? 1 : 0;
1685     tmpbuf = NULL;
1686
1687     /* we flush when we see a new keyframe */
1688     force_flush = (pad->prev_delta && !delta_unit)
1689         || pad->map.always_flush_page;
1690     if (duration != -1) {
1691       pad->duration += duration;
1692       /* if page duration exceeds max, flush page */
1693       if (pad->duration > ogg_mux->max_page_delay) {
1694         force_flush = TRUE;
1695         pad->duration = 0;
1696       }
1697     }
1698
1699     if (GST_BUFFER_IS_DISCONT (buf)) {
1700       if (pad->data_pushed) {
1701         GST_LOG_OBJECT (pad->collect.pad, "got discont");
1702         packet.packetno++;
1703         /* No public API for this; hack things in */
1704         pad->map.stream.pageno++;
1705         force_flush = TRUE;
1706       } else {
1707         GST_LOG_OBJECT (pad->collect.pad, "discont at stream start");
1708       }
1709     }
1710
1711     /* flush the currently built page if necessary */
1712     if (force_flush) {
1713       GST_LOG_OBJECT (pad->collect.pad,
1714           GST_GP_FORMAT " forced flush of page before this packet",
1715           GST_BUFFER_OFFSET_END (pad->buffer));
1716       while (ogg_stream_flush (&pad->map.stream, &page)) {
1717         /* end time of this page is the timestamp of the next buffer */
1718         ogg_mux->pulling->timestamp_end = GST_BUFFER_TIMESTAMP (pad->buffer);
1719         ret = gst_ogg_mux_pad_queue_page (ogg_mux, pad, &page,
1720             pad->first_delta);
1721
1722         /* increment the page number counter */
1723         pad->pageno++;
1724         /* mark other pages as delta */
1725         pad->first_delta = TRUE;
1726       }
1727       pad->new_page = TRUE;
1728     }
1729
1730     /* if this is the first packet of a new page figure out the delta flag */
1731     if (pad->new_page) {
1732       if (delta_unit) {
1733         /* mark the page as delta */
1734         pad->first_delta = TRUE;
1735       } else {
1736         /* got a keyframe */
1737         if (ogg_mux->delta_pad == pad) {
1738           /* if we get it on the pad with deltaunits,
1739            * we mark the page as non delta */
1740           pad->first_delta = FALSE;
1741         } else if (ogg_mux->delta_pad != NULL) {
1742           /* if there are pads with delta frames, we
1743            * must mark this one as delta */
1744           pad->first_delta = TRUE;
1745         } else {
1746           pad->first_delta = FALSE;
1747         }
1748       }
1749       pad->new_page = FALSE;
1750     }
1751
1752     /* save key unit to track delta->key unit transitions */
1753     pad->prev_delta = delta_unit;
1754
1755     /* swap the packet in */
1756     if (packet.e_o_s == 1)
1757       GST_DEBUG_OBJECT (pad->collect.pad, "swapping in EOS packet");
1758     if (packet.b_o_s == 1)
1759       GST_DEBUG_OBJECT (pad->collect.pad, "swapping in BOS packet");
1760
1761     ogg_stream_packetin (&pad->map.stream, &packet);
1762     gst_buffer_unmap (buf, packet.packet, size);
1763     pad->data_pushed = TRUE;
1764
1765     gp_time = GST_BUFFER_OFFSET (pad->buffer);
1766     granulepos = GST_BUFFER_OFFSET_END (pad->buffer);
1767     timestamp = GST_BUFFER_TIMESTAMP (pad->buffer);
1768
1769     GST_LOG_OBJECT (pad->collect.pad,
1770         GST_GP_FORMAT " packet %" G_GINT64_FORMAT ", gp time %"
1771         GST_TIME_FORMAT ", timestamp %" GST_TIME_FORMAT " packetin'd",
1772         granulepos, (gint64) packet.packetno, GST_TIME_ARGS (gp_time),
1773         GST_TIME_ARGS (timestamp));
1774     /* don't need the old buffer anymore */
1775     gst_buffer_unref (pad->buffer);
1776     /* store new readahead buffer */
1777     pad->buffer = tmpbuf;
1778
1779     /* let ogg write out the pages now. The packet we got could end
1780      * up in more than one page so we need to write them all */
1781     if (ogg_stream_pageout (&pad->map.stream, &page) > 0) {
1782       /* we have a new page, so we need to timestamp it correctly.
1783        * if this fresh packet ends on this page, then the page's granulepos
1784        * comes from that packet, and we should set this buffer's timestamp */
1785
1786       GST_LOG_OBJECT (pad->collect.pad,
1787           GST_GP_FORMAT " packet %" G_GINT64_FORMAT ", time %"
1788           GST_TIME_FORMAT ") caused new page",
1789           granulepos, (gint64) packet.packetno, GST_TIME_ARGS (timestamp));
1790       GST_LOG_OBJECT (pad->collect.pad,
1791           GST_GP_FORMAT " new page %ld",
1792           GST_GP_CAST (ogg_page_granulepos (&page)), pad->map.stream.pageno);
1793
1794       if (ogg_page_granulepos (&page) == granulepos) {
1795         /* the packet we streamed in finishes on the current page,
1796          * because the page's granulepos is the granulepos of the last
1797          * packet completed on that page,
1798          * so update the timestamp that we will give to the page */
1799         GST_LOG_OBJECT (pad->collect.pad,
1800             GST_GP_FORMAT
1801             " packet finishes on current page, updating gp time to %"
1802             GST_TIME_FORMAT, granulepos, GST_TIME_ARGS (gp_time));
1803         pad->gp_time = gp_time;
1804       } else {
1805         GST_LOG_OBJECT (pad->collect.pad,
1806             GST_GP_FORMAT
1807             " packet spans beyond current page, keeping old gp time %"
1808             GST_TIME_FORMAT, granulepos, GST_TIME_ARGS (pad->gp_time));
1809       }
1810
1811       /* push the page */
1812       /* end time of this page is the timestamp of the next buffer */
1813       pad->timestamp_end = timestamp;
1814       ret = gst_ogg_mux_pad_queue_page (ogg_mux, pad, &page, pad->first_delta);
1815       pad->pageno++;
1816       /* mark next pages as delta */
1817       pad->first_delta = TRUE;
1818
1819       /* use an inner loop here to flush the remaining pages and
1820        * mark them as delta frames as well */
1821       while (ogg_stream_pageout (&pad->map.stream, &page) > 0) {
1822         if (ogg_page_granulepos (&page) == granulepos) {
1823           /* the page has taken up the new packet completely, which means
1824            * the packet ends the page and we can update the gp time
1825            * before pushing out */
1826           pad->gp_time = gp_time;
1827         }
1828
1829         /* we have a complete page now, we can push the page
1830          * and make sure to pull on a new pad the next time around */
1831         ret = gst_ogg_mux_pad_queue_page (ogg_mux, pad, &page,
1832             pad->first_delta);
1833         /* increment the page number counter */
1834         pad->pageno++;
1835       }
1836       /* need a new page as well */
1837       pad->new_page = TRUE;
1838       pad->duration = 0;
1839       /* we're done pulling on this pad, make sure to choose a new
1840        * pad for pulling in the next iteration */
1841       ogg_mux->pulling = NULL;
1842     }
1843
1844     /* Update the gp time, if necessary, since any future page will have at
1845      * least this gp time.
1846      */
1847     if (pad->gp_time < gp_time) {
1848       pad->gp_time = gp_time;
1849       GST_LOG_OBJECT (pad->collect.pad,
1850           "Updated running gp time of pad %" GST_PTR_FORMAT
1851           " to %" GST_TIME_FORMAT, pad->collect.pad, GST_TIME_ARGS (gp_time));
1852     }
1853   }
1854
1855   return ret;
1856 }
1857
1858 /* all_pads_eos:
1859  *
1860  * Checks if all pads are EOS'd by peeking.
1861  *
1862  * Returns TRUE if all pads are EOS.
1863  */
1864 static gboolean
1865 all_pads_eos (GstCollectPads2 * pads)
1866 {
1867   GSList *walk;
1868
1869   walk = pads->data;
1870   while (walk) {
1871     GstOggPadData *oggpad = (GstOggPadData *) walk->data;
1872
1873     GST_DEBUG_OBJECT (oggpad->collect.pad,
1874         "oggpad %p eos %d", oggpad, oggpad->eos);
1875
1876     if (oggpad->eos == FALSE)
1877       return FALSE;
1878
1879     walk = g_slist_next (walk);
1880   }
1881
1882   return TRUE;
1883 }
1884
1885 /* This function is called when there is data on all pads.
1886  * 
1887  * It finds a pad to pull on, this is done by looking at the buffers
1888  * to decide which one to use, and using the 'oldest' one first. It then calls
1889  * gst_ogg_mux_process_best_pad() to process as much data as possible.
1890  * 
1891  * If all the pads have received EOS, it flushes out all data by continually
1892  * getting the best pad and calling gst_ogg_mux_process_best_pad() until they
1893  * are all empty, and then sends EOS.
1894  */
1895 static GstFlowReturn
1896 gst_ogg_mux_collected (GstCollectPads2 * pads, GstOggMux * ogg_mux)
1897 {
1898   GstOggPadData *best;
1899   GstFlowReturn ret;
1900   gboolean popped;
1901
1902   GST_LOG_OBJECT (ogg_mux, "collected");
1903
1904   /* queue buffers on all pads; find a buffer with the lowest timestamp */
1905   best = gst_ogg_mux_queue_pads (ogg_mux, &popped);
1906
1907   if (popped)
1908     return GST_FLOW_OK;
1909
1910   if (best == NULL || best->buffer == NULL) {
1911     /* This is not supposed to happen */
1912     return GST_FLOW_ERROR;
1913   }
1914
1915   ret = gst_ogg_mux_process_best_pad (ogg_mux, best);
1916
1917   if (best->eos && all_pads_eos (pads)) {
1918     gst_pad_push_event (ogg_mux->srcpad, gst_event_new_eos ());
1919     return GST_FLOW_EOS;
1920   }
1921
1922   return ret;
1923 }
1924
1925 static void
1926 gst_ogg_mux_get_property (GObject * object,
1927     guint prop_id, GValue * value, GParamSpec * pspec)
1928 {
1929   GstOggMux *ogg_mux;
1930
1931   ogg_mux = GST_OGG_MUX (object);
1932
1933   switch (prop_id) {
1934     case ARG_MAX_DELAY:
1935       g_value_set_uint64 (value, ogg_mux->max_delay);
1936       break;
1937     case ARG_MAX_PAGE_DELAY:
1938       g_value_set_uint64 (value, ogg_mux->max_page_delay);
1939       break;
1940     case ARG_MAX_TOLERANCE:
1941       g_value_set_uint64 (value, ogg_mux->max_tolerance);
1942       break;
1943     case ARG_SKELETON:
1944       g_value_set_boolean (value, ogg_mux->use_skeleton);
1945       break;
1946     default:
1947       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1948       break;
1949   }
1950 }
1951
1952 static void
1953 gst_ogg_mux_set_property (GObject * object,
1954     guint prop_id, const GValue * value, GParamSpec * pspec)
1955 {
1956   GstOggMux *ogg_mux;
1957
1958   ogg_mux = GST_OGG_MUX (object);
1959
1960   switch (prop_id) {
1961     case ARG_MAX_DELAY:
1962       ogg_mux->max_delay = g_value_get_uint64 (value);
1963       break;
1964     case ARG_MAX_PAGE_DELAY:
1965       ogg_mux->max_page_delay = g_value_get_uint64 (value);
1966       break;
1967     case ARG_MAX_TOLERANCE:
1968       ogg_mux->max_tolerance = g_value_get_uint64 (value);
1969       break;
1970     case ARG_SKELETON:
1971       ogg_mux->use_skeleton = g_value_get_boolean (value);
1972       break;
1973     default:
1974       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1975       break;
1976   }
1977 }
1978
1979 /* reset all variables in the ogg pads. */
1980 static void
1981 gst_ogg_mux_init_collectpads (GstCollectPads2 * collect)
1982 {
1983   GSList *walk;
1984
1985   walk = collect->data;
1986   while (walk) {
1987     GstOggPadData *oggpad = (GstOggPadData *) walk->data;
1988
1989     ogg_stream_init (&oggpad->map.stream, oggpad->map.serialno);
1990     oggpad->packetno = 0;
1991     oggpad->pageno = 0;
1992     oggpad->eos = FALSE;
1993     /* we assume there will be some control data first for this pad */
1994     oggpad->state = GST_OGG_PAD_STATE_CONTROL;
1995     oggpad->new_page = TRUE;
1996     oggpad->first_delta = FALSE;
1997     oggpad->prev_delta = FALSE;
1998     oggpad->data_pushed = FALSE;
1999     oggpad->pagebuffers = g_queue_new ();
2000
2001     gst_segment_init (&oggpad->segment, GST_FORMAT_TIME);
2002
2003     walk = g_slist_next (walk);
2004   }
2005 }
2006
2007 /* Clear all buffers from the collectpads object */
2008 static void
2009 gst_ogg_mux_clear_collectpads (GstCollectPads2 * collect)
2010 {
2011   GSList *walk;
2012
2013   for (walk = collect->data; walk; walk = g_slist_next (walk)) {
2014     GstOggPadData *oggpad = (GstOggPadData *) walk->data;
2015     GstBuffer *buf;
2016
2017     ogg_stream_clear (&oggpad->map.stream);
2018
2019     while ((buf = g_queue_pop_head (oggpad->pagebuffers)) != NULL) {
2020       gst_buffer_unref (buf);
2021     }
2022     g_queue_free (oggpad->pagebuffers);
2023     oggpad->pagebuffers = NULL;
2024
2025     if (oggpad->buffer) {
2026       gst_buffer_unref (oggpad->buffer);
2027       oggpad->buffer = NULL;
2028     }
2029
2030     if (oggpad->tags) {
2031       gst_tag_list_free (oggpad->tags);
2032       oggpad->tags = NULL;
2033     }
2034
2035     gst_segment_init (&oggpad->segment, GST_FORMAT_TIME);
2036   }
2037 }
2038
2039 static GstStateChangeReturn
2040 gst_ogg_mux_change_state (GstElement * element, GstStateChange transition)
2041 {
2042   GstOggMux *ogg_mux;
2043   GstStateChangeReturn ret;
2044
2045   ogg_mux = GST_OGG_MUX (element);
2046
2047   switch (transition) {
2048     case GST_STATE_CHANGE_NULL_TO_READY:
2049       break;
2050     case GST_STATE_CHANGE_READY_TO_PAUSED:
2051       gst_ogg_mux_clear (ogg_mux);
2052       gst_ogg_mux_init_collectpads (ogg_mux->collect);
2053       gst_collect_pads2_start (ogg_mux->collect);
2054       break;
2055     case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
2056       break;
2057     case GST_STATE_CHANGE_PAUSED_TO_READY:
2058       gst_collect_pads2_stop (ogg_mux->collect);
2059       break;
2060     default:
2061       break;
2062   }
2063
2064   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
2065
2066   switch (transition) {
2067     case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
2068       break;
2069     case GST_STATE_CHANGE_PAUSED_TO_READY:
2070       gst_ogg_mux_clear_collectpads (ogg_mux->collect);
2071       break;
2072     case GST_STATE_CHANGE_READY_TO_NULL:
2073       break;
2074     default:
2075       break;
2076   }
2077
2078   return ret;
2079 }
2080
2081 gboolean
2082 gst_ogg_mux_plugin_init (GstPlugin * plugin)
2083 {
2084   GST_DEBUG_CATEGORY_INIT (gst_ogg_mux_debug, "oggmux", 0, "ogg muxer");
2085
2086   return gst_element_register (plugin, "oggmux", GST_RANK_PRIMARY,
2087       GST_TYPE_OGG_MUX);
2088 }