ext/: gsttaginterface.h -> gsttagsetter.h
[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 static const GstFormat *
79 gst_speexenc_get_formats (GstPad * pad)
80 {
81   static const GstFormat src_formats[] = {
82     GST_FORMAT_BYTES,
83     GST_FORMAT_TIME,
84     0
85   };
86   static const GstFormat sink_formats[] = {
87     GST_FORMAT_BYTES,
88     GST_FORMAT_DEFAULT,
89     GST_FORMAT_TIME,
90     0
91   };
92
93   return (GST_PAD_IS_SRC (pad) ? src_formats : sink_formats);
94 }
95
96 static void gst_speexenc_base_init (gpointer g_class);
97 static void gst_speexenc_class_init (GstSpeexEncClass * klass);
98 static void gst_speexenc_init (GstSpeexEnc * speexenc);
99
100 static void gst_speexenc_chain (GstPad * pad, GstData * _data);
101 static gboolean gst_speexenc_setup (GstSpeexEnc * speexenc);
102
103 static void gst_speexenc_get_property (GObject * object, guint prop_id,
104     GValue * value, GParamSpec * pspec);
105 static void gst_speexenc_set_property (GObject * object, guint prop_id,
106     const GValue * value, GParamSpec * pspec);
107 static GstStateChangeReturn gst_speexenc_change_state (GstElement * element,
108     GstStateChange transition);
109
110 static GstElementClass *parent_class = NULL;
111
112 /*static guint gst_speexenc_signals[LAST_SIGNAL] = { 0 }; */
113
114 GType
115 gst_speexenc_get_type (void)
116 {
117   static GType speexenc_type = 0;
118
119   if (!speexenc_type) {
120     static const GTypeInfo speexenc_info = {
121       sizeof (GstSpeexEncClass),
122       gst_speexenc_base_init,
123       NULL,
124       (GClassInitFunc) gst_speexenc_class_init,
125       NULL,
126       NULL,
127       sizeof (GstSpeexEnc),
128       0,
129       (GInstanceInitFunc) gst_speexenc_init,
130     };
131     static const GInterfaceInfo tag_setter_info = {
132       NULL,
133       NULL,
134       NULL
135     };
136
137     speexenc_type =
138         g_type_register_static (GST_TYPE_ELEMENT, "GstSpeexEnc", &speexenc_info,
139         0);
140
141     g_type_add_interface_static (speexenc_type, GST_TYPE_TAG_SETTER,
142         &tag_setter_info);
143
144     GST_DEBUG_CATEGORY_INIT (speexenc_debug, "speexenc", 0, "Speex encoder");
145   }
146   return speexenc_type;
147 }
148
149 static GstCaps *
150 speex_caps_factory (void)
151 {
152   return gst_caps_new_simple ("audio/x-speex", NULL);
153 }
154
155 static GstCaps *
156 raw_caps_factory (void)
157 {
158   return
159       gst_caps_new_simple ("audio/x-raw-int",
160       "rate", GST_TYPE_INT_RANGE, 6000, 48000,
161       "channels", GST_TYPE_INT_RANGE, 1, 2,
162       "endianness", G_TYPE_INT, G_BYTE_ORDER,
163       "signed", G_TYPE_BOOLEAN, TRUE,
164       "width", G_TYPE_INT, 16, "depth", G_TYPE_INT, 16, NULL);
165 }
166
167 static void
168 gst_speexenc_base_init (gpointer g_class)
169 {
170   GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
171   GstCaps *raw_caps, *speex_caps;
172
173   raw_caps = raw_caps_factory ();
174   speex_caps = speex_caps_factory ();
175
176   gst_speexenc_sink_template = gst_pad_template_new ("sink", GST_PAD_SINK,
177       GST_PAD_ALWAYS, raw_caps);
178   gst_speexenc_src_template = gst_pad_template_new ("src", GST_PAD_SRC,
179       GST_PAD_ALWAYS, speex_caps);
180   gst_element_class_add_pad_template (element_class,
181       gst_speexenc_sink_template);
182   gst_element_class_add_pad_template (element_class, gst_speexenc_src_template);
183   gst_element_class_set_details (element_class, &speexenc_details);
184 }
185
186 static void
187 gst_speexenc_class_init (GstSpeexEncClass * klass)
188 {
189   GObjectClass *gobject_class;
190   GstElementClass *gstelement_class;
191
192   gobject_class = (GObjectClass *) klass;
193   gstelement_class = (GstElementClass *) klass;
194
195   gobject_class->set_property = gst_speexenc_set_property;
196   gobject_class->get_property = gst_speexenc_get_property;
197
198   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_QUALITY,
199       g_param_spec_float ("quality", "Quality", "Encoding quality",
200           0.0, 10.0, DEFAULT_QUALITY, G_PARAM_READWRITE));
201   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_BITRATE,
202       g_param_spec_int ("bitrate", "Encoding Bit-rate",
203           "Specify an encoding bit-rate (in bps). (0 = automatic)",
204           0, G_MAXINT, DEFAULT_BITRATE, G_PARAM_READWRITE));
205   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_VBR,
206       g_param_spec_boolean ("vbr", "VBR",
207           "Enable variable bit-rate", DEFAULT_VBR, G_PARAM_READWRITE));
208   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_ABR,
209       g_param_spec_int ("abr", "ABR",
210           "Enable average bit-rate (0 = disabled)",
211           0, G_MAXINT, DEFAULT_ABR, G_PARAM_READWRITE));
212   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_VAD,
213       g_param_spec_boolean ("vad", "VAD",
214           "Enable voice activity detection", DEFAULT_VAD, G_PARAM_READWRITE));
215   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_DTX,
216       g_param_spec_boolean ("dtx", "DTX",
217           "Enable discontinuous transmission", DEFAULT_DTX, G_PARAM_READWRITE));
218   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_COMPLEXITY,
219       g_param_spec_int ("complexity", "Complexity",
220           "Set encoding complexity",
221           0, G_MAXINT, DEFAULT_COMPLEXITY, G_PARAM_READWRITE));
222   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_NFRAMES,
223       g_param_spec_int ("nframes", "NFrames",
224           "Number of frames per buffer",
225           0, G_MAXINT, DEFAULT_NFRAMES, G_PARAM_READWRITE));
226   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_LAST_MESSAGE,
227       g_param_spec_string ("last-message", "last-message",
228           "The last status message", NULL, G_PARAM_READABLE));
229
230   parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
231
232   gstelement_class->change_state = gst_speexenc_change_state;
233 }
234
235 static GstPadLinkReturn
236 gst_speexenc_sinkconnect (GstPad * pad, const GstCaps * caps)
237 {
238   GstSpeexEnc *speexenc;
239   GstStructure *structure;
240
241   speexenc = GST_SPEEXENC (gst_pad_get_parent (pad));
242   speexenc->setup = FALSE;
243
244   structure = gst_caps_get_structure (caps, 0);
245   gst_structure_get_int (structure, "channels", &speexenc->channels);
246   gst_structure_get_int (structure, "rate", &speexenc->rate);
247
248   gst_speexenc_setup (speexenc);
249
250   if (speexenc->setup)
251     return GST_PAD_LINK_OK;
252
253   return GST_PAD_LINK_REFUSED;
254 }
255
256 static gboolean
257 gst_speexenc_convert_src (GstPad * pad, GstFormat src_format, gint64 src_value,
258     GstFormat * dest_format, gint64 * dest_value)
259 {
260   gboolean res = TRUE;
261   GstSpeexEnc *speexenc;
262   gint64 avg;
263
264   speexenc = GST_SPEEXENC (gst_pad_get_parent (pad));
265
266   if (speexenc->samples_in == 0 ||
267       speexenc->bytes_out == 0 || speexenc->rate == 0)
268     return FALSE;
269
270   avg = (speexenc->bytes_out * speexenc->rate) / (speexenc->samples_in);
271
272   switch (src_format) {
273     case GST_FORMAT_BYTES:
274       switch (*dest_format) {
275         case GST_FORMAT_TIME:
276           *dest_value = src_value * GST_SECOND / avg;
277           break;
278         default:
279           res = FALSE;
280       }
281       break;
282     case GST_FORMAT_TIME:
283       switch (*dest_format) {
284         case GST_FORMAT_BYTES:
285           *dest_value = src_value * avg / GST_SECOND;
286           break;
287         default:
288           res = FALSE;
289       }
290       break;
291     default:
292       res = FALSE;
293   }
294   return res;
295 }
296
297 static gboolean
298 gst_speexenc_convert_sink (GstPad * pad, GstFormat src_format,
299     gint64 src_value, GstFormat * dest_format, gint64 * dest_value)
300 {
301   gboolean res = TRUE;
302   guint scale = 1;
303   gint bytes_per_sample;
304   GstSpeexEnc *speexenc;
305
306   speexenc = GST_SPEEXENC (gst_pad_get_parent (pad));
307
308   bytes_per_sample = speexenc->channels * 2;
309
310   switch (src_format) {
311     case GST_FORMAT_BYTES:
312       switch (*dest_format) {
313         case GST_FORMAT_DEFAULT:
314           if (bytes_per_sample == 0)
315             return FALSE;
316           *dest_value = src_value / bytes_per_sample;
317           break;
318         case GST_FORMAT_TIME:
319         {
320           gint byterate = bytes_per_sample * speexenc->rate;
321
322           if (byterate == 0)
323             return FALSE;
324           *dest_value = src_value * GST_SECOND / byterate;
325           break;
326         }
327         default:
328           res = FALSE;
329       }
330       break;
331     case GST_FORMAT_DEFAULT:
332       switch (*dest_format) {
333         case GST_FORMAT_BYTES:
334           *dest_value = src_value * bytes_per_sample;
335           break;
336         case GST_FORMAT_TIME:
337           if (speexenc->rate == 0)
338             return FALSE;
339           *dest_value = src_value * GST_SECOND / speexenc->rate;
340           break;
341         default:
342           res = FALSE;
343       }
344       break;
345     case GST_FORMAT_TIME:
346       switch (*dest_format) {
347         case GST_FORMAT_BYTES:
348           scale = bytes_per_sample;
349           /* fallthrough */
350         case GST_FORMAT_DEFAULT:
351           *dest_value = src_value * scale * speexenc->rate / GST_SECOND;
352           break;
353         default:
354           res = FALSE;
355       }
356       break;
357     default:
358       res = FALSE;
359   }
360   return res;
361 }
362
363 static const GstQueryType *
364 gst_speexenc_get_query_types (GstPad * pad)
365 {
366   static const GstQueryType gst_speexenc_src_query_types[] = {
367     GST_QUERY_TOTAL,
368     GST_QUERY_POSITION,
369     0
370   };
371
372   return gst_speexenc_src_query_types;
373 }
374
375 static gboolean
376 gst_speexenc_src_query (GstPad * pad, GstQueryType type,
377     GstFormat * format, gint64 * value)
378 {
379   gboolean res = TRUE;
380   GstSpeexEnc *speexenc;
381
382   speexenc = GST_SPEEXENC (gst_pad_get_parent (pad));
383
384   switch (type) {
385     case GST_QUERY_TOTAL:
386     {
387       switch (*format) {
388         case GST_FORMAT_BYTES:
389         case GST_FORMAT_TIME:
390         {
391           gint64 peer_value;
392           const GstFormat *peer_formats;
393
394           res = FALSE;
395
396           peer_formats = gst_pad_get_formats (GST_PAD_PEER (speexenc->sinkpad));
397
398           while (peer_formats && *peer_formats && !res) {
399
400             GstFormat peer_format = *peer_formats;
401
402             /* do the probe */
403             if (gst_pad_query (GST_PAD_PEER (speexenc->sinkpad),
404                     GST_QUERY_TOTAL, &peer_format, &peer_value)) {
405               GstFormat conv_format;
406
407               /* convert to TIME */
408               conv_format = GST_FORMAT_TIME;
409               res = gst_pad_convert (speexenc->sinkpad,
410                   peer_format, peer_value, &conv_format, value);
411               /* and to final format */
412               res &= gst_pad_convert (pad,
413                   GST_FORMAT_TIME, *value, format, value);
414             }
415             peer_formats++;
416           }
417           break;
418         }
419         default:
420           res = FALSE;
421           break;
422       }
423       break;
424     }
425     case GST_QUERY_POSITION:
426       switch (*format) {
427         default:
428         {
429           /* we only know about our samples, convert to requested format */
430           res = gst_pad_convert (pad,
431               GST_FORMAT_BYTES, speexenc->bytes_out, format, value);
432           break;
433         }
434       }
435       break;
436     default:
437       res = FALSE;
438       break;
439   }
440   return res;
441 }
442
443 static void
444 gst_speexenc_init (GstSpeexEnc * speexenc)
445 {
446   speexenc->sinkpad =
447       gst_pad_new_from_template (gst_speexenc_sink_template, "sink");
448   gst_element_add_pad (GST_ELEMENT (speexenc), speexenc->sinkpad);
449   gst_pad_set_chain_function (speexenc->sinkpad, gst_speexenc_chain);
450   gst_pad_set_link_function (speexenc->sinkpad, gst_speexenc_sinkconnect);
451   gst_pad_set_convert_function (speexenc->sinkpad,
452       GST_DEBUG_FUNCPTR (gst_speexenc_convert_sink));
453   gst_pad_set_formats_function (speexenc->sinkpad,
454       GST_DEBUG_FUNCPTR (gst_speexenc_get_formats));
455
456   speexenc->srcpad =
457       gst_pad_new_from_template (gst_speexenc_src_template, "src");
458   gst_pad_set_query_function (speexenc->srcpad,
459       GST_DEBUG_FUNCPTR (gst_speexenc_src_query));
460   gst_pad_set_query_type_function (speexenc->srcpad,
461       GST_DEBUG_FUNCPTR (gst_speexenc_get_query_types));
462   gst_pad_set_convert_function (speexenc->srcpad,
463       GST_DEBUG_FUNCPTR (gst_speexenc_convert_src));
464   gst_pad_set_formats_function (speexenc->srcpad,
465       GST_DEBUG_FUNCPTR (gst_speexenc_get_formats));
466   gst_element_add_pad (GST_ELEMENT (speexenc), speexenc->srcpad);
467
468   speexenc->channels = -1;
469   speexenc->rate = -1;
470
471   speexenc->quality = DEFAULT_QUALITY;
472   speexenc->bitrate = DEFAULT_BITRATE;
473   speexenc->vbr = DEFAULT_VBR;
474   speexenc->abr = DEFAULT_ABR;
475   speexenc->vad = DEFAULT_VAD;
476   speexenc->dtx = DEFAULT_DTX;
477   speexenc->complexity = DEFAULT_COMPLEXITY;
478   speexenc->nframes = DEFAULT_NFRAMES;
479
480   speexenc->setup = FALSE;
481   speexenc->eos = FALSE;
482   speexenc->header_sent = FALSE;
483
484   speexenc->tags = gst_tag_list_new ();
485   speexenc->adapter = gst_adapter_new ();
486
487   /* we're chained and we can deal with events */
488   GST_FLAG_SET (speexenc, GST_ELEMENT_EVENT_AWARE);
489 }
490
491
492 static gchar *
493 gst_speexenc_get_tag_value (const GstTagList * list, const gchar * tag,
494     int index)
495 {
496   gchar *speexvalue = NULL;
497
498   if (tag == NULL) {
499     return NULL;
500   }
501
502   /* get tag name right */
503   if ((strcmp (tag, GST_TAG_TRACK_NUMBER) == 0)
504       || (strcmp (tag, GST_TAG_ALBUM_VOLUME_NUMBER) == 0)
505       || (strcmp (tag, GST_TAG_TRACK_COUNT) == 0)
506       || (strcmp (tag, GST_TAG_ALBUM_VOLUME_COUNT) == 0)) {
507     guint track_no;
508
509     if (!gst_tag_list_get_uint_index (list, tag, index, &track_no))
510       g_assert_not_reached ();
511     speexvalue = g_strdup_printf ("%u", track_no);
512   } else if (strcmp (tag, GST_TAG_DATE) == 0) {
513     /* FIXME: how are dates represented in speex files? */
514     GDate *date;
515     guint u;
516
517     if (!gst_tag_list_get_uint_index (list, tag, index, &u))
518       g_assert_not_reached ();
519     date = g_date_new_julian (u);
520     speexvalue =
521         g_strdup_printf ("%04d-%02d-%02d", (gint) g_date_get_year (date),
522         (gint) g_date_get_month (date), (gint) g_date_get_day (date));
523     g_date_free (date);
524   } else if (gst_tag_get_type (tag) == G_TYPE_STRING) {
525     if (!gst_tag_list_get_string_index (list, tag, index, &speexvalue))
526       g_assert_not_reached ();
527   }
528
529   return speexvalue;
530 }
531
532 /*
533  *  Comments will be stored in the Vorbis style.
534  *  It is describled in the "Structure" section of
535  *  http://www.xiph.org/ogg/vorbis/doc/v-comment.html
536  *
537  *  The comment header is decoded as follows:
538  *  1) [vendor_length] = read an unsigned integer of 32 bits
539  *  2) [vendor_string] = read a UTF-8 vector as [vendor_length] octets
540  *  3) [user_comment_list_length] = read an unsigned integer of 32 bits
541  *  4) iterate [user_comment_list_length] times {
542  *     5) [length] = read an unsigned integer of 32 bits
543  *     6) this iteration's user comment = read a UTF-8 vector as [length] octets
544  *     }
545  *  7) [framing_bit] = read a single bit as boolean
546  *  8) if ( [framing_bit]  unset or end of packet ) then ERROR
547  *  9) done.
548  *
549  *  If you have troubles, please write to ymnk@jcraft.com.
550  */
551 #define readint(buf, base) (((buf[base+3]<<24) & 0xff000000)| \
552                             ((buf[base+2]<<16) & 0xff0000)|   \
553                             ((buf[base+1]<< 8) & 0xff00)|     \
554                              (buf[base  ]      & 0xff))
555 #define writeint(buf, base, val) do{ buf[base+3] = ((val)>>24) & 0xff; \
556                                      buf[base+2] = ((val)>>16) & 0xff; \
557                                      buf[base+1] = ((val)>> 8) & 0xff; \
558                                      buf[base  ] =  (val)      & 0xff; \
559                                   }while(0)
560
561 static void
562 comment_init (char **comments, int *length, char *vendor_string)
563 {
564   int vendor_length = strlen (vendor_string);
565   int user_comment_list_length = 0;
566   int len = 4 + vendor_length + 4;
567   char *p = (char *) malloc (len);
568
569   if (p == NULL) {
570   }
571   writeint (p, 0, vendor_length);
572   memcpy (p + 4, vendor_string, vendor_length);
573   writeint (p, 4 + vendor_length, user_comment_list_length);
574   *length = len;
575   *comments = p;
576 }
577 static void
578 comment_add (char **comments, int *length, const char *tag, char *val)
579 {
580   char *p = *comments;
581   int vendor_length = readint (p, 0);
582   int user_comment_list_length = readint (p, 4 + vendor_length);
583   int tag_len = (tag ? strlen (tag) : 0);
584   int val_len = strlen (val);
585   int len = (*length) + 4 + tag_len + val_len;
586
587   p = (char *) realloc (p, len);
588
589   writeint (p, *length, tag_len + val_len);     /* length of comment */
590   if (tag)
591     memcpy (p + *length + 4, tag, tag_len);     /* comment */
592   memcpy (p + *length + 4 + tag_len, val, val_len);     /* comment */
593   writeint (p, 4 + vendor_length, user_comment_list_length + 1);
594
595   *comments = p;
596   *length = len;
597 }
598
599 #undef readint
600 #undef writeint
601
602 static void
603 gst_speexenc_metadata_set1 (const GstTagList * list, const gchar * tag,
604     gpointer speexenc)
605 {
606   const gchar *speextag = NULL;
607   gchar *speexvalue = NULL;
608   guint i, count;
609   GstSpeexEnc *enc = GST_SPEEXENC (speexenc);
610
611   speextag = gst_tag_to_vorbis_tag (tag);
612   if (speextag == NULL) {
613     return;
614   }
615
616   count = gst_tag_list_get_tag_size (list, tag);
617   for (i = 0; i < count; i++) {
618     speexvalue = gst_speexenc_get_tag_value (list, tag, i);
619
620     if (speexvalue != NULL) {
621       comment_add (&enc->comments, &enc->comment_len, speextag, speexvalue);
622     }
623   }
624 }
625
626 static void
627 gst_speexenc_set_metadata (GstSpeexEnc * speexenc)
628 {
629   GstTagList *copy;
630   const GstTagList *user_tags;
631
632   user_tags = gst_tag_setter_get_list (GST_TAG_SETTER (speexenc));
633   if (!(speexenc->tags || user_tags))
634     return;
635
636   comment_init (&speexenc->comments, &speexenc->comment_len,
637       "Encoded with GStreamer Speexenc");
638   copy =
639       gst_tag_list_merge (user_tags, speexenc->tags,
640       gst_tag_setter_get_merge_mode (GST_TAG_SETTER (speexenc)));
641   gst_tag_list_foreach (copy, gst_speexenc_metadata_set1, speexenc);
642   gst_tag_list_free (copy);
643 }
644
645 static gboolean
646 gst_speexenc_setup (GstSpeexEnc * speexenc)
647 {
648   speexenc->setup = FALSE;
649
650   switch (speexenc->mode) {
651     case GST_SPEEXENC_MODE_UWB:
652       speexenc->speex_mode = (SpeexMode *) & speex_uwb_mode;
653       break;
654     case GST_SPEEXENC_MODE_WB:
655       speexenc->speex_mode = (SpeexMode *) & speex_wb_mode;
656       break;
657     case GST_SPEEXENC_MODE_NB:
658       speexenc->speex_mode = (SpeexMode *) & speex_nb_mode;
659       break;
660     case GST_SPEEXENC_MODE_AUTO:
661     default:
662       break;
663   }
664
665   if (speexenc->rate > 25000) {
666     if (speexenc->mode == GST_SPEEXENC_MODE_AUTO) {
667       speexenc->speex_mode = (SpeexMode *) & speex_uwb_mode;
668     } else {
669       if (speexenc->speex_mode != &speex_uwb_mode) {
670         speexenc->last_message =
671             g_strdup_printf
672             ("Warning: suggest to use ultra wide band mode for this rate");
673         g_object_notify (G_OBJECT (speexenc), "last_message");
674       }
675     }
676   } else if (speexenc->rate > 12500) {
677     if (speexenc->mode == GST_SPEEXENC_MODE_AUTO) {
678       speexenc->speex_mode = (SpeexMode *) & speex_wb_mode;
679     } else {
680       if (speexenc->speex_mode != &speex_wb_mode) {
681         speexenc->last_message =
682             g_strdup_printf
683             ("Warning: suggest to use wide band mode for this rate");
684         g_object_notify (G_OBJECT (speexenc), "last_message");
685       }
686     }
687   } else {
688     if (speexenc->mode == GST_SPEEXENC_MODE_AUTO) {
689       speexenc->speex_mode = (SpeexMode *) & speex_nb_mode;
690     } else {
691       if (speexenc->speex_mode != &speex_nb_mode) {
692         speexenc->last_message =
693             g_strdup_printf
694             ("Warning: suggest to use narrow band mode for this rate");
695         g_object_notify (G_OBJECT (speexenc), "last_message");
696       }
697     }
698   }
699
700   if (speexenc->rate != 8000 && speexenc->rate != 16000
701       && speexenc->rate != 32000) {
702     speexenc->last_message =
703         g_strdup_printf ("Warning: speex is optimized for 8, 16 and 32 KHz");
704     g_object_notify (G_OBJECT (speexenc), "last_message");
705   }
706
707   speex_init_header (&speexenc->header, speexenc->rate, 1,
708       speexenc->speex_mode);
709   speexenc->header.frames_per_packet = speexenc->nframes;
710   speexenc->header.vbr = speexenc->vbr;
711   speexenc->header.nb_channels = speexenc->channels;
712
713   /*Initialize Speex encoder */
714   speexenc->state = speex_encoder_init (speexenc->speex_mode);
715
716   speex_encoder_ctl (speexenc->state, SPEEX_GET_FRAME_SIZE,
717       &speexenc->frame_size);
718   speex_encoder_ctl (speexenc->state, SPEEX_SET_COMPLEXITY,
719       &speexenc->complexity);
720   speex_encoder_ctl (speexenc->state, SPEEX_SET_SAMPLING_RATE, &speexenc->rate);
721
722   if (speexenc->vbr)
723     speex_encoder_ctl (speexenc->state, SPEEX_SET_VBR_QUALITY,
724         &speexenc->quality);
725   else {
726     gint tmp = floor (speexenc->quality);
727
728     speex_encoder_ctl (speexenc->state, SPEEX_SET_QUALITY, &tmp);
729   }
730   if (speexenc->bitrate) {
731     if (speexenc->quality >= 0.0 && speexenc->vbr) {
732       speexenc->last_message =
733           g_strdup_printf ("Warning: bitrate option is overriding quality");
734       g_object_notify (G_OBJECT (speexenc), "last_message");
735     }
736     speex_encoder_ctl (speexenc->state, SPEEX_SET_BITRATE, &speexenc->bitrate);
737   }
738   if (speexenc->vbr) {
739     gint tmp = 1;
740
741     speex_encoder_ctl (speexenc->state, SPEEX_SET_VBR, &tmp);
742   } else if (speexenc->vad) {
743     gint tmp = 1;
744
745     speex_encoder_ctl (speexenc->state, SPEEX_SET_VAD, &tmp);
746   }
747
748   if (speexenc->dtx) {
749     gint tmp = 1;
750
751     speex_encoder_ctl (speexenc->state, SPEEX_SET_DTX, &tmp);
752   }
753
754   if (speexenc->dtx && !(speexenc->vbr || speexenc->abr || speexenc->vad)) {
755     speexenc->last_message =
756         g_strdup_printf ("Warning: dtx is useless without vad, vbr or abr");
757     g_object_notify (G_OBJECT (speexenc), "last_message");
758   } else if ((speexenc->vbr || speexenc->abr) && (speexenc->vad)) {
759     speexenc->last_message =
760         g_strdup_printf ("Warning: vad is already implied by vbr or abr");
761     g_object_notify (G_OBJECT (speexenc), "last_message");
762   }
763
764   if (speexenc->abr) {
765     speex_encoder_ctl (speexenc->state, SPEEX_SET_ABR, &speexenc->abr);
766   }
767
768   speex_encoder_ctl (speexenc->state, SPEEX_GET_LOOKAHEAD,
769       &speexenc->lookahead);
770
771   speexenc->setup = TRUE;
772
773   return TRUE;
774 }
775
776 /* prepare a buffer for transmission */
777 static GstBuffer *
778 gst_speexenc_buffer_from_data (GstSpeexEnc * speexenc, guchar * data,
779     gint data_len, guint64 granulepos)
780 {
781   GstBuffer *outbuf;
782
783   outbuf = gst_buffer_new_and_alloc (data_len);
784   memcpy (GST_BUFFER_DATA (outbuf), data, data_len);
785   GST_BUFFER_OFFSET (outbuf) = speexenc->bytes_out;
786   GST_BUFFER_OFFSET_END (outbuf) = granulepos;
787
788   GST_DEBUG ("encoded buffer of %d bytes", GST_BUFFER_SIZE (outbuf));
789   return outbuf;
790 }
791
792 /* push out the buffer and do internal bookkeeping */
793 static void
794 gst_speexenc_push_buffer (GstSpeexEnc * speexenc, GstBuffer * buffer)
795 {
796   speexenc->bytes_out += GST_BUFFER_SIZE (buffer);
797
798   if (GST_PAD_IS_USABLE (speexenc->srcpad)) {
799     gst_pad_push (speexenc->srcpad, GST_DATA (buffer));
800   } else {
801     gst_buffer_unref (buffer);
802   }
803 }
804
805 static void
806 gst_speexenc_set_header_on_caps (GstCaps * caps, GstBuffer * buf1,
807     GstBuffer * buf2)
808 {
809   GstStructure *structure = gst_caps_get_structure (caps, 0);
810   GValue list = { 0 };
811   GValue value = { 0 };
812
813   /* mark buffers */
814   GST_BUFFER_FLAG_SET (buf1, GST_BUFFER_IN_CAPS);
815   GST_BUFFER_FLAG_SET (buf2, GST_BUFFER_IN_CAPS);
816
817   /* put buffers in a fixed list */
818   g_value_init (&list, GST_TYPE_FIXED_LIST);
819   g_value_init (&value, GST_TYPE_BUFFER);
820   g_value_set_boxed (&value, buf1);
821   gst_value_list_append_value (&list, &value);
822   g_value_unset (&value);
823   g_value_init (&value, GST_TYPE_BUFFER);
824   g_value_set_boxed (&value, buf2);
825   gst_value_list_append_value (&list, &value);
826   gst_structure_set_value (structure, "streamheader", &list);
827   g_value_unset (&value);
828   g_value_unset (&list);
829 }
830
831 static void
832 gst_speexenc_chain (GstPad * pad, GstData * _data)
833 {
834   GstBuffer *buf = GST_BUFFER (_data);
835   GstSpeexEnc *speexenc;
836
837   g_return_if_fail (pad != NULL);
838   g_return_if_fail (GST_IS_PAD (pad));
839   g_return_if_fail (buf != NULL);
840
841   speexenc = GST_SPEEXENC (gst_pad_get_parent (pad));
842
843   if (GST_IS_EVENT (buf)) {
844     GstEvent *event = GST_EVENT (buf);
845
846     switch (GST_EVENT_TYPE (event)) {
847       case GST_EVENT_EOS:
848         speexenc->eos = TRUE;
849         gst_event_unref (event);
850         break;
851       case GST_EVENT_TAG:
852         if (speexenc->tags) {
853           gst_tag_list_insert (speexenc->tags, gst_event_tag_get_list (event),
854               gst_tag_setter_get_merge_mode (GST_TAG_SETTER (speexenc)));
855         } else {
856           g_assert_not_reached ();
857         }
858         gst_pad_event_default (pad, event);
859         return;
860       default:
861         gst_pad_event_default (pad, event);
862         return;
863     }
864   } else {
865     if (!speexenc->setup) {
866       gst_buffer_unref (buf);
867       GST_ELEMENT_ERROR (speexenc, CORE, NEGOTIATION, (NULL),
868           ("encoder not initialized (input is not audio?)"));
869       return;
870     }
871
872     if (!speexenc->header_sent) {
873       /* Speex streams begin with two headers; the initial header (with
874          most of the codec setup parameters) which is mandated by the Ogg
875          bitstream spec.  The second header holds any comment fields.
876          We merely need to make the headers, then pass them to libspeex 
877          one at a time; libspeex handles the additional Ogg bitstream 
878          constraints */
879       GstBuffer *buf1, *buf2;
880       GstCaps *caps;
881       guchar *data;
882       gint data_len;
883
884       gst_speexenc_set_metadata (speexenc);
885
886       /* create header buffer */
887       data = speex_header_to_packet (&speexenc->header, &data_len);
888       buf1 = gst_speexenc_buffer_from_data (speexenc, data, data_len, 0);
889
890       /* create comment buffer */
891       buf2 =
892           gst_speexenc_buffer_from_data (speexenc, speexenc->comments,
893           speexenc->comment_len, 0);
894
895       /* mark and put on caps */
896       caps = gst_pad_get_caps (speexenc->srcpad);
897       gst_speexenc_set_header_on_caps (caps, buf1, buf2);
898
899       /* negotiate with these caps */
900       GST_DEBUG ("here are the caps: %" GST_PTR_FORMAT, caps);
901       gst_pad_try_set_caps (speexenc->srcpad, caps);
902
903       /* push out buffers */
904       gst_speexenc_push_buffer (speexenc, buf1);
905       gst_speexenc_push_buffer (speexenc, buf2);
906
907       speex_bits_init (&speexenc->bits);
908       speex_bits_reset (&speexenc->bits);
909
910       speexenc->header_sent = TRUE;
911     }
912
913     {
914       gint frame_size = speexenc->frame_size;
915       gint bytes = frame_size * 2 * speexenc->channels;
916
917       /* push buffer to adapter */
918       gst_adapter_push (speexenc->adapter, buf);
919
920       while (gst_adapter_available (speexenc->adapter) >= bytes) {
921         gint16 *data;
922         gint i;
923         gint outsize, written;
924         GstBuffer *outbuf;
925
926         data = (gint16 *) gst_adapter_peek (speexenc->adapter, bytes);
927
928         for (i = 0; i < frame_size * speexenc->channels; i++) {
929           speexenc->input[i] = (gfloat) data[i];
930         }
931         gst_adapter_flush (speexenc->adapter, bytes);
932
933         speexenc->samples_in += frame_size;
934
935         if (speexenc->channels == 2) {
936           speex_encode_stereo (speexenc->input, frame_size, &speexenc->bits);
937         }
938         speex_encode (speexenc->state, speexenc->input, &speexenc->bits);
939
940         speexenc->frameno++;
941
942         if ((speexenc->frameno % speexenc->nframes) != 0)
943           continue;
944
945         speex_bits_insert_terminator (&speexenc->bits);
946         outsize = speex_bits_nbytes (&speexenc->bits);
947         outbuf =
948             gst_pad_alloc_buffer (speexenc->srcpad, GST_BUFFER_OFFSET_NONE,
949             outsize);
950         written =
951             speex_bits_write (&speexenc->bits, GST_BUFFER_DATA (outbuf),
952             outsize);
953         g_assert (written == outsize);
954         speex_bits_reset (&speexenc->bits);
955
956         GST_BUFFER_TIMESTAMP (outbuf) =
957             (speexenc->frameno * frame_size -
958             speexenc->lookahead) * GST_SECOND / speexenc->rate;
959         GST_BUFFER_DURATION (outbuf) = frame_size * GST_SECOND / speexenc->rate;
960         GST_BUFFER_OFFSET (outbuf) = speexenc->bytes_out;
961         GST_BUFFER_OFFSET_END (outbuf) =
962             speexenc->frameno * frame_size - speexenc->lookahead;
963
964         gst_speexenc_push_buffer (speexenc, outbuf);
965       }
966     }
967   }
968
969   if (speexenc->eos) {
970     /* clean up and exit. */
971     gst_pad_push (speexenc->srcpad, GST_DATA (gst_event_new (GST_EVENT_EOS)));
972     gst_element_set_eos (GST_ELEMENT (speexenc));
973   }
974 }
975
976 static void
977 gst_speexenc_get_property (GObject * object, guint prop_id, GValue * value,
978     GParamSpec * pspec)
979 {
980   GstSpeexEnc *speexenc;
981
982   g_return_if_fail (GST_IS_SPEEXENC (object));
983
984   speexenc = GST_SPEEXENC (object);
985
986   switch (prop_id) {
987     case ARG_QUALITY:
988       g_value_set_float (value, speexenc->quality);
989       break;
990     case ARG_BITRATE:
991       g_value_set_int (value, speexenc->bitrate);
992       break;
993     case ARG_VBR:
994       g_value_set_boolean (value, speexenc->vbr);
995       break;
996     case ARG_ABR:
997       g_value_set_int (value, speexenc->abr);
998       break;
999     case ARG_VAD:
1000       g_value_set_boolean (value, speexenc->vad);
1001       break;
1002     case ARG_DTX:
1003       g_value_set_boolean (value, speexenc->dtx);
1004       break;
1005     case ARG_COMPLEXITY:
1006       g_value_set_int (value, speexenc->complexity);
1007       break;
1008     case ARG_NFRAMES:
1009       g_value_set_int (value, speexenc->nframes);
1010       break;
1011     case ARG_LAST_MESSAGE:
1012       g_value_set_string (value, speexenc->last_message);
1013       break;
1014     default:
1015       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1016       break;
1017   }
1018 }
1019
1020 static void
1021 gst_speexenc_set_property (GObject * object, guint prop_id,
1022     const GValue * value, GParamSpec * pspec)
1023 {
1024   GstSpeexEnc *speexenc;
1025
1026   g_return_if_fail (GST_IS_SPEEXENC (object));
1027
1028   speexenc = GST_SPEEXENC (object);
1029
1030   switch (prop_id) {
1031     case ARG_QUALITY:
1032       speexenc->quality = g_value_get_float (value);
1033       break;
1034     case ARG_BITRATE:
1035       speexenc->bitrate = g_value_get_int (value);
1036       break;
1037     case ARG_VBR:
1038       speexenc->vbr = g_value_get_boolean (value);
1039       break;
1040     case ARG_ABR:
1041       speexenc->abr = g_value_get_int (value);
1042       break;
1043     case ARG_VAD:
1044       speexenc->vad = g_value_get_boolean (value);
1045       break;
1046     case ARG_DTX:
1047       speexenc->dtx = g_value_get_boolean (value);
1048       break;
1049     case ARG_COMPLEXITY:
1050       speexenc->complexity = g_value_get_int (value);
1051       break;
1052     case ARG_NFRAMES:
1053       speexenc->nframes = g_value_get_int (value);
1054       break;
1055     default:
1056       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1057       break;
1058   }
1059 }
1060
1061 static GstStateChangeReturn
1062 gst_speexenc_change_state (GstElement * element, GstStateChange transition)
1063 {
1064   GstSpeexEnc *speexenc = GST_SPEEXENC (element);
1065
1066   switch (transition) {
1067     case GST_STATE_CHANGE_NULL_TO_READY:
1068       break;
1069     case GST_STATE_CHANGE_READY_TO_PAUSED:
1070       speexenc->eos = FALSE;
1071       speexenc->frameno = 0;
1072       speexenc->samples_in = 0;
1073       break;
1074     case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
1075     case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
1076       break;
1077     case GST_STATE_CHANGE_PAUSED_TO_READY:
1078       speexenc->setup = FALSE;
1079       speexenc->header_sent = FALSE;
1080       gst_tag_list_free (speexenc->tags);
1081       speexenc->tags = gst_tag_list_new ();
1082       break;
1083     case GST_STATE_CHANGE_READY_TO_NULL:
1084     default:
1085       break;
1086   }
1087
1088   if (GST_ELEMENT_CLASS (parent_class)->change_state)
1089     return GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1090
1091   return GST_STATE_CHANGE_SUCCESS;
1092 }