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