Macro qtTrIdx() replaced by tr() and QT_TRANSLATE_NOOP()
[mafwsubrenderer] / gst-plugins-base-subtitles0.10 / ext / theora / gsttheoraparse.c
1 /* GStreamer
2  * Copyright (C) <2004> Thomas Vander Stichele <thomas at apestaart dot org>
3  * Copyright (C) 2006 Andy Wingo <wingo@pobox.com>
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-theoraparse
23  * @see_also: theoradec, oggdemux, vorbisparse
24  *
25  * The theoraparse element will parse the header packets of the Theora
26  * stream and put them as the streamheader in the caps. This is used in the
27  * multifdsink case where you want to stream live theora streams to multiple
28  * clients, each client has to receive the streamheaders first before they can
29  * consume the theora packets.
30  *
31  * This element also makes sure that the buffers that it pushes out are properly
32  * timestamped and that their offset and offset_end are set. The buffers that
33  * theoraparse outputs have all of the metadata that oggmux expects to receive,
34  * which allows you to (for example) remux an ogg/theora file.
35  *
36  * In addition, this element allows you to fix badly synchronized streams. You
37  * pass in an array of (granule time, buffer time) synchronization points via
38  * the synchronization-points GValueArray property, and this element will adjust
39  * the granulepos values that it outputs. The adjustment will be made by
40  * offsetting all buffers that it outputs by a specified amount, and updating
41  * that offset from the value array whenever a keyframe is processed.
42  *
43  * <refsect2>
44  * <title>Example pipelines</title>
45  * |[
46  * gst-launch -v filesrc location=video.ogg ! oggdemux ! theoraparse ! fakesink
47  * ]| This pipeline shows that the streamheader is set in the caps, and that each
48  * buffer has the timestamp, duration, offset, and offset_end set.
49  * |[
50  * gst-launch filesrc location=video.ogg ! oggdemux ! theoraparse \
51  *            ! oggmux ! filesink location=video-remuxed.ogg
52  * ]| This pipeline shows remuxing. video-remuxed.ogg might not be exactly the same
53  * as video.ogg, but they should produce exactly the same decoded data.
54  * </refsect2>
55  *
56  * Last reviewed on 2008-05-28 (0.10.20)
57  */
58
59 #ifdef HAVE_CONFIG_H
60 #  include "config.h"
61 #endif
62
63 #include "gsttheoraparse.h"
64
65 #define GST_CAT_DEFAULT theoraparse_debug
66 GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
67
68 static GstStaticPadTemplate theora_parse_sink_factory =
69 GST_STATIC_PAD_TEMPLATE ("sink",
70     GST_PAD_SINK,
71     GST_PAD_ALWAYS,
72     GST_STATIC_CAPS ("video/x-theora")
73     );
74
75 static GstStaticPadTemplate theora_parse_src_factory =
76 GST_STATIC_PAD_TEMPLATE ("src",
77     GST_PAD_SRC,
78     GST_PAD_ALWAYS,
79     GST_STATIC_CAPS ("video/x-theora")
80     );
81
82 enum
83 {
84   PROP_0,
85   PROP_SYNCHRONIZATION_POINTS
86 };
87
88 GST_BOILERPLATE (GstTheoraParse, gst_theora_parse, GstElement,
89     GST_TYPE_ELEMENT);
90
91 static void theora_parse_dispose (GObject * object);
92 static void theora_parse_get_property (GObject * object, guint prop_id,
93     GValue * value, GParamSpec * pspec);
94 static void theora_parse_set_property (GObject * object, guint prop_id,
95     const GValue * value, GParamSpec * pspec);
96
97 static GstFlowReturn theora_parse_chain (GstPad * pad, GstBuffer * buffer);
98 static GstStateChangeReturn theora_parse_change_state (GstElement * element,
99     GstStateChange transition);
100 static gboolean theora_parse_sink_event (GstPad * pad, GstEvent * event);
101 static gboolean theora_parse_src_query (GstPad * pad, GstQuery * query);
102
103 static void
104 gst_theora_parse_base_init (gpointer g_class)
105 {
106   GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
107
108   gst_element_class_add_pad_template (element_class,
109       gst_static_pad_template_get (&theora_parse_src_factory));
110   gst_element_class_add_pad_template (element_class,
111       gst_static_pad_template_get (&theora_parse_sink_factory));
112   gst_element_class_set_details_simple (element_class,
113       "Theora video parser", "Codec/Parser/Video",
114       "parse raw theora streams", "Andy Wingo <wingo@pobox.com>");
115 }
116
117 static void
118 gst_theora_parse_class_init (GstTheoraParseClass * klass)
119 {
120   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
121   GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
122
123   gobject_class->dispose = theora_parse_dispose;
124   gobject_class->get_property = theora_parse_get_property;
125   gobject_class->set_property = theora_parse_set_property;
126
127   /**
128    * GstTheoraParse:sychronization-points
129    *
130    * An array of (granuletime, buffertime) pairs
131    *
132    * Since: 0.10.10
133    */
134   g_object_class_install_property (gobject_class, PROP_SYNCHRONIZATION_POINTS,
135       g_param_spec_value_array ("synchronization-points",
136           "Synchronization points",
137           "An array of (granuletime, buffertime) pairs",
138           g_param_spec_uint64 ("time", "Time",
139               "Time (either granuletime or buffertime)", 0, G_MAXUINT64, 0,
140               G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS),
141           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
142
143   gstelement_class->change_state = theora_parse_change_state;
144
145   GST_DEBUG_CATEGORY_INIT (theoraparse_debug, "theoraparse", 0,
146       "Theora parser");
147 }
148
149 static void
150 gst_theora_parse_init (GstTheoraParse * parse, GstTheoraParseClass * g_class)
151 {
152   parse->sinkpad =
153       gst_pad_new_from_static_template (&theora_parse_sink_factory, "sink");
154   gst_pad_set_chain_function (parse->sinkpad, theora_parse_chain);
155   gst_pad_set_event_function (parse->sinkpad, theora_parse_sink_event);
156   gst_element_add_pad (GST_ELEMENT (parse), parse->sinkpad);
157
158   parse->srcpad =
159       gst_pad_new_from_static_template (&theora_parse_src_factory, "src");
160   gst_pad_set_query_function (parse->srcpad, theora_parse_src_query);
161   gst_element_add_pad (GST_ELEMENT (parse), parse->srcpad);
162 }
163
164 static void
165 theora_parse_dispose (GObject * object)
166 {
167   GstTheoraParse *parse = GST_THEORA_PARSE (object);
168
169   g_free (parse->times);
170   parse->times = NULL;
171
172   G_OBJECT_CLASS (parent_class)->dispose (object);
173 }
174
175 static void
176 theora_parse_set_property (GObject * object, guint prop_id,
177     const GValue * value, GParamSpec * pspec)
178 {
179   GstTheoraParse *parse = GST_THEORA_PARSE (object);
180
181   switch (prop_id) {
182     case PROP_SYNCHRONIZATION_POINTS:
183     {
184       GValueArray *array;
185       guint i;
186
187       array = g_value_get_boxed (value);
188
189       if (array) {
190         if (array->n_values % 2)
191           goto odd_values;
192
193         g_free (parse->times);
194         parse->times = g_new (GstClockTime, array->n_values);
195         parse->npairs = array->n_values / 2;
196         for (i = 0; i < array->n_values; i++)
197           parse->times[i] = g_value_get_uint64 (&array->values[i]);
198       } else {
199         g_free (parse->times);
200         parse->npairs = 0;
201       }
202     }
203       break;
204     default:
205       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
206       break;
207   }
208
209   return;
210
211 odd_values:
212   {
213     g_critical ("expected an even number of time values for "
214         "synchronization-points");
215     return;
216   }
217 }
218
219 static void
220 theora_parse_get_property (GObject * object, guint prop_id,
221     GValue * value, GParamSpec * pspec)
222 {
223   GstTheoraParse *parse = GST_THEORA_PARSE (object);
224
225   switch (prop_id) {
226     case PROP_SYNCHRONIZATION_POINTS:
227     {
228       GValueArray *array = NULL;
229       guint i;
230
231       array = g_value_array_new (parse->npairs * 2);
232
233       for (i = 0; i < parse->npairs; i++) {
234         GValue v = { 0, };
235
236         g_value_init (&v, G_TYPE_UINT64);
237         g_value_set_uint64 (&v, parse->times[i * 2]);
238         g_value_array_append (array, &v);
239         g_value_set_uint64 (&v, parse->times[i * 2 + 1]);
240         g_value_array_append (array, &v);
241         g_value_unset (&v);
242       }
243
244       g_value_set_boxed (value, array);
245     }
246       break;
247     default:
248       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
249       break;
250   }
251 }
252
253 static void
254 theora_parse_set_header_on_caps (GstTheoraParse * parse, GstCaps * caps)
255 {
256   GstBuffer **bufs;
257   GstStructure *structure;
258   gint i;
259   GValue array = { 0 };
260   GValue value = { 0 };
261
262   bufs = parse->streamheader;
263   structure = gst_caps_get_structure (caps, 0);
264   g_value_init (&array, GST_TYPE_ARRAY);
265
266   for (i = 0; i < 3; i++) {
267     if (bufs[i] == NULL)
268       continue;
269
270     bufs[i] = gst_buffer_make_metadata_writable (bufs[i]);
271     GST_BUFFER_FLAG_SET (bufs[i], GST_BUFFER_FLAG_IN_CAPS);
272
273     g_value_init (&value, GST_TYPE_BUFFER);
274     gst_value_set_buffer (&value, bufs[i]);
275     gst_value_array_append_value (&array, &value);
276     g_value_unset (&value);
277   }
278
279   gst_structure_set_value (structure, "streamheader", &array);
280   g_value_unset (&array);
281 }
282
283 /* two tasks to do here: set the streamheader on the caps, and use libtheora to
284    parse the headers */
285 static void
286 theora_parse_set_streamheader (GstTheoraParse * parse)
287 {
288   GstCaps *caps;
289   gint i;
290   guint32 bitstream_version;
291   th_setup_info *setup = NULL;
292
293   g_assert (!parse->streamheader_received);
294
295   caps = gst_caps_make_writable (gst_pad_get_caps (parse->srcpad));
296   theora_parse_set_header_on_caps (parse, caps);
297   GST_DEBUG_OBJECT (parse, "here are the caps: %" GST_PTR_FORMAT, caps);
298   gst_pad_set_caps (parse->srcpad, caps);
299   gst_caps_unref (caps);
300
301   for (i = 0; i < 3; i++) {
302     ogg_packet packet;
303     GstBuffer *buf;
304     int ret;
305
306     buf = parse->streamheader[i];
307     if (buf == NULL)
308       continue;
309
310     packet.packet = GST_BUFFER_DATA (buf);
311     packet.bytes = GST_BUFFER_SIZE (buf);
312     packet.granulepos = GST_BUFFER_OFFSET_END (buf);
313     packet.packetno = i + 1;
314     packet.e_o_s = 0;
315     packet.b_o_s = (i == 0);
316     ret = th_decode_headerin (&parse->info, &parse->comment, &setup, &packet);
317     if (ret < 0) {
318       GST_WARNING_OBJECT (parse, "Failed to decode Theora header %d: %d\n",
319           i + 1, ret);
320     }
321   }
322   if (setup) {
323     th_setup_free (setup);
324   }
325
326   parse->fps_n = parse->info.fps_numerator;
327   parse->fps_d = parse->info.fps_denominator;
328   parse->shift = parse->info.keyframe_granule_shift;
329
330   /* With libtheora-1.0beta1 the granulepos scheme was changed:
331    * where earlier the granulepos refered to the index/beginning
332    * of a frame, it now refers to the end, which matches the use
333    * in vorbis/speex. We check the bitstream version from the header so
334    * we know which way to interpret the incoming granuepos
335    */
336   bitstream_version = (parse->info.version_major << 16) |
337       (parse->info.version_minor << 8) | parse->info.version_subminor;
338   parse->is_old_bitstream = (bitstream_version <= 0x00030200);
339
340   parse->streamheader_received = TRUE;
341 }
342
343 static void
344 theora_parse_drain_event_queue (GstTheoraParse * parse)
345 {
346   while (parse->event_queue->length) {
347     GstEvent *event;
348
349     event = GST_EVENT_CAST (g_queue_pop_head (parse->event_queue));
350     gst_pad_event_default (parse->sinkpad, event);
351   }
352 }
353
354 static void
355 theora_parse_push_headers (GstTheoraParse * parse)
356 {
357   gint i;
358
359   theora_parse_drain_event_queue (parse);
360
361   if (!parse->streamheader_received)
362     theora_parse_set_streamheader (parse);
363
364   /* ignore return values, we pass along the result of pushing data packets only
365    */
366   for (i = 0; i < 3; i++) {
367     GstBuffer *buf;
368
369     if ((buf = parse->streamheader[i])) {
370       buf = gst_buffer_make_metadata_writable (buf);
371       gst_buffer_set_caps (buf, GST_PAD_CAPS (parse->srcpad));
372       gst_pad_push (parse->srcpad, buf);
373       parse->streamheader[i] = NULL;
374     }
375   }
376 }
377
378 static void
379 theora_parse_clear_queue (GstTheoraParse * parse)
380 {
381   while (parse->buffer_queue->length) {
382     GstBuffer *buf;
383
384     buf = GST_BUFFER_CAST (g_queue_pop_head (parse->buffer_queue));
385     gst_buffer_unref (buf);
386   }
387   while (parse->event_queue->length) {
388     GstEvent *event;
389
390     event = GST_EVENT_CAST (g_queue_pop_head (parse->event_queue));
391     gst_event_unref (event);
392   }
393 }
394
395 static gint64
396 make_granulepos (GstTheoraParse * parse, gint64 keyframe, gint64 frame)
397 {
398   gint64 iframe;
399
400   if (keyframe == -1)
401     keyframe = 0;
402   /* If using newer theora, offset the granulepos by +1, see comment in
403    * theora_parse_set_streamheader.
404    * 
405    * We don't increment keyframe directly, as internally we always index frames
406    * starting from 0 and we do some sanity checking below. */
407   if (!parse->is_old_bitstream)
408     iframe = keyframe + 1;
409   else
410     iframe = keyframe;
411
412   g_return_val_if_fail (frame >= keyframe, -1);
413   g_return_val_if_fail (frame - keyframe < 1 << parse->shift, -1);
414
415   return (iframe << parse->shift) + (frame - keyframe);
416 }
417
418 static void
419 parse_granulepos (GstTheoraParse * parse, gint64 granulepos,
420     gint64 * keyframe, gint64 * frame)
421 {
422   gint64 kf;
423
424   kf = granulepos >> parse->shift;
425   /* If using newer theora, offset the granulepos by -1, see comment
426    * in theora_parse_set_streamheader */
427   if (!parse->is_old_bitstream)
428     kf -= 1;
429   if (keyframe)
430     *keyframe = kf;
431   if (frame)
432     *frame = kf + (granulepos & ((1 << parse->shift) - 1));
433 }
434
435 static gboolean
436 is_keyframe (GstBuffer * buf)
437 {
438   if (!GST_BUFFER_DATA (buf))
439     return FALSE;
440   if (!GST_BUFFER_SIZE (buf))
441     return FALSE;
442   return ((GST_BUFFER_DATA (buf)[0] & 0x40) == 0);
443 }
444
445 static void
446 theora_parse_munge_granulepos (GstTheoraParse * parse, GstBuffer * buf,
447     gint64 keyframe, gint64 frame)
448 {
449   gint64 frames_diff;
450   GstClockTimeDiff time_diff;
451
452   if (keyframe == frame) {
453     gint i;
454
455     /* update granule_offset */
456     for (i = 0; i < parse->npairs; i++) {
457       if (parse->times[i * 2] >= GST_BUFFER_OFFSET (buf))
458         break;
459     }
460     if (i > 0) {
461       /* time_diff gets reset below */
462       time_diff = parse->times[i * 2 - 1] - parse->times[i * 2 - 2];
463       parse->granule_offset = gst_util_uint64_scale (time_diff,
464           parse->fps_n, parse->fps_d * GST_SECOND);
465       parse->granule_offset <<= parse->shift;
466     }
467   }
468
469   frames_diff = parse->granule_offset >> parse->shift;
470   time_diff = gst_util_uint64_scale_int (GST_SECOND * frames_diff,
471       parse->fps_d, parse->fps_n);
472
473   GST_DEBUG_OBJECT (parse, "offsetting theora stream by %" G_GINT64_FORMAT
474       " frames (%" GST_TIME_FORMAT ")", frames_diff, GST_TIME_ARGS (time_diff));
475
476   GST_BUFFER_OFFSET_END (buf) += parse->granule_offset;
477   GST_BUFFER_OFFSET (buf) += time_diff;
478   GST_BUFFER_TIMESTAMP (buf) += time_diff;
479 }
480
481 static GstFlowReturn
482 theora_parse_push_buffer (GstTheoraParse * parse, GstBuffer * buf,
483     gint64 keyframe, gint64 frame)
484 {
485
486   GstClockTime this_time, next_time;
487
488   this_time = gst_util_uint64_scale_int (GST_SECOND * frame,
489       parse->fps_d, parse->fps_n);
490
491   next_time = gst_util_uint64_scale_int (GST_SECOND * (frame + 1),
492       parse->fps_d, parse->fps_n);
493
494   GST_BUFFER_OFFSET_END (buf) = make_granulepos (parse, keyframe, frame);
495   GST_BUFFER_OFFSET (buf) = this_time;
496   GST_BUFFER_TIMESTAMP (buf) = this_time;
497   GST_BUFFER_DURATION (buf) = next_time - this_time;
498
499   gst_buffer_set_caps (buf, GST_PAD_CAPS (parse->srcpad));
500
501   if (parse->times)
502     theora_parse_munge_granulepos (parse, buf, keyframe, frame);
503
504   GST_DEBUG_OBJECT (parse, "pushing buffer with granulepos %" G_GINT64_FORMAT
505       "|%" G_GINT64_FORMAT, keyframe, frame - keyframe);
506
507   return gst_pad_push (parse->srcpad, buf);
508 }
509
510 static GstFlowReturn
511 theora_parse_drain_queue_prematurely (GstTheoraParse * parse)
512 {
513   GstFlowReturn ret = GST_FLOW_OK;
514
515   /* got an EOS event, make sure to push out any buffers that were in the queue
516    * -- won't normally be the case, but this catches the
517    * didn't-get-a-granulepos-on-the-last-packet case. Assuming a continuous
518    * stream. */
519
520   GST_DEBUG_OBJECT (parse, "got EOS, draining queue");
521
522   /* if we get an eos before pushing the streamheaders, drain our events before
523    * eos */
524   theora_parse_drain_event_queue (parse);
525
526   while (!g_queue_is_empty (parse->buffer_queue)) {
527     GstBuffer *buf;
528
529     buf = GST_BUFFER_CAST (g_queue_pop_head (parse->buffer_queue));
530
531     parse->prev_frame++;
532
533     if (is_keyframe (buf))
534       /* we have a keyframe */
535       parse->prev_keyframe = parse->prev_frame;
536     else
537       GST_BUFFER_FLAGS (buf) |= GST_BUFFER_FLAG_DELTA_UNIT;
538
539     if (parse->prev_keyframe < 0) {
540       if (GST_BUFFER_OFFSET_END_IS_VALID (buf)) {
541         parse_granulepos (parse, GST_BUFFER_OFFSET_END (buf),
542             &parse->prev_keyframe, NULL);
543       } else {
544         /* No previous keyframe known; can't extract one from this frame. That
545          * means we can't do any valid output for this frame, just continue to
546          * the next frame.
547          */
548         gst_buffer_unref (buf);
549         continue;
550       }
551     }
552
553     ret = theora_parse_push_buffer (parse, buf, parse->prev_keyframe,
554         parse->prev_frame);
555
556     if (ret != GST_FLOW_OK)
557       goto done;
558   }
559
560 done:
561   return ret;
562 }
563
564 static GstFlowReturn
565 theora_parse_drain_queue (GstTheoraParse * parse, gint64 granulepos)
566 {
567   GstFlowReturn ret = GST_FLOW_OK;
568   gint64 keyframe, prev_frame, frame;
569
570   parse_granulepos (parse, granulepos, &keyframe, &frame);
571
572   GST_DEBUG ("draining queue of length %d",
573       g_queue_get_length (parse->buffer_queue));
574
575   GST_LOG_OBJECT (parse, "gp %" G_GINT64_FORMAT ", kf %" G_GINT64_FORMAT
576       ", frame %" G_GINT64_FORMAT, granulepos, keyframe, frame);
577
578   prev_frame = frame - g_queue_get_length (parse->buffer_queue);
579
580   GST_LOG_OBJECT (parse,
581       "new prev %" G_GINT64_FORMAT ", prev %" G_GINT64_FORMAT, prev_frame,
582       parse->prev_frame);
583
584   if (prev_frame < parse->prev_frame) {
585     GST_WARNING ("jumped %" G_GINT64_FORMAT
586         " frames backwards! not sure what to do here",
587         parse->prev_frame - prev_frame);
588     parse->prev_frame = prev_frame;
589   } else if (prev_frame > parse->prev_frame) {
590     GST_INFO ("discontinuity detected (%" G_GINT64_FORMAT
591         " frames)", prev_frame - parse->prev_frame);
592     if (keyframe <= prev_frame && keyframe > parse->prev_keyframe)
593       parse->prev_keyframe = keyframe;
594     parse->prev_frame = prev_frame;
595   }
596
597   while (!g_queue_is_empty (parse->buffer_queue)) {
598     GstBuffer *buf;
599
600     parse->prev_frame++;
601     g_assert (parse->prev_frame >= 0);
602
603     buf = GST_BUFFER_CAST (g_queue_pop_head (parse->buffer_queue));
604
605     if (is_keyframe (buf))
606       /* we have a keyframe */
607       parse->prev_keyframe = parse->prev_frame;
608     else
609       GST_BUFFER_FLAGS (buf) |= GST_BUFFER_FLAG_DELTA_UNIT;
610
611     ret = theora_parse_push_buffer (parse, buf, parse->prev_keyframe,
612         parse->prev_frame);
613
614     if (ret != GST_FLOW_OK)
615       goto done;
616   }
617
618 done:
619   return ret;
620 }
621
622 static GstFlowReturn
623 theora_parse_queue_buffer (GstTheoraParse * parse, GstBuffer * buf)
624 {
625   GstFlowReturn ret = GST_FLOW_OK;
626
627   buf = gst_buffer_make_metadata_writable (buf);
628
629   g_queue_push_tail (parse->buffer_queue, buf);
630
631   if (GST_BUFFER_OFFSET_END_IS_VALID (buf)) {
632     if (parse->prev_keyframe < 0) {
633       parse_granulepos (parse, GST_BUFFER_OFFSET_END (buf),
634           &parse->prev_keyframe, NULL);
635     }
636     ret = theora_parse_drain_queue (parse, GST_BUFFER_OFFSET_END (buf));
637   }
638
639   return ret;
640 }
641
642 static GstFlowReturn
643 theora_parse_chain (GstPad * pad, GstBuffer * buffer)
644 {
645   GstFlowReturn ret;
646   GstTheoraParse *parse;
647   guint8 *data;
648   guint size;
649   gboolean have_header;
650
651   parse = GST_THEORA_PARSE (gst_pad_get_parent (pad));
652
653   data = GST_BUFFER_DATA (buffer);
654   size = GST_BUFFER_SIZE (buffer);
655
656   have_header = FALSE;
657   if (size >= 1) {
658     if (data[0] & 0x80)
659       have_header = TRUE;
660   }
661
662   if (have_header) {
663     if (parse->send_streamheader) {
664       /* we need to collect the headers still */
665       /* so put it on the streamheader list and return */
666       if (data[0] >= 0x80 && data[0] <= 0x82)
667         parse->streamheader[data[0] - 0x80] = buffer;
668     }
669     ret = GST_FLOW_OK;
670   } else {
671     /* data packet, push the headers we collected before */
672     if (parse->send_streamheader) {
673       theora_parse_push_headers (parse);
674       parse->send_streamheader = FALSE;
675     }
676
677     ret = theora_parse_queue_buffer (parse, buffer);
678   }
679
680   gst_object_unref (parse);
681
682   return ret;
683 }
684
685 static gboolean
686 theora_parse_queue_event (GstTheoraParse * parse, GstEvent * event)
687 {
688   g_queue_push_tail (parse->event_queue, event);
689   return TRUE;
690 }
691
692 static gboolean
693 theora_parse_sink_event (GstPad * pad, GstEvent * event)
694 {
695   gboolean ret;
696   GstTheoraParse *parse;
697
698   parse = GST_THEORA_PARSE (gst_pad_get_parent (pad));
699
700   switch (GST_EVENT_TYPE (event)) {
701     case GST_EVENT_FLUSH_STOP:
702       theora_parse_clear_queue (parse);
703       parse->prev_keyframe = -1;
704       parse->prev_frame = -1;
705       ret = gst_pad_event_default (pad, event);
706       break;
707     case GST_EVENT_EOS:
708       theora_parse_drain_queue_prematurely (parse);
709       ret = gst_pad_event_default (pad, event);
710       break;
711     default:
712       if (parse->send_streamheader && GST_EVENT_IS_SERIALIZED (event))
713         ret = theora_parse_queue_event (parse, event);
714       else
715         ret = gst_pad_event_default (pad, event);
716       break;
717   }
718
719   gst_object_unref (parse);
720
721   return ret;
722 }
723
724 static gboolean
725 theora_parse_src_convert (GstPad * pad,
726     GstFormat src_format, gint64 src_value,
727     GstFormat * dest_format, gint64 * dest_value)
728 {
729   gboolean res = TRUE;
730   GstTheoraParse *parse;
731   guint64 scale = 1;
732
733   if (src_format == *dest_format) {
734     *dest_value = src_value;
735     return TRUE;
736   }
737
738   parse = GST_THEORA_PARSE (gst_pad_get_parent (pad));
739
740   /* we need the info part before we can done something */
741   if (!parse->streamheader_received)
742     goto no_header;
743
744   switch (src_format) {
745     case GST_FORMAT_BYTES:
746       switch (*dest_format) {
747         case GST_FORMAT_DEFAULT:
748           *dest_value = gst_util_uint64_scale_int (src_value, 2,
749               parse->info.pic_height * parse->info.pic_width * 3);
750           break;
751         case GST_FORMAT_TIME:
752           /* seems like a rather silly conversion, implement me if you like */
753         default:
754           res = FALSE;
755       }
756       break;
757     case GST_FORMAT_TIME:
758       switch (*dest_format) {
759         case GST_FORMAT_BYTES:
760           scale = 3 * (parse->info.pic_width * parse->info.pic_height) / 2;
761         case GST_FORMAT_DEFAULT:
762           *dest_value = scale * gst_util_uint64_scale (src_value,
763               parse->info.fps_numerator,
764               parse->info.fps_denominator * GST_SECOND);
765           break;
766         default:
767           GST_DEBUG_OBJECT (parse, "cannot convert to format %s",
768               gst_format_get_name (*dest_format));
769           res = FALSE;
770       }
771       break;
772     case GST_FORMAT_DEFAULT:
773       switch (*dest_format) {
774         case GST_FORMAT_TIME:
775           *dest_value = gst_util_uint64_scale (src_value,
776               GST_SECOND * parse->info.fps_denominator,
777               parse->info.fps_numerator);
778           break;
779         case GST_FORMAT_BYTES:
780           *dest_value = gst_util_uint64_scale_int (src_value,
781               3 * parse->info.pic_width * parse->info.pic_height, 2);
782           break;
783         default:
784           res = FALSE;
785       }
786       break;
787     default:
788       res = FALSE;
789   }
790 done:
791   gst_object_unref (parse);
792   return res;
793
794   /* ERRORS */
795 no_header:
796   {
797     GST_DEBUG_OBJECT (parse, "no header yet, cannot convert");
798     res = FALSE;
799     goto done;
800   }
801 }
802
803 static gboolean
804 theora_parse_src_query (GstPad * pad, GstQuery * query)
805 {
806   GstTheoraParse *parse;
807
808   gboolean res = FALSE;
809
810   parse = GST_THEORA_PARSE (gst_pad_get_parent (pad));
811
812   switch (GST_QUERY_TYPE (query)) {
813     case GST_QUERY_POSITION:
814     {
815       gint64 frame, value;
816       GstFormat my_format, format;
817       gint64 time;
818
819       frame = parse->prev_frame;
820
821       GST_LOG_OBJECT (parse,
822           "query %p: we have current frame: %" G_GINT64_FORMAT, query, frame);
823
824       /* parse format */
825       gst_query_parse_position (query, &format, NULL);
826
827       /* and convert to the final format in two steps with time as the 
828        * intermediate step */
829       my_format = GST_FORMAT_TIME;
830       if (!(res =
831               theora_parse_src_convert (parse->sinkpad, GST_FORMAT_DEFAULT,
832                   frame, &my_format, &time)))
833         goto error;
834
835       /* fixme: handle segments
836          time = (time - parse->segment.start) + parse->segment.time;
837        */
838
839       GST_LOG_OBJECT (parse,
840           "query %p: our time: %" GST_TIME_FORMAT " (conv to %s)",
841           query, GST_TIME_ARGS (time), gst_format_get_name (format));
842
843       if (!(res =
844               theora_parse_src_convert (pad, my_format, time, &format, &value)))
845         goto error;
846
847       gst_query_set_position (query, format, value);
848
849       GST_LOG_OBJECT (parse,
850           "query %p: we return %" G_GINT64_FORMAT " (format %u)", query, value,
851           format);
852
853       break;
854     }
855     case GST_QUERY_DURATION:
856       /* forward to peer for total */
857       if (!(res = gst_pad_query (GST_PAD_PEER (parse->sinkpad), query)))
858         goto error;
859       break;
860     case GST_QUERY_CONVERT:
861     {
862       GstFormat src_fmt, dest_fmt;
863       gint64 src_val, dest_val;
864
865       gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, &dest_val);
866       if (!(res =
867               theora_parse_src_convert (pad, src_fmt, src_val, &dest_fmt,
868                   &dest_val)))
869         goto error;
870
871       gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val);
872       break;
873     }
874     default:
875       res = gst_pad_query_default (pad, query);
876       break;
877   }
878 done:
879   gst_object_unref (parse);
880
881   return res;
882
883   /* ERRORS */
884 error:
885   {
886     GST_DEBUG_OBJECT (parse, "query failed");
887     goto done;
888   }
889 }
890
891 static GstStateChangeReturn
892 theora_parse_change_state (GstElement * element, GstStateChange transition)
893 {
894   GstTheoraParse *parse = GST_THEORA_PARSE (element);
895   GstStateChangeReturn ret;
896   gint i;
897
898   switch (transition) {
899     case GST_STATE_CHANGE_READY_TO_PAUSED:
900       th_info_init (&parse->info);
901       th_comment_init (&parse->comment);
902       parse->send_streamheader = TRUE;
903       parse->buffer_queue = g_queue_new ();
904       parse->event_queue = g_queue_new ();
905       parse->prev_keyframe = -1;
906       parse->prev_frame = -1;
907       parse->granule_offset = 0;
908       break;
909     default:
910       break;
911   }
912
913   ret = parent_class->change_state (element, transition);
914
915   switch (transition) {
916     case GST_STATE_CHANGE_PAUSED_TO_READY:
917       th_info_clear (&parse->info);
918       th_comment_clear (&parse->comment);
919       theora_parse_clear_queue (parse);
920       g_queue_free (parse->buffer_queue);
921       g_queue_free (parse->event_queue);
922       parse->buffer_queue = NULL;
923       for (i = 0; i < 3; i++) {
924         if (parse->streamheader[i]) {
925           gst_buffer_unref (parse->streamheader[i]);
926           parse->streamheader[i] = NULL;
927         }
928       }
929       parse->streamheader_received = FALSE;
930       break;
931     default:
932       break;
933   }
934
935   return ret;
936 }