ext/speex/gstspeexenc.*: Don't leak adapter.
[platform/upstream/gstreamer.git] / ext / speex / gstspeexenc.c
1 /* GStreamer
2  * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24 #include <stdlib.h>
25 #include <string.h>
26 #include <time.h>
27 #include <math.h>
28 #include <speex/speex.h>
29 #include <speex/speex_stereo.h>
30
31 #include <gst/gsttagsetter.h>
32 #include <gst/tag/tag.h>
33 #include "gstspeexenc.h"
34
35 GST_DEBUG_CATEGORY (speexenc_debug);
36 #define GST_CAT_DEFAULT speexenc_debug
37
38 static GstPadTemplate *gst_speexenc_src_template, *gst_speexenc_sink_template;
39
40 /* elementfactory information */
41 GstElementDetails speexenc_details = {
42   "Speex encoder",
43   "Codec/Encoder/Audio",
44   "Encodes audio in Speex format",
45   "Wim Taymans <wim@fluendo.com>",
46 };
47
48 /* GstSpeexEnc signals and args */
49 enum
50 {
51   /* FILL ME */
52   LAST_SIGNAL
53 };
54
55 #define DEFAULT_QUALITY         8.0
56 #define DEFAULT_BITRATE         0
57 #define DEFAULT_VBR             FALSE
58 #define DEFAULT_ABR             0
59 #define DEFAULT_VAD             FALSE
60 #define DEFAULT_DTX             FALSE
61 #define DEFAULT_COMPLEXITY      3
62 #define DEFAULT_NFRAMES         1
63
64 enum
65 {
66   ARG_0,
67   ARG_QUALITY,
68   ARG_BITRATE,
69   ARG_VBR,
70   ARG_ABR,
71   ARG_VAD,
72   ARG_DTX,
73   ARG_COMPLEXITY,
74   ARG_NFRAMES,
75   ARG_LAST_MESSAGE
76 };
77
78 #if 0
79 static const GstFormat *
80 gst_speexenc_get_formats (GstPad * pad)
81 {
82   static const GstFormat src_formats[] = {
83     GST_FORMAT_BYTES,
84     GST_FORMAT_TIME,
85     0
86   };
87   static const GstFormat sink_formats[] = {
88     GST_FORMAT_BYTES,
89     GST_FORMAT_DEFAULT,
90     GST_FORMAT_TIME,
91     0
92   };
93
94   return (GST_PAD_IS_SRC (pad) ? src_formats : sink_formats);
95 }
96 #endif
97
98 static void gst_speexenc_base_init (gpointer g_class);
99 static void gst_speexenc_class_init (GstSpeexEncClass * klass);
100 static void gst_speexenc_init (GstSpeexEnc * speexenc);
101 static void gst_speexenc_finalize (GObject * object);
102
103 static gboolean gst_speexenc_sinkevent (GstPad * pad, GstEvent * event);
104 static GstFlowReturn gst_speexenc_chain (GstPad * pad, GstBuffer * buf);
105 static gboolean gst_speexenc_setup (GstSpeexEnc * speexenc);
106
107 static void gst_speexenc_get_property (GObject * object, guint prop_id,
108     GValue * value, GParamSpec * pspec);
109 static void gst_speexenc_set_property (GObject * object, guint prop_id,
110     const GValue * value, GParamSpec * pspec);
111 static GstStateChangeReturn gst_speexenc_change_state (GstElement * element,
112     GstStateChange transition);
113
114 static GstElementClass *parent_class = NULL;
115
116 /*static guint gst_speexenc_signals[LAST_SIGNAL] = { 0 }; */
117
118 GType
119 gst_speexenc_get_type (void)
120 {
121   static GType speexenc_type = 0;
122
123   if (!speexenc_type) {
124     static const GTypeInfo speexenc_info = {
125       sizeof (GstSpeexEncClass),
126       gst_speexenc_base_init,
127       NULL,
128       (GClassInitFunc) gst_speexenc_class_init,
129       NULL,
130       NULL,
131       sizeof (GstSpeexEnc),
132       0,
133       (GInstanceInitFunc) gst_speexenc_init,
134     };
135     static const GInterfaceInfo tag_setter_info = {
136       NULL,
137       NULL,
138       NULL
139     };
140
141     speexenc_type =
142         g_type_register_static (GST_TYPE_ELEMENT, "GstSpeexEnc", &speexenc_info,
143         0);
144
145     g_type_add_interface_static (speexenc_type, GST_TYPE_TAG_SETTER,
146         &tag_setter_info);
147
148     GST_DEBUG_CATEGORY_INIT (speexenc_debug, "speexenc", 0, "Speex encoder");
149   }
150   return speexenc_type;
151 }
152
153 static GstCaps *
154 speex_caps_factory (void)
155 {
156   return gst_caps_new_simple ("audio/x-speex", NULL);
157 }
158
159 static GstCaps *
160 raw_caps_factory (void)
161 {
162   return
163       gst_caps_new_simple ("audio/x-raw-int",
164       "rate", GST_TYPE_INT_RANGE, 6000, 48000,
165       "channels", GST_TYPE_INT_RANGE, 1, 2,
166       "endianness", G_TYPE_INT, G_BYTE_ORDER,
167       "signed", G_TYPE_BOOLEAN, TRUE,
168       "width", G_TYPE_INT, 16, "depth", G_TYPE_INT, 16, NULL);
169 }
170
171 static void
172 gst_speexenc_base_init (gpointer g_class)
173 {
174   GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
175   GstCaps *raw_caps, *speex_caps;
176
177   raw_caps = raw_caps_factory ();
178   speex_caps = speex_caps_factory ();
179
180   gst_speexenc_sink_template = gst_pad_template_new ("sink", GST_PAD_SINK,
181       GST_PAD_ALWAYS, raw_caps);
182   gst_speexenc_src_template = gst_pad_template_new ("src", GST_PAD_SRC,
183       GST_PAD_ALWAYS, speex_caps);
184   gst_element_class_add_pad_template (element_class,
185       gst_speexenc_sink_template);
186   gst_element_class_add_pad_template (element_class, gst_speexenc_src_template);
187   gst_element_class_set_details (element_class, &speexenc_details);
188 }
189
190 static void
191 gst_speexenc_class_init (GstSpeexEncClass * klass)
192 {
193   GObjectClass *gobject_class;
194   GstElementClass *gstelement_class;
195
196   gobject_class = (GObjectClass *) klass;
197   gstelement_class = (GstElementClass *) klass;
198
199   gobject_class->set_property = gst_speexenc_set_property;
200   gobject_class->get_property = gst_speexenc_get_property;
201
202   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_QUALITY,
203       g_param_spec_float ("quality", "Quality", "Encoding quality",
204           0.0, 10.0, DEFAULT_QUALITY, G_PARAM_READWRITE));
205   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_BITRATE,
206       g_param_spec_int ("bitrate", "Encoding Bit-rate",
207           "Specify an encoding bit-rate (in bps). (0 = automatic)",
208           0, G_MAXINT, DEFAULT_BITRATE, G_PARAM_READWRITE));
209   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_VBR,
210       g_param_spec_boolean ("vbr", "VBR",
211           "Enable variable bit-rate", DEFAULT_VBR, G_PARAM_READWRITE));
212   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_ABR,
213       g_param_spec_int ("abr", "ABR",
214           "Enable average bit-rate (0 = disabled)",
215           0, G_MAXINT, DEFAULT_ABR, G_PARAM_READWRITE));
216   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_VAD,
217       g_param_spec_boolean ("vad", "VAD",
218           "Enable voice activity detection", DEFAULT_VAD, G_PARAM_READWRITE));
219   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_DTX,
220       g_param_spec_boolean ("dtx", "DTX",
221           "Enable discontinuous transmission", DEFAULT_DTX, G_PARAM_READWRITE));
222   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_COMPLEXITY,
223       g_param_spec_int ("complexity", "Complexity",
224           "Set encoding complexity",
225           0, G_MAXINT, DEFAULT_COMPLEXITY, G_PARAM_READWRITE));
226   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_NFRAMES,
227       g_param_spec_int ("nframes", "NFrames",
228           "Number of frames per buffer",
229           0, G_MAXINT, DEFAULT_NFRAMES, G_PARAM_READWRITE));
230   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_LAST_MESSAGE,
231       g_param_spec_string ("last-message", "last-message",
232           "The last status message", NULL, G_PARAM_READABLE));
233
234   parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
235
236   gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_speexenc_finalize);
237
238   gstelement_class->change_state =
239       GST_DEBUG_FUNCPTR (gst_speexenc_change_state);
240 }
241
242 static void
243 gst_speexenc_finalize (GObject * object)
244 {
245   GstSpeexEnc *speexenc;
246
247   speexenc = GST_SPEEXENC (object);
248
249   g_object_unref (speexenc->adapter);
250
251   G_OBJECT_CLASS (parent_class)->finalize (object);
252 }
253
254 static gboolean
255 gst_speexenc_sink_setcaps (GstPad * pad, GstCaps * caps)
256 {
257   GstSpeexEnc *speexenc;
258   GstStructure *structure;
259
260   speexenc = GST_SPEEXENC (gst_pad_get_parent (pad));
261   speexenc->setup = FALSE;
262
263   structure = gst_caps_get_structure (caps, 0);
264   gst_structure_get_int (structure, "channels", &speexenc->channels);
265   gst_structure_get_int (structure, "rate", &speexenc->rate);
266
267   gst_speexenc_setup (speexenc);
268
269   gst_object_unref (speexenc);
270
271   return speexenc->setup;
272 }
273
274 static gboolean
275 gst_speexenc_convert_src (GstPad * pad, GstFormat src_format, gint64 src_value,
276     GstFormat * dest_format, gint64 * dest_value)
277 {
278   gboolean res = TRUE;
279   GstSpeexEnc *speexenc;
280   gint64 avg;
281
282   speexenc = GST_SPEEXENC (GST_PAD_PARENT (pad));
283
284   if (speexenc->samples_in == 0 ||
285       speexenc->bytes_out == 0 || speexenc->rate == 0)
286     return FALSE;
287
288   avg = (speexenc->bytes_out * speexenc->rate) / (speexenc->samples_in);
289
290   switch (src_format) {
291     case GST_FORMAT_BYTES:
292       switch (*dest_format) {
293         case GST_FORMAT_TIME:
294           *dest_value = src_value * GST_SECOND / avg;
295           break;
296         default:
297           res = FALSE;
298       }
299       break;
300     case GST_FORMAT_TIME:
301       switch (*dest_format) {
302         case GST_FORMAT_BYTES:
303           *dest_value = src_value * avg / GST_SECOND;
304           break;
305         default:
306           res = FALSE;
307       }
308       break;
309     default:
310       res = FALSE;
311   }
312   return res;
313 }
314
315 static gboolean
316 gst_speexenc_convert_sink (GstPad * pad, GstFormat src_format,
317     gint64 src_value, GstFormat * dest_format, gint64 * dest_value)
318 {
319   gboolean res = TRUE;
320   guint scale = 1;
321   gint bytes_per_sample;
322   GstSpeexEnc *speexenc;
323
324   speexenc = GST_SPEEXENC (GST_PAD_PARENT (pad));
325
326   bytes_per_sample = speexenc->channels * 2;
327
328   switch (src_format) {
329     case GST_FORMAT_BYTES:
330       switch (*dest_format) {
331         case GST_FORMAT_DEFAULT:
332           if (bytes_per_sample == 0)
333             return FALSE;
334           *dest_value = src_value / bytes_per_sample;
335           break;
336         case GST_FORMAT_TIME:
337         {
338           gint byterate = bytes_per_sample * speexenc->rate;
339
340           if (byterate == 0)
341             return FALSE;
342           *dest_value = src_value * GST_SECOND / byterate;
343           break;
344         }
345         default:
346           res = FALSE;
347       }
348       break;
349     case GST_FORMAT_DEFAULT:
350       switch (*dest_format) {
351         case GST_FORMAT_BYTES:
352           *dest_value = src_value * bytes_per_sample;
353           break;
354         case GST_FORMAT_TIME:
355           if (speexenc->rate == 0)
356             return FALSE;
357           *dest_value = src_value * GST_SECOND / speexenc->rate;
358           break;
359         default:
360           res = FALSE;
361       }
362       break;
363     case GST_FORMAT_TIME:
364       switch (*dest_format) {
365         case GST_FORMAT_BYTES:
366           scale = bytes_per_sample;
367           /* fallthrough */
368         case GST_FORMAT_DEFAULT:
369           *dest_value = src_value * scale * speexenc->rate / GST_SECOND;
370           break;
371         default:
372           res = FALSE;
373       }
374       break;
375     default:
376       res = FALSE;
377   }
378   return res;
379 }
380
381 static const GstQueryType *
382 gst_speexenc_get_query_types (GstPad * pad)
383 {
384   static const GstQueryType gst_speexenc_src_query_types[] = {
385     GST_QUERY_POSITION,
386     GST_QUERY_DURATION,
387     GST_QUERY_CONVERT,
388     0
389   };
390
391   return gst_speexenc_src_query_types;
392 }
393
394 static gboolean
395 gst_speexenc_src_query (GstPad * pad, GstQuery * query)
396 {
397   gboolean res = TRUE;
398   GstSpeexEnc *speexenc;
399   GstPad *peerpad;
400
401   speexenc = GST_SPEEXENC (gst_pad_get_parent (pad));
402   peerpad = gst_pad_get_peer (GST_PAD (speexenc->sinkpad));
403
404   switch (GST_QUERY_TYPE (query)) {
405     case GST_QUERY_POSITION:
406     {
407       GstFormat fmt, req_fmt;
408       gint64 pos, val;
409
410       gst_query_parse_position (query, &req_fmt, NULL);
411       if ((res = gst_pad_query_position (peerpad, &req_fmt, &val))) {
412         gst_query_set_position (query, req_fmt, val);
413         break;
414       }
415
416       fmt = GST_FORMAT_TIME;
417       if (!(res = gst_pad_query_position (peerpad, &fmt, &pos)))
418         break;
419
420       if ((res = gst_pad_query_convert (peerpad, fmt, pos, &req_fmt, &val)))
421         gst_query_set_position (query, req_fmt, val);
422
423       break;
424     }
425     case GST_QUERY_DURATION:
426     {
427       GstFormat fmt, req_fmt;
428       gint64 dur, val;
429
430       gst_query_parse_duration (query, &req_fmt, NULL);
431       if ((res = gst_pad_query_duration (peerpad, &req_fmt, &val))) {
432         gst_query_set_duration (query, req_fmt, val);
433         break;
434       }
435
436       fmt = GST_FORMAT_TIME;
437       if (!(res = gst_pad_query_duration (peerpad, &fmt, &dur)))
438         break;
439
440       if ((res = gst_pad_query_convert (peerpad, fmt, dur, &req_fmt, &val))) {
441         gst_query_set_duration (query, req_fmt, val);
442       }
443       break;
444     }
445     case GST_QUERY_CONVERT:
446     {
447       GstFormat src_fmt, dest_fmt;
448       gint64 src_val, dest_val;
449
450       gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, &dest_val);
451       if (!(res = gst_speexenc_convert_src (pad, src_fmt, src_val, &dest_fmt,
452                   &dest_val)))
453         goto error;
454       gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val);
455       break;
456     }
457     default:
458       res = gst_pad_query_default (pad, query);
459       break;
460   }
461
462 error:
463   gst_object_unref (peerpad);
464   gst_object_unref (speexenc);
465   return res;
466 }
467
468 static gboolean
469 gst_speexenc_sink_query (GstPad * pad, GstQuery * query)
470 {
471   gboolean res = TRUE;
472   GstSpeexEnc *speexenc;
473
474   speexenc = GST_SPEEXENC (GST_PAD_PARENT (pad));
475
476   switch (GST_QUERY_TYPE (query)) {
477     case GST_QUERY_CONVERT:
478     {
479       GstFormat src_fmt, dest_fmt;
480       gint64 src_val, dest_val;
481
482       gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, &dest_val);
483       if (!(res =
484               gst_speexenc_convert_sink (pad, src_fmt, src_val, &dest_fmt,
485                   &dest_val)))
486         goto error;
487       gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val);
488       break;
489     }
490     default:
491       res = gst_pad_query_default (pad, query);
492       break;
493   }
494
495 error:
496   return res;
497 }
498
499 static void
500 gst_speexenc_init (GstSpeexEnc * speexenc)
501 {
502   speexenc->sinkpad =
503       gst_pad_new_from_template (gst_speexenc_sink_template, "sink");
504   gst_element_add_pad (GST_ELEMENT (speexenc), speexenc->sinkpad);
505   gst_pad_set_event_function (speexenc->sinkpad, gst_speexenc_sinkevent);
506   gst_pad_set_chain_function (speexenc->sinkpad, gst_speexenc_chain);
507   gst_pad_set_setcaps_function (speexenc->sinkpad, gst_speexenc_sink_setcaps);
508   gst_pad_set_query_function (speexenc->sinkpad,
509       GST_DEBUG_FUNCPTR (gst_speexenc_sink_query));
510
511   speexenc->srcpad =
512       gst_pad_new_from_template (gst_speexenc_src_template, "src");
513   gst_pad_set_query_function (speexenc->srcpad,
514       GST_DEBUG_FUNCPTR (gst_speexenc_src_query));
515   gst_pad_set_query_type_function (speexenc->srcpad,
516       GST_DEBUG_FUNCPTR (gst_speexenc_get_query_types));
517   gst_element_add_pad (GST_ELEMENT (speexenc), speexenc->srcpad);
518
519   speexenc->channels = -1;
520   speexenc->rate = -1;
521
522   speexenc->quality = DEFAULT_QUALITY;
523   speexenc->bitrate = DEFAULT_BITRATE;
524   speexenc->vbr = DEFAULT_VBR;
525   speexenc->abr = DEFAULT_ABR;
526   speexenc->vad = DEFAULT_VAD;
527   speexenc->dtx = DEFAULT_DTX;
528   speexenc->complexity = DEFAULT_COMPLEXITY;
529   speexenc->nframes = DEFAULT_NFRAMES;
530
531   speexenc->setup = FALSE;
532   speexenc->header_sent = FALSE;
533
534   speexenc->adapter = gst_adapter_new ();
535 }
536
537
538 /* FIXME: why are we not using the from/to vorbiscomment 
539  * functions that are in -lgsttagedit-0.9 here? */
540
541 static gchar *
542 gst_speexenc_get_tag_value (const GstTagList * list, const gchar * tag,
543     int index)
544 {
545   GType tag_type;
546   gchar *speexvalue = NULL;
547
548   if (tag == NULL)
549     return NULL;
550
551   tag_type = gst_tag_get_type (tag);
552
553   /* get tag name right */
554   if ((strcmp (tag, GST_TAG_TRACK_NUMBER) == 0)
555       || (strcmp (tag, GST_TAG_ALBUM_VOLUME_NUMBER) == 0)
556       || (strcmp (tag, GST_TAG_TRACK_COUNT) == 0)
557       || (strcmp (tag, GST_TAG_ALBUM_VOLUME_COUNT) == 0)) {
558     guint track_no;
559
560     if (gst_tag_list_get_uint_index (list, tag, index, &track_no)) {
561       speexvalue = g_strdup_printf ("%u", track_no);
562     } else {
563       GST_WARNING ("Failed to extract int tag %d for '%s'", index, tag);
564     }
565   } else if (tag_type == GST_TYPE_DATE) {
566     /* FIXME: how are dates represented in speex files? */
567     GDate *date;
568
569     if (gst_tag_list_get_date_index (list, tag, index, &date)) {
570       speexvalue =
571           g_strdup_printf ("%04d-%02d-%02d", (gint) g_date_get_year (date),
572           (gint) g_date_get_month (date), (gint) g_date_get_day (date));
573       g_date_free (date);
574     } else {
575       GST_WARNING ("Failed to extract date tag %d for '%s'", index, tag);
576     }
577   } else if (tag_type == G_TYPE_STRING) {
578     if (!gst_tag_list_get_string_index (list, tag, index, &speexvalue))
579       GST_WARNING ("Failed to extract string tag %d for '%s'", index, tag);
580   }
581
582   return speexvalue;
583 }
584
585 /*
586  *  Comments will be stored in the Vorbis style.
587  *  It is describled in the "Structure" section of
588  *  http://www.xiph.org/ogg/vorbis/doc/v-comment.html
589  *
590  *  The comment header is decoded as follows:
591  *  1) [vendor_length] = read an unsigned integer of 32 bits
592  *  2) [vendor_string] = read a UTF-8 vector as [vendor_length] octets
593  *  3) [user_comment_list_length] = read an unsigned integer of 32 bits
594  *  4) iterate [user_comment_list_length] times {
595  *     5) [length] = read an unsigned integer of 32 bits
596  *     6) this iteration's user comment = read a UTF-8 vector as [length] octets
597  *     }
598  *  7) [framing_bit] = read a single bit as boolean
599  *  8) if ( [framing_bit]  unset or end of packet ) then ERROR
600  *  9) done.
601  *
602  *  If you have troubles, please write to ymnk@jcraft.com.
603  */
604 static void
605 comment_init (guint8 ** comments, int *length, char *vendor_string)
606 {
607   int vendor_length = strlen (vendor_string);
608   int user_comment_list_length = 0;
609   int len = 4 + vendor_length + 4;
610   guint8 *p = g_malloc (len);
611
612   GST_WRITE_UINT32_LE (p, vendor_length);
613   memcpy (p + 4, vendor_string, vendor_length);
614   GST_WRITE_UINT32_LE (p + 4 + vendor_length, user_comment_list_length);
615   *length = len;
616   *comments = p;
617 }
618 static void
619 comment_add (guint8 ** comments, int *length, const char *tag, char *val)
620 {
621   guint8 *p = *comments;
622   int vendor_length = GST_READ_UINT32_LE (p);
623   int user_comment_list_length = GST_READ_UINT32_LE (p + 4 + vendor_length);
624   int tag_len = (tag ? strlen (tag) : 0);
625   int val_len = strlen (val);
626   int len = (*length) + 4 + tag_len + val_len;
627
628   p = g_realloc (p, len);
629
630   GST_WRITE_UINT32_LE (p + *length, tag_len + val_len); /* length of comment */
631   if (tag)
632     memcpy (p + *length + 4, (guint8 *) tag, tag_len);  /* comment */
633   memcpy (p + *length + 4 + tag_len, val, val_len);     /* comment */
634   GST_WRITE_UINT32_LE (p + 4 + vendor_length, user_comment_list_length + 1);
635
636   *comments = p;
637   *length = len;
638 }
639
640 static void
641 gst_speexenc_metadata_set1 (const GstTagList * list, const gchar * tag,
642     gpointer speexenc)
643 {
644   const gchar *speextag = NULL;
645   gchar *speexvalue = NULL;
646   guint i, count;
647   GstSpeexEnc *enc = GST_SPEEXENC (speexenc);
648
649   speextag = gst_tag_to_vorbis_tag (tag);
650   if (speextag == NULL) {
651     return;
652   }
653
654   count = gst_tag_list_get_tag_size (list, tag);
655   for (i = 0; i < count; i++) {
656     speexvalue = gst_speexenc_get_tag_value (list, tag, i);
657
658     if (speexvalue != NULL) {
659       comment_add (&enc->comments, &enc->comment_len, speextag, speexvalue);
660     }
661   }
662 }
663
664 static void
665 gst_speexenc_set_metadata (GstSpeexEnc * speexenc)
666 {
667   GstTagList *copy;
668   const GstTagList *user_tags;
669
670   user_tags = gst_tag_setter_get_tag_list (GST_TAG_SETTER (speexenc));
671   if (!(speexenc->tags || user_tags))
672     return;
673
674   comment_init (&speexenc->comments, &speexenc->comment_len,
675       "Encoded with GStreamer Speexenc");
676   copy =
677       gst_tag_list_merge (user_tags, speexenc->tags,
678       gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (speexenc)));
679   gst_tag_list_foreach (copy, gst_speexenc_metadata_set1, speexenc);
680   gst_tag_list_free (copy);
681 }
682
683 static gboolean
684 gst_speexenc_setup (GstSpeexEnc * speexenc)
685 {
686   speexenc->setup = FALSE;
687
688   switch (speexenc->mode) {
689     case GST_SPEEXENC_MODE_UWB:
690       speexenc->speex_mode = (SpeexMode *) & speex_uwb_mode;
691       break;
692     case GST_SPEEXENC_MODE_WB:
693       speexenc->speex_mode = (SpeexMode *) & speex_wb_mode;
694       break;
695     case GST_SPEEXENC_MODE_NB:
696       speexenc->speex_mode = (SpeexMode *) & speex_nb_mode;
697       break;
698     case GST_SPEEXENC_MODE_AUTO:
699       /* fall through */
700     default:
701       break;
702   }
703
704   if (speexenc->rate > 25000) {
705     if (speexenc->mode == GST_SPEEXENC_MODE_AUTO) {
706       speexenc->speex_mode = (SpeexMode *) & speex_uwb_mode;
707     } else {
708       if (speexenc->speex_mode != &speex_uwb_mode) {
709         speexenc->last_message =
710             g_strdup_printf
711             ("Warning: suggest to use ultra wide band mode for this rate");
712         g_object_notify (G_OBJECT (speexenc), "last_message");
713       }
714     }
715   } else if (speexenc->rate > 12500) {
716     if (speexenc->mode == GST_SPEEXENC_MODE_AUTO) {
717       speexenc->speex_mode = (SpeexMode *) & speex_wb_mode;
718     } else {
719       if (speexenc->speex_mode != &speex_wb_mode) {
720         speexenc->last_message =
721             g_strdup_printf
722             ("Warning: suggest to use wide band mode for this rate");
723         g_object_notify (G_OBJECT (speexenc), "last_message");
724       }
725     }
726   } else {
727     if (speexenc->mode == GST_SPEEXENC_MODE_AUTO) {
728       speexenc->speex_mode = (SpeexMode *) & speex_nb_mode;
729     } else {
730       if (speexenc->speex_mode != &speex_nb_mode) {
731         speexenc->last_message =
732             g_strdup_printf
733             ("Warning: suggest to use narrow band mode for this rate");
734         g_object_notify (G_OBJECT (speexenc), "last_message");
735       }
736     }
737   }
738
739   if (speexenc->rate != 8000 && speexenc->rate != 16000
740       && speexenc->rate != 32000) {
741     speexenc->last_message =
742         g_strdup_printf ("Warning: speex is optimized for 8, 16 and 32 KHz");
743     g_object_notify (G_OBJECT (speexenc), "last_message");
744   }
745
746   speex_init_header (&speexenc->header, speexenc->rate, 1,
747       speexenc->speex_mode);
748   speexenc->header.frames_per_packet = speexenc->nframes;
749   speexenc->header.vbr = speexenc->vbr;
750   speexenc->header.nb_channels = speexenc->channels;
751
752   /*Initialize Speex encoder */
753   speexenc->state = speex_encoder_init (speexenc->speex_mode);
754
755   speex_encoder_ctl (speexenc->state, SPEEX_GET_FRAME_SIZE,
756       &speexenc->frame_size);
757   speex_encoder_ctl (speexenc->state, SPEEX_SET_COMPLEXITY,
758       &speexenc->complexity);
759   speex_encoder_ctl (speexenc->state, SPEEX_SET_SAMPLING_RATE, &speexenc->rate);
760
761   if (speexenc->vbr)
762     speex_encoder_ctl (speexenc->state, SPEEX_SET_VBR_QUALITY,
763         &speexenc->quality);
764   else {
765     gint tmp = floor (speexenc->quality);
766
767     speex_encoder_ctl (speexenc->state, SPEEX_SET_QUALITY, &tmp);
768   }
769   if (speexenc->bitrate) {
770     if (speexenc->quality >= 0.0 && speexenc->vbr) {
771       speexenc->last_message =
772           g_strdup_printf ("Warning: bitrate option is overriding quality");
773       g_object_notify (G_OBJECT (speexenc), "last_message");
774     }
775     speex_encoder_ctl (speexenc->state, SPEEX_SET_BITRATE, &speexenc->bitrate);
776   }
777   if (speexenc->vbr) {
778     gint tmp = 1;
779
780     speex_encoder_ctl (speexenc->state, SPEEX_SET_VBR, &tmp);
781   } else if (speexenc->vad) {
782     gint tmp = 1;
783
784     speex_encoder_ctl (speexenc->state, SPEEX_SET_VAD, &tmp);
785   }
786
787   if (speexenc->dtx) {
788     gint tmp = 1;
789
790     speex_encoder_ctl (speexenc->state, SPEEX_SET_DTX, &tmp);
791   }
792
793   if (speexenc->dtx && !(speexenc->vbr || speexenc->abr || speexenc->vad)) {
794     speexenc->last_message =
795         g_strdup_printf ("Warning: dtx is useless without vad, vbr or abr");
796     g_object_notify (G_OBJECT (speexenc), "last_message");
797   } else if ((speexenc->vbr || speexenc->abr) && (speexenc->vad)) {
798     speexenc->last_message =
799         g_strdup_printf ("Warning: vad is already implied by vbr or abr");
800     g_object_notify (G_OBJECT (speexenc), "last_message");
801   }
802
803   if (speexenc->abr) {
804     speex_encoder_ctl (speexenc->state, SPEEX_SET_ABR, &speexenc->abr);
805   }
806
807   speex_encoder_ctl (speexenc->state, SPEEX_GET_LOOKAHEAD,
808       &speexenc->lookahead);
809
810   speexenc->setup = TRUE;
811
812   return TRUE;
813 }
814
815 /* prepare a buffer for transmission */
816 static GstBuffer *
817 gst_speexenc_buffer_from_data (GstSpeexEnc * speexenc, guchar * data,
818     gint data_len, guint64 granulepos)
819 {
820   GstBuffer *outbuf;
821
822   outbuf = gst_buffer_new_and_alloc (data_len);
823   memcpy (GST_BUFFER_DATA (outbuf), data, data_len);
824   GST_BUFFER_OFFSET (outbuf) = speexenc->bytes_out;
825   GST_BUFFER_OFFSET_END (outbuf) = granulepos;
826
827   GST_DEBUG ("encoded buffer of %d bytes", GST_BUFFER_SIZE (outbuf));
828   return outbuf;
829 }
830
831
832 /* push out the buffer and do internal bookkeeping */
833 static GstFlowReturn
834 gst_speexenc_push_buffer (GstSpeexEnc * speexenc, GstBuffer * buffer)
835 {
836   speexenc->bytes_out += GST_BUFFER_SIZE (buffer);
837
838   return gst_pad_push (speexenc->srcpad, buffer);
839
840 }
841
842 static GstCaps *
843 gst_speexenc_set_header_on_caps (GstCaps * caps, GstBuffer * buf1,
844     GstBuffer * buf2)
845 {
846   caps = gst_caps_make_writable (caps);
847   GstStructure *structure = gst_caps_get_structure (caps, 0);
848   GValue array = { 0 };
849   GValue value = { 0 };
850
851   /* mark buffers */
852   GST_BUFFER_FLAG_SET (buf1, GST_BUFFER_FLAG_IN_CAPS);
853   GST_BUFFER_FLAG_SET (buf2, GST_BUFFER_FLAG_IN_CAPS);
854
855   /* put buffers in a fixed list */
856   g_value_init (&array, GST_TYPE_ARRAY);
857   g_value_init (&value, GST_TYPE_BUFFER);
858   gst_value_set_buffer (&value, buf1);
859   gst_value_array_append_value (&array, &value);
860   g_value_unset (&value);
861   g_value_init (&value, GST_TYPE_BUFFER);
862   gst_value_set_buffer (&value, buf2);
863   gst_value_array_append_value (&array, &value);
864   gst_structure_set_value (structure, "streamheader", &array);
865   g_value_unset (&value);
866   g_value_unset (&array);
867
868   return caps;
869 }
870
871
872 static gboolean
873 gst_speexenc_sinkevent (GstPad * pad, GstEvent * event)
874 {
875   gboolean res = TRUE;
876   GstSpeexEnc *speexenc;
877
878   speexenc = GST_SPEEXENC (GST_PAD_PARENT (pad));
879
880   switch (GST_EVENT_TYPE (event)) {
881     case GST_EVENT_EOS:
882       speexenc->eos = TRUE;
883       res = gst_pad_event_default (pad, event);
884       break;
885     case GST_EVENT_TAG:
886     {
887       GstTagList *list;
888
889       gst_event_parse_tag (event, &list);
890       if (speexenc->tags) {
891         gst_tag_list_insert (speexenc->tags, list,
892             gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (speexenc)));
893       } else {
894         g_assert_not_reached ();
895       }
896       res = gst_pad_event_default (pad, event);
897       break;
898     }
899     default:
900       res = gst_pad_event_default (pad, event);
901       break;
902   }
903   return res;
904 }
905
906
907 static GstFlowReturn
908 gst_speexenc_chain (GstPad * pad, GstBuffer * buf)
909 {
910   GstSpeexEnc *speexenc;
911   GstFlowReturn ret = GST_FLOW_OK;
912
913   speexenc = GST_SPEEXENC (gst_pad_get_parent (pad));
914
915   if (!speexenc->setup)
916     goto not_setup;
917
918   if (!speexenc->header_sent) {
919     /* Speex streams begin with two headers; the initial header (with
920        most of the codec setup parameters) which is mandated by the Ogg
921        bitstream spec.  The second header holds any comment fields.
922        We merely need to make the headers, then pass them to libspeex 
923        one at a time; libspeex handles the additional Ogg bitstream 
924        constraints */
925     GstBuffer *buf1, *buf2;
926     GstCaps *caps;
927     guchar *data;
928     gint data_len;
929
930     gst_speexenc_set_metadata (speexenc);
931
932     /* create header buffer */
933     data = (guint8 *) speex_header_to_packet (&speexenc->header, &data_len);
934     buf1 = gst_speexenc_buffer_from_data (speexenc, data, data_len, 0);
935
936     /* create comment buffer */
937     buf2 =
938         gst_speexenc_buffer_from_data (speexenc, speexenc->comments,
939         speexenc->comment_len, 0);
940
941     /* mark and put on caps */
942     caps = gst_pad_get_caps (speexenc->srcpad);
943     caps = gst_speexenc_set_header_on_caps (caps, buf1, buf2);
944
945     /* negotiate with these caps */
946     GST_DEBUG ("here are the caps: %" GST_PTR_FORMAT, caps);
947     gst_pad_set_caps (speexenc->srcpad, caps);
948
949     gst_buffer_set_caps (buf1, caps);
950     gst_buffer_set_caps (buf2, caps);
951
952     /* push out buffers */
953     ret = gst_speexenc_push_buffer (speexenc, buf1);
954
955     if ((GST_FLOW_OK != ret) && (GST_FLOW_NOT_LINKED != ret)) {
956       /* unref buf2 as we are not going to push it anymore */
957
958       gst_buffer_unref (buf2);
959       goto done;
960     }
961
962     ret = gst_speexenc_push_buffer (speexenc, buf2);
963
964     if ((GST_FLOW_OK != ret) && (GST_FLOW_NOT_LINKED != ret))
965       goto done;
966
967     speex_bits_init (&speexenc->bits);
968     speex_bits_reset (&speexenc->bits);
969
970     speexenc->header_sent = TRUE;
971   }
972
973   {
974     gint frame_size = speexenc->frame_size;
975     gint bytes = frame_size * 2 * speexenc->channels;
976
977     /* push buffer to adapter */
978     gst_adapter_push (speexenc->adapter, buf);
979
980     while (gst_adapter_available (speexenc->adapter) >= bytes) {
981       gint16 *data;
982       gint i;
983       gint outsize, written;
984       GstBuffer *outbuf;
985
986       data = (gint16 *) gst_adapter_peek (speexenc->adapter, bytes);
987
988       for (i = 0; i < frame_size * speexenc->channels; i++) {
989         speexenc->input[i] = (gfloat) data[i];
990       }
991       gst_adapter_flush (speexenc->adapter, bytes);
992
993       speexenc->samples_in += frame_size;
994
995       if (speexenc->channels == 2) {
996         speex_encode_stereo (speexenc->input, frame_size, &speexenc->bits);
997       }
998       speex_encode (speexenc->state, speexenc->input, &speexenc->bits);
999
1000       speexenc->frameno++;
1001
1002       if ((speexenc->frameno % speexenc->nframes) != 0)
1003         continue;
1004
1005       speex_bits_insert_terminator (&speexenc->bits);
1006       outsize = speex_bits_nbytes (&speexenc->bits);
1007
1008       ret = gst_pad_alloc_buffer_and_set_caps (speexenc->srcpad,
1009           GST_BUFFER_OFFSET_NONE, outsize, GST_PAD_CAPS (speexenc->srcpad),
1010           &outbuf);
1011
1012       if ((GST_FLOW_OK != ret))
1013         goto done;
1014
1015       written = speex_bits_write (&speexenc->bits,
1016           (gchar *) GST_BUFFER_DATA (outbuf), outsize);
1017       g_assert (written == outsize);
1018       speex_bits_reset (&speexenc->bits);
1019
1020       GST_BUFFER_TIMESTAMP (outbuf) =
1021           gst_util_uint64_scale_int (speexenc->frameno * frame_size -
1022           speexenc->lookahead, GST_SECOND, speexenc->rate);
1023       GST_BUFFER_DURATION (outbuf) = gst_util_uint64_scale_int (frame_size,
1024           GST_SECOND, speexenc->rate);
1025       /* set gp time and granulepos; see gst-plugins-base/ext/ogg/README */
1026       GST_BUFFER_OFFSET_END (outbuf) =
1027           ((speexenc->frameno + 1) * frame_size - speexenc->lookahead);
1028       GST_BUFFER_OFFSET (outbuf) =
1029           gst_util_uint64_scale_int (GST_BUFFER_OFFSET_END (outbuf), GST_SECOND,
1030           speexenc->rate);
1031
1032       ret = gst_speexenc_push_buffer (speexenc, outbuf);
1033
1034       if ((GST_FLOW_OK != ret) && (GST_FLOW_NOT_LINKED != ret))
1035         goto done;
1036     }
1037   }
1038
1039 done:
1040   gst_object_unref (speexenc);
1041   return ret;
1042
1043   /* ERRORS */
1044 not_setup:
1045   {
1046     gst_buffer_unref (buf);
1047     GST_ELEMENT_ERROR (speexenc, CORE, NEGOTIATION, (NULL),
1048         ("encoder not initialized (input is not audio?)"));
1049     ret = GST_FLOW_NOT_NEGOTIATED;
1050     goto done;
1051   }
1052
1053 }
1054
1055
1056 static void
1057 gst_speexenc_get_property (GObject * object, guint prop_id, GValue * value,
1058     GParamSpec * pspec)
1059 {
1060   GstSpeexEnc *speexenc;
1061
1062   g_return_if_fail (GST_IS_SPEEXENC (object));
1063
1064   speexenc = GST_SPEEXENC (object);
1065
1066   switch (prop_id) {
1067     case ARG_QUALITY:
1068       g_value_set_float (value, speexenc->quality);
1069       break;
1070     case ARG_BITRATE:
1071       g_value_set_int (value, speexenc->bitrate);
1072       break;
1073     case ARG_VBR:
1074       g_value_set_boolean (value, speexenc->vbr);
1075       break;
1076     case ARG_ABR:
1077       g_value_set_int (value, speexenc->abr);
1078       break;
1079     case ARG_VAD:
1080       g_value_set_boolean (value, speexenc->vad);
1081       break;
1082     case ARG_DTX:
1083       g_value_set_boolean (value, speexenc->dtx);
1084       break;
1085     case ARG_COMPLEXITY:
1086       g_value_set_int (value, speexenc->complexity);
1087       break;
1088     case ARG_NFRAMES:
1089       g_value_set_int (value, speexenc->nframes);
1090       break;
1091     case ARG_LAST_MESSAGE:
1092       g_value_set_string (value, speexenc->last_message);
1093       break;
1094     default:
1095       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1096       break;
1097   }
1098 }
1099
1100 static void
1101 gst_speexenc_set_property (GObject * object, guint prop_id,
1102     const GValue * value, GParamSpec * pspec)
1103 {
1104   GstSpeexEnc *speexenc;
1105
1106   g_return_if_fail (GST_IS_SPEEXENC (object));
1107
1108   speexenc = GST_SPEEXENC (object);
1109
1110   switch (prop_id) {
1111     case ARG_QUALITY:
1112       speexenc->quality = g_value_get_float (value);
1113       break;
1114     case ARG_BITRATE:
1115       speexenc->bitrate = g_value_get_int (value);
1116       break;
1117     case ARG_VBR:
1118       speexenc->vbr = g_value_get_boolean (value);
1119       break;
1120     case ARG_ABR:
1121       speexenc->abr = g_value_get_int (value);
1122       break;
1123     case ARG_VAD:
1124       speexenc->vad = g_value_get_boolean (value);
1125       break;
1126     case ARG_DTX:
1127       speexenc->dtx = g_value_get_boolean (value);
1128       break;
1129     case ARG_COMPLEXITY:
1130       speexenc->complexity = g_value_get_int (value);
1131       break;
1132     case ARG_NFRAMES:
1133       speexenc->nframes = g_value_get_int (value);
1134       break;
1135     default:
1136       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1137       break;
1138   }
1139 }
1140
1141 static GstStateChangeReturn
1142 gst_speexenc_change_state (GstElement * element, GstStateChange transition)
1143 {
1144   GstSpeexEnc *speexenc = GST_SPEEXENC (element);
1145   GstStateChangeReturn res;
1146
1147   switch (transition) {
1148     case GST_STATE_CHANGE_NULL_TO_READY:
1149       speexenc->tags = gst_tag_list_new ();
1150       break;
1151     case GST_STATE_CHANGE_READY_TO_PAUSED:
1152       speexenc->frameno = 0;
1153       speexenc->samples_in = 0;
1154       break;
1155     case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
1156       /* fall through */
1157     default:
1158       break;
1159   }
1160
1161   res = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1162
1163   switch (transition) {
1164     case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
1165       break;
1166     case GST_STATE_CHANGE_PAUSED_TO_READY:
1167       speexenc->setup = FALSE;
1168       speexenc->header_sent = FALSE;
1169       break;
1170     case GST_STATE_CHANGE_READY_TO_NULL:
1171       gst_tag_list_free (speexenc->tags);
1172       speexenc->tags = NULL;
1173     default:
1174       break;
1175   }
1176
1177   return res;
1178 }