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., 51 Franklin St, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
19 */
20
21 /**
22 * SECTION:element-vorbisparse
23 * @title: vorbisparse
24 * @see_also: vorbisdec, oggdemux, theoraparse
25 *
26 * The vorbisparse element will parse the header packets of the Vorbis
27 * stream and put them as the streamheader in the caps. This is used in the
28 * multifdsink case where you want to stream live vorbis streams to multiple
29 * clients, each client has to receive the streamheaders first before they can
30 * consume the vorbis packets.
31 *
32 * This element also makes sure that the buffers that it pushes out are properly
33 * timestamped and that their offset and offset_end are set. The buffers that
34 * vorbisparse outputs have all of the metadata that oggmux expects to receive,
35 * which allows you to (for example) remux an ogg/vorbis file.
36 *
37 * ## Example pipelines
38 * |[
39 * gst-launch-1.0 -v filesrc location=sine.ogg ! oggdemux ! vorbisparse ! fakesink
40 * ]|
41 * This pipeline shows that the streamheader is set in the caps, and that each
42 * buffer has the timestamp, duration, offset, and offset_end set.
43 * |[
44 * gst-launch-1.0 filesrc location=sine.ogg ! oggdemux ! vorbisparse \
45 * ! oggmux ! filesink location=sine-remuxed.ogg
46 * ]|
47 * This pipeline shows remuxing. sine-remuxed.ogg might not be exactly the same
48 * as sine.ogg, but they should produce exactly the same decoded data.
49 *
50 */
51
52 #ifdef HAVE_CONFIG_H
53 # include "config.h"
54 #endif
55
56 #include "gstvorbisparse.h"
57
58 GST_DEBUG_CATEGORY_EXTERN (vorbisparse_debug);
59 #define GST_CAT_DEFAULT vorbisparse_debug
60
61 static GstStaticPadTemplate vorbis_parse_sink_factory =
62 GST_STATIC_PAD_TEMPLATE ("sink",
63 GST_PAD_SINK,
64 GST_PAD_ALWAYS,
65 GST_STATIC_CAPS ("audio/x-vorbis")
66 );
67
68 static GstStaticPadTemplate vorbis_parse_src_factory =
69 GST_STATIC_PAD_TEMPLATE ("src",
70 GST_PAD_SRC,
71 GST_PAD_ALWAYS,
72 GST_STATIC_CAPS ("audio/x-vorbis")
73 );
74
75 #define gst_vorbis_parse_parent_class parent_class
76 G_DEFINE_TYPE (GstVorbisParse, gst_vorbis_parse, GST_TYPE_ELEMENT);
77
78 static GstFlowReturn vorbis_parse_chain (GstPad * pad, GstObject * parent,
79 GstBuffer * buffer);
80 static GstStateChangeReturn vorbis_parse_change_state (GstElement * element,
81 GstStateChange transition);
82 static gboolean vorbis_parse_sink_event (GstPad * pad, GstObject * parent,
83 GstEvent * event);
84 static gboolean vorbis_parse_src_query (GstPad * pad, GstObject * parent,
85 GstQuery * query);
86 static gboolean vorbis_parse_convert (GstPad * pad, GstFormat src_format,
87 gint64 src_value, GstFormat * dest_format, gint64 * dest_value);
88 static GstFlowReturn vorbis_parse_parse_packet (GstVorbisParse * parse,
89 GstBuffer * buf);
90
91 static void
gst_vorbis_parse_class_init(GstVorbisParseClass * klass)92 gst_vorbis_parse_class_init (GstVorbisParseClass * klass)
93 {
94 GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
95
96 gstelement_class->change_state = vorbis_parse_change_state;
97
98 gst_element_class_add_static_pad_template (gstelement_class,
99 &vorbis_parse_src_factory);
100 gst_element_class_add_static_pad_template (gstelement_class,
101 &vorbis_parse_sink_factory);
102 gst_element_class_set_static_metadata (gstelement_class, "VorbisParse",
103 "Codec/Parser/Audio", "parse raw vorbis streams",
104 "Thomas Vander Stichele <thomas at apestaart dot org>");
105
106 klass->parse_packet = GST_DEBUG_FUNCPTR (vorbis_parse_parse_packet);
107 }
108
109 static void
gst_vorbis_parse_init(GstVorbisParse * parse)110 gst_vorbis_parse_init (GstVorbisParse * parse)
111 {
112 parse->sinkpad =
113 gst_pad_new_from_static_template (&vorbis_parse_sink_factory, "sink");
114 gst_pad_set_chain_function (parse->sinkpad,
115 GST_DEBUG_FUNCPTR (vorbis_parse_chain));
116 gst_pad_set_event_function (parse->sinkpad,
117 GST_DEBUG_FUNCPTR (vorbis_parse_sink_event));
118 gst_element_add_pad (GST_ELEMENT (parse), parse->sinkpad);
119
120 parse->srcpad =
121 gst_pad_new_from_static_template (&vorbis_parse_src_factory, "src");
122 gst_pad_set_query_function (parse->srcpad,
123 GST_DEBUG_FUNCPTR (vorbis_parse_src_query));
124 gst_element_add_pad (GST_ELEMENT (parse), parse->srcpad);
125 }
126
127 static void
vorbis_parse_set_header_on_caps(GstVorbisParse * parse,GstCaps * caps)128 vorbis_parse_set_header_on_caps (GstVorbisParse * parse, GstCaps * caps)
129 {
130 GstBuffer *buf1, *buf2, *buf3;
131 GstStructure *structure;
132 GValue array = { 0 };
133 GValue value = { 0 };
134
135 g_assert (parse);
136 g_assert (parse->streamheader);
137 g_assert (parse->streamheader->next);
138 g_assert (parse->streamheader->next->next);
139 buf1 = parse->streamheader->data;
140 g_assert (buf1);
141 buf2 = parse->streamheader->next->data;
142 g_assert (buf2);
143 buf3 = parse->streamheader->next->next->data;
144 g_assert (buf3);
145
146 structure = gst_caps_get_structure (caps, 0);
147
148 /* mark buffers */
149 GST_BUFFER_FLAG_SET (buf1, GST_BUFFER_FLAG_HEADER);
150 GST_BUFFER_FLAG_SET (buf2, GST_BUFFER_FLAG_HEADER);
151 GST_BUFFER_FLAG_SET (buf3, GST_BUFFER_FLAG_HEADER);
152
153 /* put buffers in a fixed list */
154 g_value_init (&array, GST_TYPE_ARRAY);
155 g_value_init (&value, GST_TYPE_BUFFER);
156 gst_value_set_buffer (&value, buf1);
157 gst_value_array_append_value (&array, &value);
158 g_value_unset (&value);
159 g_value_init (&value, GST_TYPE_BUFFER);
160 gst_value_set_buffer (&value, buf2);
161 gst_value_array_append_value (&array, &value);
162 g_value_unset (&value);
163 g_value_init (&value, GST_TYPE_BUFFER);
164 gst_value_set_buffer (&value, buf3);
165 gst_value_array_append_value (&array, &value);
166 gst_structure_take_value (structure, "streamheader", &array);
167 g_value_unset (&value);
168 }
169
170 static void
vorbis_parse_drain_event_queue(GstVorbisParse * parse)171 vorbis_parse_drain_event_queue (GstVorbisParse * parse)
172 {
173 while (parse->event_queue->length) {
174 GstEvent *event;
175
176 event = GST_EVENT_CAST (g_queue_pop_head (parse->event_queue));
177 gst_pad_event_default (parse->sinkpad, GST_OBJECT_CAST (parse), event);
178 }
179 }
180
181 static gboolean
vorbis_parse_have_header_packet(GstVorbisParse * parse,guint8 hdr_id)182 vorbis_parse_have_header_packet (GstVorbisParse * parse, guint8 hdr_id)
183 {
184 guint8 hdr;
185 GList *l;
186
187 for (l = parse->streamheader; l != NULL; l = l->next) {
188 if (gst_buffer_extract (l->data, 0, &hdr, 1) == 1 && hdr == hdr_id)
189 return TRUE;
190 }
191
192 return FALSE;
193 }
194
195 static gboolean
vorbis_parse_push_headers(GstVorbisParse * parse)196 vorbis_parse_push_headers (GstVorbisParse * parse)
197 {
198 /* mark and put on caps */
199 GstCaps *caps;
200 GstBuffer *outbuf, *outbuf1, *outbuf2, *outbuf3;
201 ogg_packet packet;
202 GstMapInfo map;
203 const gchar *hdr_name;
204
205 /* Check we have enough header packets, and the right ones */
206 hdr_name = "identification";
207 if (!vorbis_parse_have_header_packet (parse, 1))
208 goto missing_header;
209
210 hdr_name = "comment";
211 if (!vorbis_parse_have_header_packet (parse, 3))
212 goto missing_header;
213
214 hdr_name = "setup";
215 if (!vorbis_parse_have_header_packet (parse, 5))
216 goto missing_header;
217
218 outbuf = GST_BUFFER_CAST (parse->streamheader->data);
219 gst_buffer_map (outbuf, &map, GST_MAP_READ);
220 packet.packet = map.data;
221 packet.bytes = map.size;
222 packet.granulepos = GST_BUFFER_OFFSET_END (outbuf);
223 packet.packetno = 1;
224 packet.e_o_s = 0;
225 packet.b_o_s = 1;
226 vorbis_synthesis_headerin (&parse->vi, &parse->vc, &packet);
227 gst_buffer_unmap (outbuf, &map);
228 parse->sample_rate = parse->vi.rate;
229 parse->channels = parse->vi.channels;
230 outbuf1 = outbuf;
231
232 outbuf = GST_BUFFER_CAST (parse->streamheader->next->data);
233 gst_buffer_map (outbuf, &map, GST_MAP_READ);
234 packet.packet = map.data;
235 packet.bytes = map.size;
236 packet.granulepos = GST_BUFFER_OFFSET_END (outbuf);
237 packet.packetno = 2;
238 packet.e_o_s = 0;
239 packet.b_o_s = 0;
240 vorbis_synthesis_headerin (&parse->vi, &parse->vc, &packet);
241 gst_buffer_unmap (outbuf, &map);
242 outbuf2 = outbuf;
243
244 outbuf = GST_BUFFER_CAST (parse->streamheader->next->next->data);
245 gst_buffer_map (outbuf, &map, GST_MAP_READ);
246 packet.packet = map.data;
247 packet.bytes = map.size;
248 packet.granulepos = GST_BUFFER_OFFSET_END (outbuf);
249 packet.packetno = 3;
250 packet.e_o_s = 0;
251 packet.b_o_s = 0;
252 vorbis_synthesis_headerin (&parse->vi, &parse->vc, &packet);
253 gst_buffer_unmap (outbuf, &map);
254 outbuf3 = outbuf;
255
256 /* get the headers into the caps, passing them to vorbis as we go */
257 caps = gst_caps_new_simple ("audio/x-vorbis",
258 "rate", G_TYPE_INT, parse->sample_rate,
259 "channels", G_TYPE_INT, parse->channels, NULL);
260 vorbis_parse_set_header_on_caps (parse, caps);
261 GST_DEBUG_OBJECT (parse, "here are the caps: %" GST_PTR_FORMAT, caps);
262 gst_pad_set_caps (parse->srcpad, caps);
263 gst_caps_unref (caps);
264
265 /* first process queued events */
266 vorbis_parse_drain_event_queue (parse);
267
268 /* push out buffers, ignoring return value... */
269 gst_pad_push (parse->srcpad, outbuf1);
270 gst_pad_push (parse->srcpad, outbuf2);
271 gst_pad_push (parse->srcpad, outbuf3);
272
273 g_list_free (parse->streamheader);
274 parse->streamheader = NULL;
275 return TRUE;
276
277 /* ERRORS */
278 missing_header:
279 {
280 GST_ELEMENT_ERROR (parse, STREAM, DECODE, (NULL),
281 ("Vorbis stream is missing %s header", hdr_name));
282 return FALSE;
283 }
284 }
285
286 static void
vorbis_parse_clear_queue(GstVorbisParse * parse)287 vorbis_parse_clear_queue (GstVorbisParse * parse)
288 {
289 while (parse->buffer_queue->length) {
290 GstBuffer *buf;
291
292 buf = GST_BUFFER_CAST (g_queue_pop_head (parse->buffer_queue));
293 gst_buffer_unref (buf);
294 }
295 while (parse->event_queue->length) {
296 GstEvent *event;
297
298 event = GST_EVENT_CAST (g_queue_pop_head (parse->event_queue));
299 gst_event_unref (event);
300 }
301 }
302
303 static GstFlowReturn
vorbis_parse_push_buffer(GstVorbisParse * parse,GstBuffer * buf,gint64 granulepos)304 vorbis_parse_push_buffer (GstVorbisParse * parse, GstBuffer * buf,
305 gint64 granulepos)
306 {
307 guint64 samples;
308
309 /* our hack as noted below */
310 samples = GST_BUFFER_OFFSET (buf);
311
312 GST_BUFFER_OFFSET_END (buf) = granulepos;
313 GST_BUFFER_DURATION (buf) = samples * GST_SECOND / parse->sample_rate;
314 GST_BUFFER_OFFSET (buf) = granulepos * GST_SECOND / parse->sample_rate;
315 GST_BUFFER_TIMESTAMP (buf) =
316 GST_BUFFER_OFFSET (buf) - GST_BUFFER_DURATION (buf);
317
318 return gst_pad_push (parse->srcpad, buf);
319 }
320
321 static GstFlowReturn
vorbis_parse_drain_queue_prematurely(GstVorbisParse * parse)322 vorbis_parse_drain_queue_prematurely (GstVorbisParse * parse)
323 {
324 GstFlowReturn ret = GST_FLOW_OK;
325 gint64 granulepos = MAX (parse->prev_granulepos, 0);
326
327 /* got an EOS event, make sure to push out any buffers that were in the queue
328 * -- won't normally be the case, but this catches the
329 * didn't-get-a-granulepos-on-the-last-packet case. Assuming a continuous
330 * stream. */
331
332 /* if we got EOS before any buffers came, go ahead and push the other events
333 * first */
334 vorbis_parse_drain_event_queue (parse);
335
336 while (!g_queue_is_empty (parse->buffer_queue)) {
337 GstBuffer *buf;
338
339 buf = GST_BUFFER_CAST (g_queue_pop_head (parse->buffer_queue));
340
341 granulepos += GST_BUFFER_OFFSET (buf);
342 ret = vorbis_parse_push_buffer (parse, buf, granulepos);
343
344 if (ret != GST_FLOW_OK)
345 goto done;
346 }
347
348 parse->prev_granulepos = granulepos;
349
350 done:
351 return ret;
352 }
353
354 static GstFlowReturn
vorbis_parse_drain_queue(GstVorbisParse * parse,gint64 granulepos)355 vorbis_parse_drain_queue (GstVorbisParse * parse, gint64 granulepos)
356 {
357 GstFlowReturn ret = GST_FLOW_OK;
358 GList *walk;
359 gint64 cur = granulepos;
360 gint64 gp;
361
362 for (walk = parse->buffer_queue->head; walk; walk = walk->next)
363 cur -= GST_BUFFER_OFFSET (walk->data);
364
365 if (parse->prev_granulepos != -1)
366 cur = MAX (cur, parse->prev_granulepos);
367
368 while (!g_queue_is_empty (parse->buffer_queue)) {
369 GstBuffer *buf;
370
371 buf = GST_BUFFER_CAST (g_queue_pop_head (parse->buffer_queue));
372
373 cur += GST_BUFFER_OFFSET (buf);
374 gp = CLAMP (cur, 0, granulepos);
375
376 ret = vorbis_parse_push_buffer (parse, buf, gp);
377
378 if (ret != GST_FLOW_OK)
379 goto done;
380 }
381
382 parse->prev_granulepos = granulepos;
383
384 done:
385 return ret;
386 }
387
388 static GstFlowReturn
vorbis_parse_queue_buffer(GstVorbisParse * parse,GstBuffer * buf)389 vorbis_parse_queue_buffer (GstVorbisParse * parse, GstBuffer * buf)
390 {
391 GstFlowReturn ret = GST_FLOW_OK;
392 long blocksize;
393 ogg_packet packet;
394 GstMapInfo map;
395
396 buf = gst_buffer_make_writable (buf);
397
398 gst_buffer_map (buf, &map, GST_MAP_READ);
399 packet.packet = map.data;
400 packet.bytes = map.size;
401 GST_DEBUG ("%p, %" G_GSIZE_FORMAT, map.data, map.size);
402 packet.granulepos = GST_BUFFER_OFFSET_END (buf);
403 packet.packetno = parse->packetno + parse->buffer_queue->length;
404 packet.e_o_s = 0;
405
406 blocksize = vorbis_packet_blocksize (&parse->vi, &packet);
407 gst_buffer_unmap (buf, &map);
408
409 /* temporarily store the sample count in OFFSET -- we overwrite this later */
410
411 if (parse->prev_blocksize < 0)
412 GST_BUFFER_OFFSET (buf) = 0;
413 else
414 GST_BUFFER_OFFSET (buf) = (blocksize + parse->prev_blocksize) / 4;
415
416 parse->prev_blocksize = blocksize;
417
418 g_queue_push_tail (parse->buffer_queue, buf);
419
420 if (GST_BUFFER_OFFSET_END_IS_VALID (buf))
421 ret = vorbis_parse_drain_queue (parse, GST_BUFFER_OFFSET_END (buf));
422
423 return ret;
424 }
425
426 static GstFlowReturn
vorbis_parse_parse_packet(GstVorbisParse * parse,GstBuffer * buf)427 vorbis_parse_parse_packet (GstVorbisParse * parse, GstBuffer * buf)
428 {
429 GstFlowReturn ret;
430 GstMapInfo map;
431 gboolean have_header;
432
433 parse->packetno++;
434
435 have_header = FALSE;
436 gst_buffer_map (buf, &map, GST_MAP_READ);
437 if (map.size >= 1) {
438 if (map.data[0] & 1)
439 have_header = TRUE;
440 }
441 gst_buffer_unmap (buf, &map);
442
443 if (have_header) {
444 if (!parse->streamheader_sent) {
445 /* we need to collect the headers still */
446 /* so put it on the streamheader list and return */
447 parse->streamheader = g_list_append (parse->streamheader, buf);
448 }
449 ret = GST_FLOW_OK;
450 } else {
451 /* data packet, push the headers we collected before */
452 if (!parse->streamheader_sent) {
453 if (!vorbis_parse_push_headers (parse)) {
454 ret = GST_FLOW_ERROR;
455 goto out;
456 }
457 parse->streamheader_sent = TRUE;
458 }
459 ret = vorbis_parse_queue_buffer (parse, buf);
460 }
461
462 out:
463
464 return ret;
465 }
466
467 static GstFlowReturn
vorbis_parse_chain(GstPad * pad,GstObject * parent,GstBuffer * buffer)468 vorbis_parse_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer)
469 {
470 GstVorbisParseClass *klass;
471 GstVorbisParse *parse;
472
473 parse = GST_VORBIS_PARSE (parent);
474 klass = GST_VORBIS_PARSE_CLASS (G_OBJECT_GET_CLASS (parse));
475
476 g_assert (klass->parse_packet != NULL);
477
478 return klass->parse_packet (parse, buffer);
479 }
480
481 static gboolean
vorbis_parse_queue_event(GstVorbisParse * parse,GstEvent * event)482 vorbis_parse_queue_event (GstVorbisParse * parse, GstEvent * event)
483 {
484 GstFlowReturn ret = TRUE;
485
486 g_queue_push_tail (parse->event_queue, event);
487
488 return ret;
489 }
490
491 static gboolean
vorbis_parse_sink_event(GstPad * pad,GstObject * parent,GstEvent * event)492 vorbis_parse_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
493 {
494 gboolean ret;
495 GstVorbisParse *parse;
496
497 parse = GST_VORBIS_PARSE (parent);
498
499 switch (GST_EVENT_TYPE (event)) {
500 case GST_EVENT_FLUSH_STOP:
501 vorbis_parse_clear_queue (parse);
502 parse->prev_granulepos = -1;
503 parse->prev_blocksize = -1;
504 ret = gst_pad_event_default (pad, parent, event);
505 break;
506 case GST_EVENT_EOS:
507 vorbis_parse_drain_queue_prematurely (parse);
508 ret = gst_pad_event_default (pad, parent, event);
509 break;
510 default:
511 if (!parse->streamheader_sent && GST_EVENT_IS_SERIALIZED (event)
512 && GST_EVENT_TYPE (event) > GST_EVENT_CAPS)
513 ret = vorbis_parse_queue_event (parse, event);
514 else
515 ret = gst_pad_event_default (pad, parent, event);
516 break;
517 }
518
519 return ret;
520 }
521
522 static gboolean
vorbis_parse_convert(GstPad * pad,GstFormat src_format,gint64 src_value,GstFormat * dest_format,gint64 * dest_value)523 vorbis_parse_convert (GstPad * pad,
524 GstFormat src_format, gint64 src_value,
525 GstFormat * dest_format, gint64 * dest_value)
526 {
527 gboolean res = TRUE;
528 GstVorbisParse *parse;
529 guint64 scale = 1;
530
531 parse = GST_VORBIS_PARSE (GST_PAD_PARENT (pad));
532
533 /* fixme: assumes atomic access to lots of instance variables modified from
534 * the streaming thread, including 64-bit variables */
535
536 if (parse->packetno < 4)
537 return FALSE;
538
539 if (src_format == *dest_format) {
540 *dest_value = src_value;
541 return TRUE;
542 }
543
544 if (parse->sinkpad == pad &&
545 (src_format == GST_FORMAT_BYTES || *dest_format == GST_FORMAT_BYTES))
546 return FALSE;
547
548 switch (src_format) {
549 case GST_FORMAT_TIME:
550 switch (*dest_format) {
551 case GST_FORMAT_BYTES:
552 scale = sizeof (float) * parse->vi.channels;
553 case GST_FORMAT_DEFAULT:
554 *dest_value =
555 scale * gst_util_uint64_scale_int (src_value, parse->vi.rate,
556 GST_SECOND);
557 break;
558 default:
559 res = FALSE;
560 }
561 break;
562 case GST_FORMAT_DEFAULT:
563 switch (*dest_format) {
564 case GST_FORMAT_BYTES:
565 *dest_value = src_value * sizeof (float) * parse->vi.channels;
566 break;
567 case GST_FORMAT_TIME:
568 *dest_value =
569 gst_util_uint64_scale_int (src_value, GST_SECOND, parse->vi.rate);
570 break;
571 default:
572 res = FALSE;
573 }
574 break;
575 case GST_FORMAT_BYTES:
576 switch (*dest_format) {
577 case GST_FORMAT_DEFAULT:
578 *dest_value = src_value / (sizeof (float) * parse->vi.channels);
579 break;
580 case GST_FORMAT_TIME:
581 *dest_value = gst_util_uint64_scale_int (src_value, GST_SECOND,
582 parse->vi.rate * sizeof (float) * parse->vi.channels);
583 break;
584 default:
585 res = FALSE;
586 }
587 break;
588 default:
589 res = FALSE;
590 }
591
592 return res;
593 }
594
595 static gboolean
vorbis_parse_src_query(GstPad * pad,GstObject * parent,GstQuery * query)596 vorbis_parse_src_query (GstPad * pad, GstObject * parent, GstQuery * query)
597 {
598 gint64 granulepos;
599 GstVorbisParse *parse;
600 gboolean res = FALSE;
601
602 parse = GST_VORBIS_PARSE (parent);
603
604 switch (GST_QUERY_TYPE (query)) {
605 case GST_QUERY_POSITION:
606 {
607 GstFormat format;
608 gint64 value;
609
610 granulepos = parse->prev_granulepos;
611
612 gst_query_parse_position (query, &format, NULL);
613
614 /* and convert to the final format */
615 if (!(res =
616 vorbis_parse_convert (pad, GST_FORMAT_DEFAULT, granulepos,
617 &format, &value)))
618 goto error;
619
620 /* fixme: support segments
621 value = (value - parse->segment_start) + parse->segment_time;
622 */
623
624 gst_query_set_position (query, format, value);
625
626 GST_LOG_OBJECT (parse, "query %p: peer returned granulepos: %"
627 G_GUINT64_FORMAT " - we return %" G_GUINT64_FORMAT " (format %u)",
628 query, granulepos, value, format);
629
630 break;
631 }
632 case GST_QUERY_DURATION:
633 {
634 /* fixme: not threadsafe */
635 /* query peer for total length */
636 if (!gst_pad_is_linked (parse->sinkpad)) {
637 GST_WARNING_OBJECT (parse, "sink pad %" GST_PTR_FORMAT " is not linked",
638 parse->sinkpad);
639 goto error;
640 }
641 if (!(res = gst_pad_peer_query (parse->sinkpad, query)))
642 goto error;
643 break;
644 }
645 case GST_QUERY_CONVERT:
646 {
647 GstFormat src_fmt, dest_fmt;
648 gint64 src_val, dest_val;
649
650 gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, &dest_val);
651 if (!(res =
652 vorbis_parse_convert (pad, src_fmt, src_val, &dest_fmt,
653 &dest_val)))
654 goto error;
655 gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val);
656 break;
657 }
658 default:
659 res = gst_pad_query_default (pad, parent, query);
660 break;
661 }
662 return res;
663
664 error:
665 {
666 GST_WARNING_OBJECT (parse, "error handling query");
667 return res;
668 }
669 }
670
671 static GstStateChangeReturn
vorbis_parse_change_state(GstElement * element,GstStateChange transition)672 vorbis_parse_change_state (GstElement * element, GstStateChange transition)
673 {
674 GstVorbisParse *parse = GST_VORBIS_PARSE (element);
675 GstStateChangeReturn ret;
676
677 switch (transition) {
678 case GST_STATE_CHANGE_READY_TO_PAUSED:
679 vorbis_info_init (&parse->vi);
680 vorbis_comment_init (&parse->vc);
681 parse->prev_granulepos = -1;
682 parse->prev_blocksize = -1;
683 parse->packetno = 0;
684 parse->streamheader_sent = FALSE;
685 parse->buffer_queue = g_queue_new ();
686 parse->event_queue = g_queue_new ();
687 break;
688 default:
689 break;
690 }
691
692 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
693
694 switch (transition) {
695 case GST_STATE_CHANGE_PAUSED_TO_READY:
696 vorbis_info_clear (&parse->vi);
697 vorbis_comment_clear (&parse->vc);
698 vorbis_parse_clear_queue (parse);
699 g_queue_free (parse->buffer_queue);
700 parse->buffer_queue = NULL;
701 g_queue_free (parse->event_queue);
702 parse->event_queue = NULL;
703 break;
704 default:
705 break;
706 }
707
708 return ret;
709 }
710