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