Merge branch 'master' into 0.11
[platform/upstream/gst-plugins-good.git] / ext / speex / gstspeexdec.c
1 /* GStreamer
2  * Copyright (C) 2004 Wim Taymans <wim@fluendo.com>
3  * Copyright (C) 2006 Tim-Philipp Müller <tim centricular net>
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-speexdec
23  * @see_also: speexenc, oggdemux
24  *
25  * This element decodes a Speex stream to raw integer audio.
26  * <ulink url="http://www.speex.org/">Speex</ulink> is a royalty-free
27  * audio codec maintained by the <ulink url="http://www.xiph.org/">Xiph.org
28  * Foundation</ulink>.
29  *
30  * <refsect2>
31  * <title>Example pipelines</title>
32  * |[
33  * gst-launch -v filesrc location=speex.ogg ! oggdemux ! speexdec ! audioconvert ! audioresample ! alsasink
34  * ]| Decode an Ogg/Speex file. To create an Ogg/Speex file refer to the
35  * documentation of speexenc.
36  * </refsect2>
37  *
38  * Last reviewed on 2006-04-05 (0.10.2)
39  */
40
41 #ifdef HAVE_CONFIG_H
42 #  include "config.h"
43 #endif
44
45 #include "gstspeexdec.h"
46 #include <stdlib.h>
47 #include <string.h>
48 #include <gst/tag/tag.h>
49
50 GST_DEBUG_CATEGORY_STATIC (speexdec_debug);
51 #define GST_CAT_DEFAULT speexdec_debug
52
53 #define DEFAULT_ENH   TRUE
54
55 enum
56 {
57   ARG_0,
58   ARG_ENH
59 };
60
61 static GstStaticPadTemplate speex_dec_src_factory =
62 GST_STATIC_PAD_TEMPLATE ("src",
63     GST_PAD_SRC,
64     GST_PAD_ALWAYS,
65     GST_STATIC_CAPS ("audio/x-raw-int, "
66         "rate = (int) [ 6000, 48000 ], "
67         "channels = (int) [ 1, 2 ], "
68         "endianness = (int) BYTE_ORDER, "
69         "signed = (boolean) true, " "width = (int) 16, " "depth = (int) 16")
70     );
71
72 static GstStaticPadTemplate speex_dec_sink_factory =
73 GST_STATIC_PAD_TEMPLATE ("sink",
74     GST_PAD_SINK,
75     GST_PAD_ALWAYS,
76     GST_STATIC_CAPS ("audio/x-speex")
77     );
78
79 #define gst_speex_dec_parent_class parent_class
80 G_DEFINE_TYPE (GstSpeexDec, gst_speex_dec, GST_TYPE_ELEMENT);
81
82 static gboolean speex_dec_sink_event (GstPad * pad, GstEvent * event);
83 static GstFlowReturn speex_dec_chain (GstPad * pad, GstBuffer * buf);
84 static GstStateChangeReturn speex_dec_change_state (GstElement * element,
85     GstStateChange transition);
86
87 static gboolean speex_dec_src_event (GstPad * pad, GstEvent * event);
88 static gboolean speex_dec_src_query (GstPad * pad, GstQuery * query);
89 static gboolean speex_dec_sink_query (GstPad * pad, GstQuery * query);
90 static const GstQueryType *speex_get_src_query_types (GstPad * pad);
91 static const GstQueryType *speex_get_sink_query_types (GstPad * pad);
92 static gboolean speex_dec_convert (GstPad * pad,
93     GstFormat src_format, gint64 src_value,
94     GstFormat * dest_format, gint64 * dest_value);
95
96 static void gst_speex_dec_get_property (GObject * object, guint prop_id,
97     GValue * value, GParamSpec * pspec);
98 static void gst_speex_dec_set_property (GObject * object, guint prop_id,
99     const GValue * value, GParamSpec * pspec);
100
101 static GstFlowReturn speex_dec_chain_parse_data (GstSpeexDec * dec,
102     GstBuffer * buf, GstClockTime timestamp, GstClockTime duration);
103
104 static GstFlowReturn speex_dec_chain_parse_header (GstSpeexDec * dec,
105     GstBuffer * buf);
106 static GstFlowReturn speex_dec_chain_parse_comments (GstSpeexDec * dec,
107     GstBuffer * buf);
108
109 static void
110 gst_speex_dec_class_init (GstSpeexDecClass * klass)
111 {
112   GObjectClass *gobject_class;
113   GstElementClass *gstelement_class;
114
115   gobject_class = (GObjectClass *) klass;
116   gstelement_class = (GstElementClass *) klass;
117
118   gobject_class->set_property = gst_speex_dec_set_property;
119   gobject_class->get_property = gst_speex_dec_get_property;
120
121   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_ENH,
122       g_param_spec_boolean ("enh", "Enh", "Enable perceptual enhancement",
123           DEFAULT_ENH, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
124
125   gstelement_class->change_state = GST_DEBUG_FUNCPTR (speex_dec_change_state);
126
127   gst_element_class_add_pad_template (gstelement_class,
128       gst_static_pad_template_get (&speex_dec_src_factory));
129   gst_element_class_add_pad_template (gstelement_class,
130       gst_static_pad_template_get (&speex_dec_sink_factory));
131   gst_element_class_set_details_simple (gstelement_class, "Speex audio decoder",
132       "Codec/Decoder/Audio",
133       "decode speex streams to audio", "Wim Taymans <wim@fluendo.com>");
134
135   GST_DEBUG_CATEGORY_INIT (speexdec_debug, "speexdec", 0,
136       "speex decoding element");
137 }
138
139 static void
140 gst_speex_dec_reset (GstSpeexDec * dec)
141 {
142   gst_segment_init (&dec->segment, GST_FORMAT_UNDEFINED);
143   dec->packetno = 0;
144   dec->frame_size = 0;
145   dec->frame_duration = 0;
146   dec->mode = NULL;
147   free (dec->header);
148   dec->header = NULL;
149   speex_bits_destroy (&dec->bits);
150
151   gst_buffer_replace (&dec->streamheader, NULL);
152   gst_buffer_replace (&dec->vorbiscomment, NULL);
153
154   if (dec->stereo) {
155     speex_stereo_state_destroy (dec->stereo);
156     dec->stereo = NULL;
157   }
158
159   if (dec->state) {
160     speex_decoder_destroy (dec->state);
161     dec->state = NULL;
162   }
163 }
164
165 static void
166 gst_speex_dec_init (GstSpeexDec * dec)
167 {
168   dec->sinkpad =
169       gst_pad_new_from_static_template (&speex_dec_sink_factory, "sink");
170   gst_pad_set_chain_function (dec->sinkpad,
171       GST_DEBUG_FUNCPTR (speex_dec_chain));
172   gst_pad_set_event_function (dec->sinkpad,
173       GST_DEBUG_FUNCPTR (speex_dec_sink_event));
174   gst_pad_set_query_type_function (dec->sinkpad,
175       GST_DEBUG_FUNCPTR (speex_get_sink_query_types));
176   gst_pad_set_query_function (dec->sinkpad,
177       GST_DEBUG_FUNCPTR (speex_dec_sink_query));
178   gst_element_add_pad (GST_ELEMENT (dec), dec->sinkpad);
179
180   dec->srcpad =
181       gst_pad_new_from_static_template (&speex_dec_src_factory, "src");
182   gst_pad_use_fixed_caps (dec->srcpad);
183   gst_pad_set_event_function (dec->srcpad,
184       GST_DEBUG_FUNCPTR (speex_dec_src_event));
185   gst_pad_set_query_type_function (dec->srcpad,
186       GST_DEBUG_FUNCPTR (speex_get_src_query_types));
187   gst_pad_set_query_function (dec->srcpad,
188       GST_DEBUG_FUNCPTR (speex_dec_src_query));
189   gst_element_add_pad (GST_ELEMENT (dec), dec->srcpad);
190
191   dec->enh = DEFAULT_ENH;
192
193   gst_speex_dec_reset (dec);
194 }
195
196 static gboolean
197 speex_dec_sink_setcaps (GstPad * pad, GstCaps * caps)
198 {
199   GstSpeexDec *dec = GST_SPEEX_DEC (gst_pad_get_parent (pad));
200   gboolean ret = TRUE;
201   GstStructure *s;
202   const GValue *streamheader;
203
204   s = gst_caps_get_structure (caps, 0);
205   if ((streamheader = gst_structure_get_value (s, "streamheader")) &&
206       G_VALUE_HOLDS (streamheader, GST_TYPE_ARRAY) &&
207       gst_value_array_get_size (streamheader) >= 2) {
208     const GValue *header, *vorbiscomment;
209     GstBuffer *buf;
210     GstFlowReturn res = GST_FLOW_OK;
211
212     header = gst_value_array_get_value (streamheader, 0);
213     if (header && G_VALUE_HOLDS (header, GST_TYPE_BUFFER)) {
214       buf = gst_value_get_buffer (header);
215       res = speex_dec_chain_parse_header (dec, buf);
216       if (res != GST_FLOW_OK)
217         goto done;
218       gst_buffer_replace (&dec->streamheader, buf);
219     }
220
221     vorbiscomment = gst_value_array_get_value (streamheader, 1);
222     if (vorbiscomment && G_VALUE_HOLDS (vorbiscomment, GST_TYPE_BUFFER)) {
223       buf = gst_value_get_buffer (vorbiscomment);
224       res = speex_dec_chain_parse_comments (dec, buf);
225       if (res != GST_FLOW_OK)
226         goto done;
227       gst_buffer_replace (&dec->vorbiscomment, buf);
228     }
229   }
230
231 done:
232   gst_object_unref (dec);
233   return ret;
234 }
235
236 static gboolean
237 speex_dec_convert (GstPad * pad,
238     GstFormat src_format, gint64 src_value,
239     GstFormat * dest_format, gint64 * dest_value)
240 {
241   gboolean res = TRUE;
242   GstSpeexDec *dec;
243   guint64 scale = 1;
244
245   dec = GST_SPEEX_DEC (gst_pad_get_parent (pad));
246
247   if (src_format == *dest_format) {
248     *dest_value = src_value;
249     res = TRUE;
250     goto cleanup;
251   }
252
253   if (dec->packetno < 1) {
254     res = FALSE;
255     goto cleanup;
256   }
257
258   if (pad == dec->sinkpad &&
259       (src_format == GST_FORMAT_BYTES || *dest_format == GST_FORMAT_BYTES)) {
260     res = FALSE;
261     goto cleanup;
262   }
263
264   switch (src_format) {
265     case GST_FORMAT_TIME:
266       switch (*dest_format) {
267         case GST_FORMAT_BYTES:
268           scale = 2 * dec->header->nb_channels;
269         case GST_FORMAT_DEFAULT:
270           *dest_value =
271               gst_util_uint64_scale_int (scale * src_value, dec->header->rate,
272               GST_SECOND);
273           break;
274         default:
275           res = FALSE;
276           break;
277       }
278       break;
279     case GST_FORMAT_DEFAULT:
280       switch (*dest_format) {
281         case GST_FORMAT_BYTES:
282           *dest_value = src_value * 2 * dec->header->nb_channels;
283           break;
284         case GST_FORMAT_TIME:
285           *dest_value =
286               gst_util_uint64_scale_int (src_value, GST_SECOND,
287               dec->header->rate);
288           break;
289         default:
290           res = FALSE;
291           break;
292       }
293       break;
294     case GST_FORMAT_BYTES:
295       switch (*dest_format) {
296         case GST_FORMAT_DEFAULT:
297           *dest_value = src_value / (2 * dec->header->nb_channels);
298           break;
299         case GST_FORMAT_TIME:
300           *dest_value = gst_util_uint64_scale_int (src_value, GST_SECOND,
301               dec->header->rate * 2 * dec->header->nb_channels);
302           break;
303         default:
304           res = FALSE;
305           break;
306       }
307       break;
308     default:
309       res = FALSE;
310       break;
311   }
312
313 cleanup:
314   gst_object_unref (dec);
315   return res;
316 }
317
318 static const GstQueryType *
319 speex_get_sink_query_types (GstPad * pad)
320 {
321   static const GstQueryType speex_dec_sink_query_types[] = {
322     GST_QUERY_CONVERT,
323     0
324   };
325
326   return speex_dec_sink_query_types;
327 }
328
329 static gboolean
330 speex_dec_sink_query (GstPad * pad, GstQuery * query)
331 {
332   GstSpeexDec *dec;
333   gboolean res;
334
335   dec = GST_SPEEX_DEC (gst_pad_get_parent (pad));
336
337   switch (GST_QUERY_TYPE (query)) {
338     case GST_QUERY_CONVERT:
339     {
340       GstFormat src_fmt, dest_fmt;
341       gint64 src_val, dest_val;
342
343       gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, &dest_val);
344       res = speex_dec_convert (pad, src_fmt, src_val, &dest_fmt, &dest_val);
345       if (res) {
346         gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val);
347       }
348       break;
349     }
350     default:
351       res = gst_pad_query_default (pad, query);
352       break;
353   }
354
355   gst_object_unref (dec);
356   return res;
357 }
358
359 static const GstQueryType *
360 speex_get_src_query_types (GstPad * pad)
361 {
362   static const GstQueryType speex_dec_src_query_types[] = {
363     GST_QUERY_POSITION,
364     GST_QUERY_DURATION,
365     0
366   };
367
368   return speex_dec_src_query_types;
369 }
370
371 static gboolean
372 speex_dec_src_query (GstPad * pad, GstQuery * query)
373 {
374   GstSpeexDec *dec;
375   gboolean res = FALSE;
376
377   dec = GST_SPEEX_DEC (gst_pad_get_parent (pad));
378
379   /* FIXME: why not just pass position/duration queries upstream to demuxer? */
380   switch (GST_QUERY_TYPE (query)) {
381     case GST_QUERY_POSITION:{
382       GstSegment segment;
383       GstFormat format;
384       gint64 cur;
385
386       gst_query_parse_position (query, &format, NULL);
387
388       GST_PAD_STREAM_LOCK (dec->sinkpad);
389       segment = dec->segment;
390       GST_PAD_STREAM_UNLOCK (dec->sinkpad);
391
392       if (segment.format != GST_FORMAT_TIME) {
393         GST_DEBUG_OBJECT (dec, "segment not initialised yet");
394         break;
395       }
396
397       if ((res = speex_dec_convert (dec->srcpad, GST_FORMAT_TIME,
398                   segment.position, &format, &cur))) {
399         gst_query_set_position (query, format, cur);
400       }
401       break;
402     }
403     case GST_QUERY_DURATION:{
404       GstFormat format;
405       gint64 dur;
406
407       /* get duration from demuxer */
408       if (!gst_pad_query_peer_duration (dec->sinkpad, GST_FORMAT_TIME, &dur))
409         break;
410
411       gst_query_parse_duration (query, &format, NULL);
412
413       /* and convert it into the requested format */
414       if ((res = speex_dec_convert (dec->srcpad, GST_FORMAT_TIME,
415                   dur, &format, &dur))) {
416         gst_query_set_duration (query, format, dur);
417       }
418       break;
419     }
420     default:
421       res = gst_pad_query_default (pad, query);
422       break;
423   }
424
425   gst_object_unref (dec);
426   return res;
427 }
428
429 static gboolean
430 speex_dec_src_event (GstPad * pad, GstEvent * event)
431 {
432   gboolean res = FALSE;
433   GstSpeexDec *dec = GST_SPEEX_DEC (gst_pad_get_parent (pad));
434
435   GST_LOG_OBJECT (dec, "handling %s event", GST_EVENT_TYPE_NAME (event));
436
437   switch (GST_EVENT_TYPE (event)) {
438     case GST_EVENT_SEEK:{
439       GstFormat format, tformat;
440       gdouble rate;
441       GstEvent *real_seek;
442       GstSeekFlags flags;
443       GstSeekType cur_type, stop_type;
444       gint64 cur, stop;
445       gint64 tcur, tstop;
446
447       gst_event_parse_seek (event, &rate, &format, &flags, &cur_type, &cur,
448           &stop_type, &stop);
449
450       /* we have to ask our peer to seek to time here as we know
451        * nothing about how to generate a granulepos from the src
452        * formats or anything.
453        *
454        * First bring the requested format to time
455        */
456       tformat = GST_FORMAT_TIME;
457       if (!(res = speex_dec_convert (pad, format, cur, &tformat, &tcur)))
458         break;
459       if (!(res = speex_dec_convert (pad, format, stop, &tformat, &tstop)))
460         break;
461
462       /* then seek with time on the peer */
463       real_seek = gst_event_new_seek (rate, GST_FORMAT_TIME,
464           flags, cur_type, tcur, stop_type, tstop);
465
466       GST_LOG_OBJECT (dec, "seek to %" GST_TIME_FORMAT, GST_TIME_ARGS (tcur));
467
468       res = gst_pad_push_event (dec->sinkpad, real_seek);
469       gst_event_unref (event);
470       break;
471     }
472     default:
473       res = gst_pad_event_default (pad, event);
474       break;
475   }
476
477   gst_object_unref (dec);
478   return res;
479 }
480
481 static gboolean
482 speex_dec_sink_event (GstPad * pad, GstEvent * event)
483 {
484   GstSpeexDec *dec;
485   gboolean ret = FALSE;
486
487   dec = GST_SPEEX_DEC (gst_pad_get_parent (pad));
488
489   GST_LOG_OBJECT (dec, "handling %s event", GST_EVENT_TYPE_NAME (event));
490
491   switch (GST_EVENT_TYPE (event)) {
492     case GST_EVENT_CAPS:
493     {
494       GstCaps *caps;
495
496       gst_event_parse_caps (event, &caps);
497       ret = speex_dec_sink_setcaps (pad, caps);
498       gst_event_unref (event);
499       break;
500     }
501     case GST_EVENT_SEGMENT:{
502       GstSegment segment;
503
504       gst_event_copy_segment (event, &segment);
505
506       if (segment.format != GST_FORMAT_TIME)
507         goto newseg_wrong_format;
508
509       if (segment.rate <= 0.0)
510         goto newseg_wrong_rate;
511
512 #if 0
513       if (update) {
514         /* time progressed without data, see if we can fill the gap with
515          * some concealment data */
516         if (dec->segment.position < start) {
517           GstClockTime duration;
518
519           duration = start - dec->segment.position;
520           speex_dec_chain_parse_data (dec, NULL, dec->segment.position,
521               duration);
522         }
523       }
524 #endif
525
526       /* now configure the values */
527       dec->segment = segment;
528
529       GST_DEBUG_OBJECT (dec, "segment now: %" GST_SEGMENT_FORMAT, &segment);
530       ret = gst_pad_push_event (dec->srcpad, event);
531       break;
532     }
533     default:
534       ret = gst_pad_event_default (pad, event);
535       break;
536   }
537
538   gst_object_unref (dec);
539   return ret;
540
541   /* ERRORS */
542 newseg_wrong_format:
543   {
544     GST_DEBUG_OBJECT (dec, "received non TIME newsegment");
545     gst_object_unref (dec);
546     return FALSE;
547   }
548 newseg_wrong_rate:
549   {
550     GST_DEBUG_OBJECT (dec, "negative rates not supported yet");
551     gst_object_unref (dec);
552     return FALSE;
553   }
554 }
555
556 static GstFlowReturn
557 speex_dec_chain_parse_header (GstSpeexDec * dec, GstBuffer * buf)
558 {
559   GstCaps *caps;
560   char *data;
561   gsize size;
562
563   /* get the header */
564   data = gst_buffer_map (buf, &size, NULL, GST_MAP_READ);
565   dec->header = speex_packet_to_header (data, size);
566   gst_buffer_unmap (buf, data, size);
567
568   if (!dec->header)
569     goto no_header;
570
571   if (dec->header->mode >= SPEEX_NB_MODES || dec->header->mode < 0)
572     goto mode_too_old;
573
574   dec->mode = speex_lib_get_mode (dec->header->mode);
575
576   /* initialize the decoder */
577   dec->state = speex_decoder_init (dec->mode);
578   if (!dec->state)
579     goto init_failed;
580
581   speex_decoder_ctl (dec->state, SPEEX_SET_ENH, &dec->enh);
582   speex_decoder_ctl (dec->state, SPEEX_GET_FRAME_SIZE, &dec->frame_size);
583
584   if (dec->header->nb_channels != 1) {
585     dec->stereo = speex_stereo_state_init ();
586     dec->callback.callback_id = SPEEX_INBAND_STEREO;
587     dec->callback.func = speex_std_stereo_request_handler;
588     dec->callback.data = dec->stereo;
589     speex_decoder_ctl (dec->state, SPEEX_SET_HANDLER, &dec->callback);
590   }
591
592   speex_decoder_ctl (dec->state, SPEEX_SET_SAMPLING_RATE, &dec->header->rate);
593
594   dec->frame_duration = gst_util_uint64_scale_int (dec->frame_size,
595       GST_SECOND, dec->header->rate);
596
597   speex_bits_init (&dec->bits);
598
599   /* set caps */
600   caps = gst_caps_new_simple ("audio/x-raw-int",
601       "rate", G_TYPE_INT, dec->header->rate,
602       "channels", G_TYPE_INT, dec->header->nb_channels,
603       "signed", G_TYPE_BOOLEAN, TRUE,
604       "endianness", G_TYPE_INT, G_BYTE_ORDER,
605       "width", G_TYPE_INT, 16, "depth", G_TYPE_INT, 16, NULL);
606
607   if (!gst_pad_set_caps (dec->srcpad, caps))
608     goto nego_failed;
609
610   gst_caps_unref (caps);
611   return GST_FLOW_OK;
612
613   /* ERRORS */
614 no_header:
615   {
616     GST_ELEMENT_ERROR (GST_ELEMENT (dec), STREAM, DECODE,
617         (NULL), ("couldn't read header"));
618     return GST_FLOW_ERROR;
619   }
620 mode_too_old:
621   {
622     GST_ELEMENT_ERROR (GST_ELEMENT (dec), STREAM, DECODE,
623         (NULL),
624         ("Mode number %d does not (yet/any longer) exist in this version",
625             dec->header->mode));
626     return GST_FLOW_ERROR;
627   }
628 init_failed:
629   {
630     GST_ELEMENT_ERROR (GST_ELEMENT (dec), STREAM, DECODE,
631         (NULL), ("couldn't initialize decoder"));
632     return GST_FLOW_ERROR;
633   }
634 nego_failed:
635   {
636     GST_ELEMENT_ERROR (GST_ELEMENT (dec), STREAM, DECODE,
637         (NULL), ("couldn't negotiate format"));
638     gst_caps_unref (caps);
639     return GST_FLOW_NOT_NEGOTIATED;
640   }
641 }
642
643 static GstFlowReturn
644 speex_dec_chain_parse_comments (GstSpeexDec * dec, GstBuffer * buf)
645 {
646   GstTagList *list;
647   gchar *ver, *encoder = NULL;
648
649   list = gst_tag_list_from_vorbiscomment_buffer (buf, NULL, 0, &encoder);
650
651   if (!list) {
652     GST_WARNING_OBJECT (dec, "couldn't decode comments");
653     list = gst_tag_list_new ();
654   }
655
656   if (encoder) {
657     gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
658         GST_TAG_ENCODER, encoder, NULL);
659   }
660
661   gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
662       GST_TAG_AUDIO_CODEC, "Speex", NULL);
663
664   ver = g_strndup (dec->header->speex_version, SPEEX_HEADER_VERSION_LENGTH);
665   g_strstrip (ver);
666
667   if (ver != NULL && *ver != '\0') {
668     gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
669         GST_TAG_ENCODER_VERSION, ver, NULL);
670   }
671
672   if (dec->header->bitrate > 0) {
673     gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
674         GST_TAG_BITRATE, (guint) dec->header->bitrate, NULL);
675   }
676
677   GST_INFO_OBJECT (dec, "tags: %" GST_PTR_FORMAT, list);
678
679   gst_element_found_tags_for_pad (GST_ELEMENT (dec), dec->srcpad, list);
680
681   g_free (encoder);
682   g_free (ver);
683
684   return GST_FLOW_OK;
685 }
686
687 static GstFlowReturn
688 speex_dec_chain_parse_data (GstSpeexDec * dec, GstBuffer * buf,
689     GstClockTime timestamp, GstClockTime duration)
690 {
691   GstFlowReturn res = GST_FLOW_OK;
692   gint i, fpp;
693   SpeexBits *bits;
694   gsize size;
695   char *data;
696
697   if (!dec->frame_duration)
698     goto not_negotiated;
699
700   if (timestamp != -1) {
701     dec->segment.position = timestamp;
702   } else {
703     timestamp = dec->segment.position;
704   }
705
706   if (buf) {
707     /* send data to the bitstream */
708     data = gst_buffer_map (buf, &size, NULL, GST_MAP_READ);
709     speex_bits_read_from (&dec->bits, data, size);
710     gst_buffer_unmap (buf, data, size);
711
712     fpp = dec->header->frames_per_packet;
713     bits = &dec->bits;
714
715     GST_DEBUG_OBJECT (dec, "received buffer of size %u, fpp %d, %d bits", size,
716         fpp, speex_bits_remaining (bits));
717   } else {
718     /* concealment data, pass NULL as the bits parameters */
719     GST_DEBUG_OBJECT (dec, "creating concealment data");
720     fpp = dec->header->frames_per_packet;
721     bits = NULL;
722   }
723
724
725   /* now decode each frame, catering for unknown number of them (e.g. rtp) */
726   for (i = 0; i < fpp; i++) {
727     GstBuffer *outbuf;
728     gint16 *out_data;
729     gint ret;
730
731     GST_LOG_OBJECT (dec, "decoding frame %d/%d, %d bits remaining", i, fpp,
732         bits ? speex_bits_remaining (bits) : -1);
733 #if 0
734     res = gst_pad_alloc_buffer_and_set_caps (dec->srcpad,
735         GST_BUFFER_OFFSET_NONE, dec->frame_size * dec->header->nb_channels * 2,
736         GST_PAD_CAPS (dec->srcpad), &outbuf);
737
738     if (res != GST_FLOW_OK) {
739       GST_DEBUG_OBJECT (dec, "buf alloc flow: %s", gst_flow_get_name (res));
740       return res;
741     }
742 #endif
743     /* FIXME, we can use a bufferpool because we have fixed size buffers. We
744      * could also use an allocator */
745     outbuf =
746         gst_buffer_new_allocate (NULL,
747         dec->frame_size * dec->header->nb_channels * 2, 0);
748
749     out_data = gst_buffer_map (outbuf, &size, NULL, GST_MAP_WRITE);
750     ret = speex_decode_int (dec->state, bits, out_data);
751     gst_buffer_unmap (outbuf, out_data, size);
752
753     if (ret == -1) {
754       /* uh? end of stream */
755       if (fpp == 0 && speex_bits_remaining (bits) < 8) {
756         /* if we did not know how many frames to expect, then we get this
757            at the end if there are leftover bits to pad to the next byte */
758       } else {
759         GST_WARNING_OBJECT (dec, "Unexpected end of stream found");
760       }
761       gst_buffer_unref (outbuf);
762       outbuf = NULL;
763       break;
764     } else if (ret == -2) {
765       GST_WARNING_OBJECT (dec, "Decoding error: corrupted stream?");
766       gst_buffer_unref (outbuf);
767       outbuf = NULL;
768       break;
769     }
770
771     if (bits && speex_bits_remaining (bits) < 0) {
772       GST_WARNING_OBJECT (dec, "Decoding overflow: corrupted stream?");
773       gst_buffer_unref (outbuf);
774       outbuf = NULL;
775       break;
776     }
777     if (dec->header->nb_channels == 2)
778       speex_decode_stereo_int (out_data, dec->frame_size, dec->stereo);
779
780     GST_BUFFER_TIMESTAMP (outbuf) = timestamp;
781     GST_BUFFER_DURATION (outbuf) = dec->frame_duration;
782
783     dec->segment.position += dec->frame_duration;
784     timestamp = dec->segment.position;
785
786     GST_LOG_OBJECT (dec, "pushing buffer with ts=%" GST_TIME_FORMAT ", dur=%"
787         GST_TIME_FORMAT, GST_TIME_ARGS (timestamp),
788         GST_TIME_ARGS (dec->frame_duration));
789
790     res = gst_pad_push (dec->srcpad, outbuf);
791
792     if (res != GST_FLOW_OK) {
793       GST_DEBUG_OBJECT (dec, "flow: %s", gst_flow_get_name (res));
794       break;
795     }
796   }
797
798   return res;
799
800   /* ERRORS */
801 not_negotiated:
802   {
803     GST_ELEMENT_ERROR (dec, CORE, NEGOTIATION, (NULL),
804         ("decoder not initialized"));
805     return GST_FLOW_NOT_NEGOTIATED;
806   }
807 }
808
809 static gboolean
810 memcmp_buffers (GstBuffer * buf1, GstBuffer * buf2)
811 {
812   gsize size1, size2;
813   gpointer data1;
814   gboolean res;
815
816   size1 = gst_buffer_get_size (buf1);
817   size2 = gst_buffer_get_size (buf2);
818
819   if (size1 != size2)
820     return FALSE;
821
822   data1 = gst_buffer_map (buf1, NULL, NULL, GST_MAP_READ);
823   res = gst_buffer_memcmp (buf2, 0, data1, size1) == 0;
824   gst_buffer_unmap (buf1, data1, size1);
825
826   return res;
827 }
828
829 static GstFlowReturn
830 speex_dec_chain (GstPad * pad, GstBuffer * buf)
831 {
832   GstFlowReturn res;
833   GstSpeexDec *dec;
834
835   dec = GST_SPEEX_DEC (gst_pad_get_parent (pad));
836
837   /* If we have the streamheader and vorbiscomment from the caps already
838    * ignore them here */
839   if (dec->streamheader && dec->vorbiscomment) {
840     if (memcmp_buffers (dec->streamheader, buf)) {
841       res = GST_FLOW_OK;
842     } else if (memcmp_buffers (dec->vorbiscomment, buf)) {
843       res = GST_FLOW_OK;
844     } else {
845       res =
846           speex_dec_chain_parse_data (dec, buf, GST_BUFFER_TIMESTAMP (buf),
847           GST_BUFFER_DURATION (buf));
848     }
849   } else {
850     /* Otherwise fall back to packet counting and assume that the
851      * first two packets are the headers. */
852     switch (dec->packetno) {
853       case 0:
854         res = speex_dec_chain_parse_header (dec, buf);
855         break;
856       case 1:
857         res = speex_dec_chain_parse_comments (dec, buf);
858         break;
859       default:
860         res =
861             speex_dec_chain_parse_data (dec, buf, GST_BUFFER_TIMESTAMP (buf),
862             GST_BUFFER_DURATION (buf));
863         break;
864     }
865   }
866
867   dec->packetno++;
868
869   gst_buffer_unref (buf);
870   gst_object_unref (dec);
871
872   return res;
873 }
874
875 static void
876 gst_speex_dec_get_property (GObject * object, guint prop_id,
877     GValue * value, GParamSpec * pspec)
878 {
879   GstSpeexDec *speexdec;
880
881   speexdec = GST_SPEEX_DEC (object);
882
883   switch (prop_id) {
884     case ARG_ENH:
885       g_value_set_boolean (value, speexdec->enh);
886       break;
887     default:
888       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
889       break;
890   }
891 }
892
893 static void
894 gst_speex_dec_set_property (GObject * object, guint prop_id,
895     const GValue * value, GParamSpec * pspec)
896 {
897   GstSpeexDec *speexdec;
898
899   speexdec = GST_SPEEX_DEC (object);
900
901   switch (prop_id) {
902     case ARG_ENH:
903       speexdec->enh = g_value_get_boolean (value);
904       break;
905     default:
906       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
907       break;
908   }
909 }
910
911
912 static GstStateChangeReturn
913 speex_dec_change_state (GstElement * element, GstStateChange transition)
914 {
915   GstStateChangeReturn ret;
916   GstSpeexDec *dec = GST_SPEEX_DEC (element);
917
918   switch (transition) {
919     case GST_STATE_CHANGE_NULL_TO_READY:
920     case GST_STATE_CHANGE_READY_TO_PAUSED:
921     case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
922     default:
923       break;
924   }
925
926   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
927   if (ret != GST_STATE_CHANGE_SUCCESS)
928     return ret;
929
930   switch (transition) {
931     case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
932       break;
933     case GST_STATE_CHANGE_PAUSED_TO_READY:
934       gst_speex_dec_reset (dec);
935       break;
936     case GST_STATE_CHANGE_READY_TO_NULL:
937       break;
938     default:
939       break;
940   }
941
942   return ret;
943 }