Update for gst_tag_setter API changes.
[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     GST_QUERY_DURATION,
372     GST_QUERY_CONVERT,
373     0
374   };
375
376   return gst_speexenc_src_query_types;
377 }
378
379 static gboolean
380 gst_speexenc_src_query (GstPad * pad, GstQuery * query)
381 {
382   gboolean res = TRUE;
383   GstSpeexEnc *speexenc;
384   GstPad *peerpad;
385
386   speexenc = GST_SPEEXENC (gst_pad_get_parent (pad));
387   peerpad = gst_pad_get_peer (GST_PAD (speexenc->sinkpad));
388
389   switch (GST_QUERY_TYPE (query)) {
390     case GST_QUERY_POSITION:
391     {
392       GstFormat fmt, req_fmt;
393       gint64 pos, val;
394
395       gst_query_parse_position (query, &req_fmt, NULL);
396       if ((res = gst_pad_query_position (peerpad, &req_fmt, &val))) {
397         gst_query_set_position (query, req_fmt, val);
398         break;
399       }
400
401       fmt = GST_FORMAT_TIME;
402       if (!(res = gst_pad_query_position (peerpad, &fmt, &pos)))
403         break;
404
405       if ((res = gst_pad_query_convert (peerpad, fmt, pos, &req_fmt, &val)))
406         gst_query_set_position (query, req_fmt, val);
407
408       break;
409     }
410     case GST_QUERY_DURATION:
411     {
412       GstFormat fmt, req_fmt;
413       gint64 dur, val;
414
415       gst_query_parse_duration (query, &req_fmt, NULL);
416       if ((res = gst_pad_query_duration (peerpad, &req_fmt, &val))) {
417         gst_query_set_duration (query, req_fmt, val);
418         break;
419       }
420
421       fmt = GST_FORMAT_TIME;
422       if (!(res = gst_pad_query_duration (peerpad, &fmt, &dur)))
423         break;
424
425       if ((res = gst_pad_query_convert (peerpad, fmt, dur, &req_fmt, &val))) {
426         gst_query_set_duration (query, req_fmt, val);
427       }
428       break;
429     }
430     case GST_QUERY_CONVERT:
431     {
432       GstFormat src_fmt, dest_fmt;
433       gint64 src_val, dest_val;
434
435       gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, &dest_val);
436       if (!(res = gst_speexenc_convert_src (pad, src_fmt, src_val, &dest_fmt,
437                   &dest_val)))
438         goto error;
439       gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val);
440       break;
441     }
442     default:
443       res = FALSE;
444       break;
445   }
446
447 error:
448   gst_object_unref (peerpad);
449   gst_object_unref (speexenc);
450   return res;
451 }
452
453 static gboolean
454 gst_speexenc_sink_query (GstPad * pad, GstQuery * query)
455 {
456   gboolean res = TRUE;
457   GstSpeexEnc *speexenc;
458
459   speexenc = GST_SPEEXENC (GST_PAD_PARENT (pad));
460
461   switch (GST_QUERY_TYPE (query)) {
462     case GST_QUERY_CONVERT:
463     {
464       GstFormat src_fmt, dest_fmt;
465       gint64 src_val, dest_val;
466
467       gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, &dest_val);
468       if (!(res =
469               gst_speexenc_convert_sink (pad, src_fmt, src_val, &dest_fmt,
470                   &dest_val)))
471         goto error;
472       gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val);
473       break;
474     }
475     default:
476       res = FALSE;
477       break;
478   }
479
480 error:
481   return res;
482 }
483
484 static void
485 gst_speexenc_init (GstSpeexEnc * speexenc)
486 {
487   speexenc->sinkpad =
488       gst_pad_new_from_template (gst_speexenc_sink_template, "sink");
489   gst_element_add_pad (GST_ELEMENT (speexenc), speexenc->sinkpad);
490   gst_pad_set_event_function (speexenc->sinkpad, gst_speexenc_sinkevent);
491   gst_pad_set_chain_function (speexenc->sinkpad, gst_speexenc_chain);
492   gst_pad_set_setcaps_function (speexenc->sinkpad, gst_speexenc_sink_setcaps);
493   gst_pad_set_query_function (speexenc->sinkpad,
494       GST_DEBUG_FUNCPTR (gst_speexenc_sink_query));
495
496   speexenc->srcpad =
497       gst_pad_new_from_template (gst_speexenc_src_template, "src");
498   gst_pad_set_query_function (speexenc->srcpad,
499       GST_DEBUG_FUNCPTR (gst_speexenc_src_query));
500   gst_pad_set_query_type_function (speexenc->srcpad,
501       GST_DEBUG_FUNCPTR (gst_speexenc_get_query_types));
502   gst_element_add_pad (GST_ELEMENT (speexenc), speexenc->srcpad);
503
504   speexenc->channels = -1;
505   speexenc->rate = -1;
506
507   speexenc->quality = DEFAULT_QUALITY;
508   speexenc->bitrate = DEFAULT_BITRATE;
509   speexenc->vbr = DEFAULT_VBR;
510   speexenc->abr = DEFAULT_ABR;
511   speexenc->vad = DEFAULT_VAD;
512   speexenc->dtx = DEFAULT_DTX;
513   speexenc->complexity = DEFAULT_COMPLEXITY;
514   speexenc->nframes = DEFAULT_NFRAMES;
515
516   speexenc->setup = FALSE;
517   speexenc->header_sent = FALSE;
518
519   speexenc->adapter = gst_adapter_new ();
520 }
521
522
523 /* FIXME: why are we not using the from/to vorbiscomment 
524  * functions that are in -lgsttagedit-0.9 here? */
525
526 static gchar *
527 gst_speexenc_get_tag_value (const GstTagList * list, const gchar * tag,
528     int index)
529 {
530   GType tag_type;
531   gchar *speexvalue = NULL;
532
533   if (tag == NULL)
534     return NULL;
535
536   tag_type = gst_tag_get_type (tag);
537
538   /* get tag name right */
539   if ((strcmp (tag, GST_TAG_TRACK_NUMBER) == 0)
540       || (strcmp (tag, GST_TAG_ALBUM_VOLUME_NUMBER) == 0)
541       || (strcmp (tag, GST_TAG_TRACK_COUNT) == 0)
542       || (strcmp (tag, GST_TAG_ALBUM_VOLUME_COUNT) == 0)) {
543     guint track_no;
544
545     if (gst_tag_list_get_uint_index (list, tag, index, &track_no)) {
546       speexvalue = g_strdup_printf ("%u", track_no);
547     } else {
548       GST_WARNING ("Failed to extract int tag %d for '%s'", index, tag);
549     }
550   } else if (tag_type == GST_TYPE_DATE) {
551     /* FIXME: how are dates represented in speex files? */
552     GDate *date;
553
554     if (gst_tag_list_get_date_index (list, tag, index, &date)) {
555       speexvalue =
556           g_strdup_printf ("%04d-%02d-%02d", (gint) g_date_get_year (date),
557           (gint) g_date_get_month (date), (gint) g_date_get_day (date));
558       g_date_free (date);
559     } else {
560       GST_WARNING ("Failed to extract date tag %d for '%s'", index, tag);
561     }
562   } else if (tag_type == G_TYPE_STRING) {
563     if (!gst_tag_list_get_string_index (list, tag, index, &speexvalue))
564       GST_WARNING ("Failed to extract string tag %d for '%s'", index, tag);
565   }
566
567   return speexvalue;
568 }
569
570 /*
571  *  Comments will be stored in the Vorbis style.
572  *  It is describled in the "Structure" section of
573  *  http://www.xiph.org/ogg/vorbis/doc/v-comment.html
574  *
575  *  The comment header is decoded as follows:
576  *  1) [vendor_length] = read an unsigned integer of 32 bits
577  *  2) [vendor_string] = read a UTF-8 vector as [vendor_length] octets
578  *  3) [user_comment_list_length] = read an unsigned integer of 32 bits
579  *  4) iterate [user_comment_list_length] times {
580  *     5) [length] = read an unsigned integer of 32 bits
581  *     6) this iteration's user comment = read a UTF-8 vector as [length] octets
582  *     }
583  *  7) [framing_bit] = read a single bit as boolean
584  *  8) if ( [framing_bit]  unset or end of packet ) then ERROR
585  *  9) done.
586  *
587  *  If you have troubles, please write to ymnk@jcraft.com.
588  */
589 static void
590 comment_init (guint8 ** comments, int *length, char *vendor_string)
591 {
592   int vendor_length = strlen (vendor_string);
593   int user_comment_list_length = 0;
594   int len = 4 + vendor_length + 4;
595   guint8 *p = g_malloc (len);
596
597   GST_WRITE_UINT32_LE (p, vendor_length);
598   memcpy (p + 4, vendor_string, vendor_length);
599   GST_WRITE_UINT32_LE (p + 4 + vendor_length, user_comment_list_length);
600   *length = len;
601   *comments = p;
602 }
603 static void
604 comment_add (guint8 ** comments, int *length, const char *tag, char *val)
605 {
606   guint8 *p = *comments;
607   int vendor_length = GST_READ_UINT32_LE (p);
608   int user_comment_list_length = GST_READ_UINT32_LE (p + 4 + vendor_length);
609   int tag_len = (tag ? strlen (tag) : 0);
610   int val_len = strlen (val);
611   int len = (*length) + 4 + tag_len + val_len;
612
613   p = g_realloc (p, len);
614
615   GST_WRITE_UINT32_LE (p + *length, tag_len + val_len); /* length of comment */
616   if (tag)
617     memcpy (p + *length + 4, (guint8 *) tag, tag_len);  /* comment */
618   memcpy (p + *length + 4 + tag_len, val, val_len);     /* comment */
619   GST_WRITE_UINT32_LE (p + 4 + vendor_length, user_comment_list_length + 1);
620
621   *comments = p;
622   *length = len;
623 }
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_tag_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_tag_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
817 /* push out the buffer and do internal bookkeeping */
818 static GstFlowReturn
819 gst_speexenc_push_buffer (GstSpeexEnc * speexenc, GstBuffer * buffer)
820 {
821   speexenc->bytes_out += GST_BUFFER_SIZE (buffer);
822
823   return gst_pad_push (speexenc->srcpad, buffer);
824
825 }
826
827 static GstCaps *
828 gst_speexenc_set_header_on_caps (GstCaps * caps, GstBuffer * buf1,
829     GstBuffer * buf2)
830 {
831   caps = gst_caps_make_writable (caps);
832   GstStructure *structure = gst_caps_get_structure (caps, 0);
833   GValue list = { 0 };
834   GValue value = { 0 };
835
836   /* mark buffers */
837   GST_BUFFER_FLAG_SET (buf1, GST_BUFFER_FLAG_IN_CAPS);
838   GST_BUFFER_FLAG_SET (buf2, GST_BUFFER_FLAG_IN_CAPS);
839
840   /* put buffers in a fixed list */
841   g_value_init (&list, GST_TYPE_ARRAY);
842   g_value_init (&value, GST_TYPE_BUFFER);
843   gst_value_set_buffer (&value, buf1);
844   gst_value_list_append_value (&list, &value);
845   g_value_unset (&value);
846   g_value_init (&value, GST_TYPE_BUFFER);
847   gst_value_set_buffer (&value, buf2);
848   gst_value_list_append_value (&list, &value);
849   gst_structure_set_value (structure, "streamheader", &list);
850   g_value_unset (&value);
851   g_value_unset (&list);
852
853   return caps;
854 }
855
856
857 static gboolean
858 gst_speexenc_sinkevent (GstPad * pad, GstEvent * event)
859 {
860   gboolean res = TRUE;
861   GstSpeexEnc *speexenc;
862
863   speexenc = GST_SPEEXENC (GST_PAD_PARENT (pad));
864
865   switch (GST_EVENT_TYPE (event)) {
866     case GST_EVENT_EOS:
867       speexenc->eos = TRUE;
868       res = gst_pad_event_default (pad, event);
869       break;
870     case GST_EVENT_TAG:
871     {
872       GstTagList *list;
873
874       gst_event_parse_tag (event, &list);
875       if (speexenc->tags) {
876         gst_tag_list_insert (speexenc->tags, list,
877             gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (speexenc)));
878       } else {
879         g_assert_not_reached ();
880       }
881       res = gst_pad_event_default (pad, event);
882       break;
883     }
884     default:
885       res = gst_pad_event_default (pad, event);
886       break;
887   }
888   return res;
889 }
890
891
892 static GstFlowReturn
893 gst_speexenc_chain (GstPad * pad, GstBuffer * buf)
894 {
895   GstSpeexEnc *speexenc;
896   GstFlowReturn ret = GST_FLOW_OK;
897
898   speexenc = GST_SPEEXENC (gst_pad_get_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     ret = GST_FLOW_UNEXPECTED;
905     goto error;
906   }
907
908   if (!speexenc->header_sent) {
909     /* Speex streams begin with two headers; the initial header (with
910        most of the codec setup parameters) which is mandated by the Ogg
911        bitstream spec.  The second header holds any comment fields.
912        We merely need to make the headers, then pass them to libspeex 
913        one at a time; libspeex handles the additional Ogg bitstream 
914        constraints */
915     GstBuffer *buf1, *buf2;
916     GstCaps *caps;
917     guchar *data;
918     gint data_len;
919
920     gst_speexenc_set_metadata (speexenc);
921
922     /* create header buffer */
923     data = (guint8 *) speex_header_to_packet (&speexenc->header, &data_len);
924     buf1 = gst_speexenc_buffer_from_data (speexenc, data, data_len, 0);
925
926     /* create comment buffer */
927     buf2 =
928         gst_speexenc_buffer_from_data (speexenc, speexenc->comments,
929         speexenc->comment_len, 0);
930
931     /* mark and put on caps */
932     caps = gst_pad_get_caps (speexenc->srcpad);
933     caps = gst_speexenc_set_header_on_caps (caps, buf1, buf2);
934
935     /* negotiate with these caps */
936     GST_DEBUG ("here are the caps: %" GST_PTR_FORMAT, caps);
937     gst_pad_set_caps (speexenc->srcpad, caps);
938
939     gst_buffer_set_caps (buf1, caps);
940     gst_buffer_set_caps (buf2, caps);
941
942     /* push out buffers */
943     ret = gst_speexenc_push_buffer (speexenc, buf1);
944
945     if ((GST_FLOW_OK != ret) && (GST_FLOW_NOT_LINKED != ret)) {
946       gst_buffer_unref (buf1);
947       goto error;
948     }
949
950     ret = gst_speexenc_push_buffer (speexenc, buf2);
951
952     if ((GST_FLOW_OK != ret) && (GST_FLOW_NOT_LINKED != ret)) {
953
954       gst_buffer_unref (buf2);
955       goto error;
956     }
957
958     speex_bits_init (&speexenc->bits);
959     speex_bits_reset (&speexenc->bits);
960
961     speexenc->header_sent = TRUE;
962   }
963
964   {
965     gint frame_size = speexenc->frame_size;
966     gint bytes = frame_size * 2 * speexenc->channels;
967
968     /* push buffer to adapter */
969     gst_adapter_push (speexenc->adapter, buf);
970
971     while (gst_adapter_available (speexenc->adapter) >= bytes) {
972       gint16 *data;
973       gint i;
974       gint outsize, written;
975       GstBuffer *outbuf;
976
977       data = (gint16 *) gst_adapter_peek (speexenc->adapter, bytes);
978
979       for (i = 0; i < frame_size * speexenc->channels; i++) {
980         speexenc->input[i] = (gfloat) data[i];
981       }
982       gst_adapter_flush (speexenc->adapter, bytes);
983
984       speexenc->samples_in += frame_size;
985
986       if (speexenc->channels == 2) {
987         speex_encode_stereo (speexenc->input, frame_size, &speexenc->bits);
988       }
989       speex_encode (speexenc->state, speexenc->input, &speexenc->bits);
990
991       speexenc->frameno++;
992
993       if ((speexenc->frameno % speexenc->nframes) != 0)
994         continue;
995
996       speex_bits_insert_terminator (&speexenc->bits);
997       outsize = speex_bits_nbytes (&speexenc->bits);
998
999       ret = gst_pad_alloc_buffer (speexenc->srcpad,
1000           GST_BUFFER_OFFSET_NONE, outsize, GST_PAD_CAPS (speexenc->srcpad),
1001           &outbuf);
1002
1003       if ((GST_FLOW_OK != ret)) {
1004         goto error;
1005       }
1006
1007       written = speex_bits_write (&speexenc->bits,
1008           (gchar *) GST_BUFFER_DATA (outbuf), outsize);
1009       g_assert (written == outsize);
1010       speex_bits_reset (&speexenc->bits);
1011
1012       GST_BUFFER_TIMESTAMP (outbuf) =
1013           (speexenc->frameno * frame_size -
1014           speexenc->lookahead) * GST_SECOND / speexenc->rate;
1015       GST_BUFFER_DURATION (outbuf) = frame_size * GST_SECOND / speexenc->rate;
1016       GST_BUFFER_OFFSET (outbuf) = speexenc->bytes_out;
1017       GST_BUFFER_OFFSET_END (outbuf) =
1018           speexenc->frameno * frame_size - speexenc->lookahead;
1019
1020       ret = gst_speexenc_push_buffer (speexenc, outbuf);
1021
1022       if ((GST_FLOW_OK != ret) && (GST_FLOW_NOT_LINKED != ret)) {
1023         gst_buffer_unref (outbuf);
1024         goto error;
1025       }
1026     }
1027   }
1028
1029 error:
1030
1031   gst_object_unref (speexenc);
1032   return ret;
1033 }
1034
1035
1036 static void
1037 gst_speexenc_get_property (GObject * object, guint prop_id, GValue * value,
1038     GParamSpec * pspec)
1039 {
1040   GstSpeexEnc *speexenc;
1041
1042   g_return_if_fail (GST_IS_SPEEXENC (object));
1043
1044   speexenc = GST_SPEEXENC (object);
1045
1046   switch (prop_id) {
1047     case ARG_QUALITY:
1048       g_value_set_float (value, speexenc->quality);
1049       break;
1050     case ARG_BITRATE:
1051       g_value_set_int (value, speexenc->bitrate);
1052       break;
1053     case ARG_VBR:
1054       g_value_set_boolean (value, speexenc->vbr);
1055       break;
1056     case ARG_ABR:
1057       g_value_set_int (value, speexenc->abr);
1058       break;
1059     case ARG_VAD:
1060       g_value_set_boolean (value, speexenc->vad);
1061       break;
1062     case ARG_DTX:
1063       g_value_set_boolean (value, speexenc->dtx);
1064       break;
1065     case ARG_COMPLEXITY:
1066       g_value_set_int (value, speexenc->complexity);
1067       break;
1068     case ARG_NFRAMES:
1069       g_value_set_int (value, speexenc->nframes);
1070       break;
1071     case ARG_LAST_MESSAGE:
1072       g_value_set_string (value, speexenc->last_message);
1073       break;
1074     default:
1075       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1076       break;
1077   }
1078 }
1079
1080 static void
1081 gst_speexenc_set_property (GObject * object, guint prop_id,
1082     const GValue * value, GParamSpec * pspec)
1083 {
1084   GstSpeexEnc *speexenc;
1085
1086   g_return_if_fail (GST_IS_SPEEXENC (object));
1087
1088   speexenc = GST_SPEEXENC (object);
1089
1090   switch (prop_id) {
1091     case ARG_QUALITY:
1092       speexenc->quality = g_value_get_float (value);
1093       break;
1094     case ARG_BITRATE:
1095       speexenc->bitrate = g_value_get_int (value);
1096       break;
1097     case ARG_VBR:
1098       speexenc->vbr = g_value_get_boolean (value);
1099       break;
1100     case ARG_ABR:
1101       speexenc->abr = g_value_get_int (value);
1102       break;
1103     case ARG_VAD:
1104       speexenc->vad = g_value_get_boolean (value);
1105       break;
1106     case ARG_DTX:
1107       speexenc->dtx = g_value_get_boolean (value);
1108       break;
1109     case ARG_COMPLEXITY:
1110       speexenc->complexity = g_value_get_int (value);
1111       break;
1112     case ARG_NFRAMES:
1113       speexenc->nframes = g_value_get_int (value);
1114       break;
1115     default:
1116       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1117       break;
1118   }
1119 }
1120
1121 static GstStateChangeReturn
1122 gst_speexenc_change_state (GstElement * element, GstStateChange transition)
1123 {
1124   GstSpeexEnc *speexenc = GST_SPEEXENC (element);
1125   GstStateChangeReturn res;
1126
1127   switch (transition) {
1128     case GST_STATE_CHANGE_NULL_TO_READY:
1129       speexenc->tags = gst_tag_list_new ();
1130       break;
1131     case GST_STATE_CHANGE_READY_TO_PAUSED:
1132       speexenc->frameno = 0;
1133       speexenc->samples_in = 0;
1134       break;
1135     case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
1136       /* fall through */
1137     default:
1138       break;
1139   }
1140
1141   res = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1142
1143   switch (transition) {
1144     case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
1145       break;
1146     case GST_STATE_CHANGE_PAUSED_TO_READY:
1147       speexenc->setup = FALSE;
1148       speexenc->header_sent = FALSE;
1149       break;
1150     case GST_STATE_CHANGE_READY_TO_NULL:
1151       gst_tag_list_free (speexenc->tags);
1152       speexenc->tags = NULL;
1153     default:
1154       break;
1155   }
1156
1157   return res;
1158 }