ext/speex/gstspeexenc.c: Fix handling of GST_TAG_DATE, which is now of GST_TYPE_DATE...
[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 /* FIXME: why are we not using the from/to vorbiscomment 
518  * functions that are in -lgsttagedit-0.9 here? */
519
520 static gchar *
521 gst_speexenc_get_tag_value (const GstTagList * list, const gchar * tag,
522     int index)
523 {
524   GType tag_type;
525   gchar *speexvalue = NULL;
526
527   if (tag == NULL)
528     return NULL;
529
530   tag_type = gst_tag_get_type (tag);
531
532   /* get tag name right */
533   if ((strcmp (tag, GST_TAG_TRACK_NUMBER) == 0)
534       || (strcmp (tag, GST_TAG_ALBUM_VOLUME_NUMBER) == 0)
535       || (strcmp (tag, GST_TAG_TRACK_COUNT) == 0)
536       || (strcmp (tag, GST_TAG_ALBUM_VOLUME_COUNT) == 0)) {
537     guint track_no;
538
539     if (gst_tag_list_get_uint_index (list, tag, index, &track_no)) {
540       speexvalue = g_strdup_printf ("%u", track_no);
541     } else {
542       GST_WARNING ("Failed to extract int tag %d for '%s'", index, tag);
543     }
544   } else if (tag_type == GST_TYPE_DATE) {
545     /* FIXME: how are dates represented in speex files? */
546     GDate *date;
547
548     if (gst_tag_list_get_date_index (list, tag, index, &date)) {
549       speexvalue =
550           g_strdup_printf ("%04d-%02d-%02d", (gint) g_date_get_year (date),
551           (gint) g_date_get_month (date), (gint) g_date_get_day (date));
552       g_date_free (date);
553     } else {
554       GST_WARNING ("Failed to extract date tag %d for '%s'", index, tag);
555     }
556   } else if (tag_type == G_TYPE_STRING) {
557     if (!gst_tag_list_get_string_index (list, tag, index, &speexvalue))
558       GST_WARNING ("Failed to extract string tag %d for '%s'", index, tag);
559   }
560
561   return speexvalue;
562 }
563
564 /*
565  *  Comments will be stored in the Vorbis style.
566  *  It is describled in the "Structure" section of
567  *  http://www.xiph.org/ogg/vorbis/doc/v-comment.html
568  *
569  *  The comment header is decoded as follows:
570  *  1) [vendor_length] = read an unsigned integer of 32 bits
571  *  2) [vendor_string] = read a UTF-8 vector as [vendor_length] octets
572  *  3) [user_comment_list_length] = read an unsigned integer of 32 bits
573  *  4) iterate [user_comment_list_length] times {
574  *     5) [length] = read an unsigned integer of 32 bits
575  *     6) this iteration's user comment = read a UTF-8 vector as [length] octets
576  *     }
577  *  7) [framing_bit] = read a single bit as boolean
578  *  8) if ( [framing_bit]  unset or end of packet ) then ERROR
579  *  9) done.
580  *
581  *  If you have troubles, please write to ymnk@jcraft.com.
582  */
583 static void
584 comment_init (guint8 ** comments, int *length, char *vendor_string)
585 {
586   int vendor_length = strlen (vendor_string);
587   int user_comment_list_length = 0;
588   int len = 4 + vendor_length + 4;
589   guint8 *p = g_malloc (len);
590
591   GST_WRITE_UINT32_LE (p, vendor_length);
592   memcpy (p + 4, vendor_string, vendor_length);
593   GST_WRITE_UINT32_LE (p + 4 + vendor_length, user_comment_list_length);
594   *length = len;
595   *comments = p;
596 }
597 static void
598 comment_add (guint8 ** comments, int *length, const char *tag, char *val)
599 {
600   guint8 *p = *comments;
601   int vendor_length = GST_READ_UINT32_LE (p);
602   int user_comment_list_length = GST_READ_UINT32_LE (p + 4 + vendor_length);
603   int tag_len = (tag ? strlen (tag) : 0);
604   int val_len = strlen (val);
605   int len = (*length) + 4 + tag_len + val_len;
606
607   p = g_realloc (p, len);
608
609   GST_WRITE_UINT32_LE (p + *length, tag_len + val_len); /* length of comment */
610   if (tag)
611     memcpy (p + *length + 4, (guint8 *) tag, tag_len);  /* comment */
612   memcpy (p + *length + 4 + tag_len, val, val_len);     /* comment */
613   GST_WRITE_UINT32_LE (p + 4 + vendor_length, user_comment_list_length + 1);
614
615   *comments = p;
616   *length = len;
617 }
618
619 static void
620 gst_speexenc_metadata_set1 (const GstTagList * list, const gchar * tag,
621     gpointer speexenc)
622 {
623   const gchar *speextag = NULL;
624   gchar *speexvalue = NULL;
625   guint i, count;
626   GstSpeexEnc *enc = GST_SPEEXENC (speexenc);
627
628   speextag = gst_tag_to_vorbis_tag (tag);
629   if (speextag == NULL) {
630     return;
631   }
632
633   count = gst_tag_list_get_tag_size (list, tag);
634   for (i = 0; i < count; i++) {
635     speexvalue = gst_speexenc_get_tag_value (list, tag, i);
636
637     if (speexvalue != NULL) {
638       comment_add (&enc->comments, &enc->comment_len, speextag, speexvalue);
639     }
640   }
641 }
642
643 static void
644 gst_speexenc_set_metadata (GstSpeexEnc * speexenc)
645 {
646   GstTagList *copy;
647   const GstTagList *user_tags;
648
649   user_tags = gst_tag_setter_get_list (GST_TAG_SETTER (speexenc));
650   if (!(speexenc->tags || user_tags))
651     return;
652
653   comment_init (&speexenc->comments, &speexenc->comment_len,
654       "Encoded with GStreamer Speexenc");
655   copy =
656       gst_tag_list_merge (user_tags, speexenc->tags,
657       gst_tag_setter_get_merge_mode (GST_TAG_SETTER (speexenc)));
658   gst_tag_list_foreach (copy, gst_speexenc_metadata_set1, speexenc);
659   gst_tag_list_free (copy);
660 }
661
662 static gboolean
663 gst_speexenc_setup (GstSpeexEnc * speexenc)
664 {
665   speexenc->setup = FALSE;
666
667   switch (speexenc->mode) {
668     case GST_SPEEXENC_MODE_UWB:
669       speexenc->speex_mode = (SpeexMode *) & speex_uwb_mode;
670       break;
671     case GST_SPEEXENC_MODE_WB:
672       speexenc->speex_mode = (SpeexMode *) & speex_wb_mode;
673       break;
674     case GST_SPEEXENC_MODE_NB:
675       speexenc->speex_mode = (SpeexMode *) & speex_nb_mode;
676       break;
677     case GST_SPEEXENC_MODE_AUTO:
678       /* fall through */
679     default:
680       break;
681   }
682
683   if (speexenc->rate > 25000) {
684     if (speexenc->mode == GST_SPEEXENC_MODE_AUTO) {
685       speexenc->speex_mode = (SpeexMode *) & speex_uwb_mode;
686     } else {
687       if (speexenc->speex_mode != &speex_uwb_mode) {
688         speexenc->last_message =
689             g_strdup_printf
690             ("Warning: suggest to use ultra wide band mode for this rate");
691         g_object_notify (G_OBJECT (speexenc), "last_message");
692       }
693     }
694   } else if (speexenc->rate > 12500) {
695     if (speexenc->mode == GST_SPEEXENC_MODE_AUTO) {
696       speexenc->speex_mode = (SpeexMode *) & speex_wb_mode;
697     } else {
698       if (speexenc->speex_mode != &speex_wb_mode) {
699         speexenc->last_message =
700             g_strdup_printf
701             ("Warning: suggest to use wide band mode for this rate");
702         g_object_notify (G_OBJECT (speexenc), "last_message");
703       }
704     }
705   } else {
706     if (speexenc->mode == GST_SPEEXENC_MODE_AUTO) {
707       speexenc->speex_mode = (SpeexMode *) & speex_nb_mode;
708     } else {
709       if (speexenc->speex_mode != &speex_nb_mode) {
710         speexenc->last_message =
711             g_strdup_printf
712             ("Warning: suggest to use narrow band mode for this rate");
713         g_object_notify (G_OBJECT (speexenc), "last_message");
714       }
715     }
716   }
717
718   if (speexenc->rate != 8000 && speexenc->rate != 16000
719       && speexenc->rate != 32000) {
720     speexenc->last_message =
721         g_strdup_printf ("Warning: speex is optimized for 8, 16 and 32 KHz");
722     g_object_notify (G_OBJECT (speexenc), "last_message");
723   }
724
725   speex_init_header (&speexenc->header, speexenc->rate, 1,
726       speexenc->speex_mode);
727   speexenc->header.frames_per_packet = speexenc->nframes;
728   speexenc->header.vbr = speexenc->vbr;
729   speexenc->header.nb_channels = speexenc->channels;
730
731   /*Initialize Speex encoder */
732   speexenc->state = speex_encoder_init (speexenc->speex_mode);
733
734   speex_encoder_ctl (speexenc->state, SPEEX_GET_FRAME_SIZE,
735       &speexenc->frame_size);
736   speex_encoder_ctl (speexenc->state, SPEEX_SET_COMPLEXITY,
737       &speexenc->complexity);
738   speex_encoder_ctl (speexenc->state, SPEEX_SET_SAMPLING_RATE, &speexenc->rate);
739
740   if (speexenc->vbr)
741     speex_encoder_ctl (speexenc->state, SPEEX_SET_VBR_QUALITY,
742         &speexenc->quality);
743   else {
744     gint tmp = floor (speexenc->quality);
745
746     speex_encoder_ctl (speexenc->state, SPEEX_SET_QUALITY, &tmp);
747   }
748   if (speexenc->bitrate) {
749     if (speexenc->quality >= 0.0 && speexenc->vbr) {
750       speexenc->last_message =
751           g_strdup_printf ("Warning: bitrate option is overriding quality");
752       g_object_notify (G_OBJECT (speexenc), "last_message");
753     }
754     speex_encoder_ctl (speexenc->state, SPEEX_SET_BITRATE, &speexenc->bitrate);
755   }
756   if (speexenc->vbr) {
757     gint tmp = 1;
758
759     speex_encoder_ctl (speexenc->state, SPEEX_SET_VBR, &tmp);
760   } else if (speexenc->vad) {
761     gint tmp = 1;
762
763     speex_encoder_ctl (speexenc->state, SPEEX_SET_VAD, &tmp);
764   }
765
766   if (speexenc->dtx) {
767     gint tmp = 1;
768
769     speex_encoder_ctl (speexenc->state, SPEEX_SET_DTX, &tmp);
770   }
771
772   if (speexenc->dtx && !(speexenc->vbr || speexenc->abr || speexenc->vad)) {
773     speexenc->last_message =
774         g_strdup_printf ("Warning: dtx is useless without vad, vbr or abr");
775     g_object_notify (G_OBJECT (speexenc), "last_message");
776   } else if ((speexenc->vbr || speexenc->abr) && (speexenc->vad)) {
777     speexenc->last_message =
778         g_strdup_printf ("Warning: vad is already implied by vbr or abr");
779     g_object_notify (G_OBJECT (speexenc), "last_message");
780   }
781
782   if (speexenc->abr) {
783     speex_encoder_ctl (speexenc->state, SPEEX_SET_ABR, &speexenc->abr);
784   }
785
786   speex_encoder_ctl (speexenc->state, SPEEX_GET_LOOKAHEAD,
787       &speexenc->lookahead);
788
789   speexenc->setup = TRUE;
790
791   return TRUE;
792 }
793
794 /* prepare a buffer for transmission */
795 static GstBuffer *
796 gst_speexenc_buffer_from_data (GstSpeexEnc * speexenc, guchar * data,
797     gint data_len, guint64 granulepos)
798 {
799   GstBuffer *outbuf;
800
801   outbuf = gst_buffer_new_and_alloc (data_len);
802   memcpy (GST_BUFFER_DATA (outbuf), data, data_len);
803   GST_BUFFER_OFFSET (outbuf) = speexenc->bytes_out;
804   GST_BUFFER_OFFSET_END (outbuf) = granulepos;
805
806   GST_DEBUG ("encoded buffer of %d bytes", GST_BUFFER_SIZE (outbuf));
807   return outbuf;
808 }
809
810 /* push out the buffer and do internal bookkeeping */
811 static void
812 gst_speexenc_push_buffer (GstSpeexEnc * speexenc, GstBuffer * buffer)
813 {
814   speexenc->bytes_out += GST_BUFFER_SIZE (buffer);
815
816   if (GST_PAD_IS_USABLE (speexenc->srcpad)) {
817     gst_pad_push (speexenc->srcpad, buffer);
818   } else {
819     gst_buffer_unref (buffer);
820   }
821 }
822
823 static GstCaps *
824 gst_speexenc_set_header_on_caps (GstCaps * caps, GstBuffer * buf1,
825     GstBuffer * buf2)
826 {
827   caps = gst_caps_make_writable (caps);
828   GstStructure *structure = gst_caps_get_structure (caps, 0);
829   GValue list = { 0 };
830   GValue value = { 0 };
831
832   /* mark buffers */
833   GST_BUFFER_FLAG_SET (buf1, GST_BUFFER_FLAG_IN_CAPS);
834   GST_BUFFER_FLAG_SET (buf2, GST_BUFFER_FLAG_IN_CAPS);
835
836   /* put buffers in a fixed list */
837   g_value_init (&list, GST_TYPE_ARRAY);
838   g_value_init (&value, GST_TYPE_BUFFER);
839   gst_value_set_buffer (&value, buf1);
840   gst_value_list_append_value (&list, &value);
841   g_value_unset (&value);
842   g_value_init (&value, GST_TYPE_BUFFER);
843   gst_value_set_buffer (&value, buf2);
844   gst_value_list_append_value (&list, &value);
845   gst_structure_set_value (structure, "streamheader", &list);
846   g_value_unset (&value);
847   g_value_unset (&list);
848
849   return caps;
850 }
851
852
853 static gboolean
854 gst_speexenc_sinkevent (GstPad * pad, GstEvent * event)
855 {
856   gboolean res = TRUE;
857   GstSpeexEnc *speexenc;
858
859   speexenc = GST_SPEEXENC (GST_PAD_PARENT (pad));
860
861   switch (GST_EVENT_TYPE (event)) {
862     case GST_EVENT_EOS:
863       speexenc->eos = TRUE;
864       res = gst_pad_event_default (pad, event);
865       break;
866     case GST_EVENT_TAG:
867     {
868       GstTagList *list;
869
870       gst_event_parse_tag (event, &list);
871       if (speexenc->tags) {
872         gst_tag_list_insert (speexenc->tags, list,
873             gst_tag_setter_get_merge_mode (GST_TAG_SETTER (speexenc)));
874       } else {
875         g_assert_not_reached ();
876       }
877       res = gst_pad_event_default (pad, event);
878       break;
879     }
880     default:
881       res = gst_pad_event_default (pad, event);
882       break;
883   }
884   return res;
885 }
886
887 static GstFlowReturn
888 gst_speexenc_chain (GstPad * pad, GstBuffer * buf)
889 {
890   GstSpeexEnc *speexenc;
891
892   speexenc = GST_SPEEXENC (GST_PAD_PARENT (pad));
893
894   if (!speexenc->setup) {
895     gst_buffer_unref (buf);
896     GST_ELEMENT_ERROR (speexenc, CORE, NEGOTIATION, (NULL),
897         ("encoder not initialized (input is not audio?)"));
898     return GST_FLOW_UNEXPECTED;
899   }
900
901   if (!speexenc->header_sent) {
902     /* Speex streams begin with two headers; the initial header (with
903        most of the codec setup parameters) which is mandated by the Ogg
904        bitstream spec.  The second header holds any comment fields.
905        We merely need to make the headers, then pass them to libspeex 
906        one at a time; libspeex handles the additional Ogg bitstream 
907        constraints */
908     GstBuffer *buf1, *buf2;
909     GstCaps *caps;
910     guchar *data;
911     gint data_len;
912
913     gst_speexenc_set_metadata (speexenc);
914
915     /* create header buffer */
916     data = (guint8 *) speex_header_to_packet (&speexenc->header, &data_len);
917     buf1 = gst_speexenc_buffer_from_data (speexenc, data, data_len, 0);
918
919     /* create comment buffer */
920     buf2 =
921         gst_speexenc_buffer_from_data (speexenc, speexenc->comments,
922         speexenc->comment_len, 0);
923
924     /* mark and put on caps */
925     caps = gst_pad_get_caps (speexenc->srcpad);
926     caps = gst_speexenc_set_header_on_caps (caps, buf1, buf2);
927
928     /* negotiate with these caps */
929     GST_DEBUG ("here are the caps: %" GST_PTR_FORMAT, caps);
930     gst_pad_set_caps (speexenc->srcpad, caps);
931
932     gst_buffer_set_caps (buf1, caps);
933     gst_buffer_set_caps (buf2, caps);
934
935     /* push out buffers */
936     gst_speexenc_push_buffer (speexenc, buf1);
937     gst_speexenc_push_buffer (speexenc, buf2);
938
939     speex_bits_init (&speexenc->bits);
940     speex_bits_reset (&speexenc->bits);
941
942     speexenc->header_sent = TRUE;
943   }
944
945   {
946     gint frame_size = speexenc->frame_size;
947     gint bytes = frame_size * 2 * speexenc->channels;
948
949     /* push buffer to adapter */
950     gst_adapter_push (speexenc->adapter, buf);
951
952     while (gst_adapter_available (speexenc->adapter) >= bytes) {
953       gint16 *data;
954       gint i;
955       gint outsize, written;
956       GstBuffer *outbuf;
957
958       data = (gint16 *) gst_adapter_peek (speexenc->adapter, bytes);
959
960       for (i = 0; i < frame_size * speexenc->channels; i++) {
961         speexenc->input[i] = (gfloat) data[i];
962       }
963       gst_adapter_flush (speexenc->adapter, bytes);
964
965       speexenc->samples_in += frame_size;
966
967       if (speexenc->channels == 2) {
968         speex_encode_stereo (speexenc->input, frame_size, &speexenc->bits);
969       }
970       speex_encode (speexenc->state, speexenc->input, &speexenc->bits);
971
972       speexenc->frameno++;
973
974       if ((speexenc->frameno % speexenc->nframes) != 0)
975         continue;
976
977       speex_bits_insert_terminator (&speexenc->bits);
978       outsize = speex_bits_nbytes (&speexenc->bits);
979
980       gst_pad_alloc_buffer (speexenc->srcpad,
981           GST_BUFFER_OFFSET_NONE, outsize, GST_PAD_CAPS (speexenc->srcpad),
982           &outbuf);
983
984       written = speex_bits_write (&speexenc->bits,
985           (gchar *) GST_BUFFER_DATA (outbuf), outsize);
986       g_assert (written == outsize);
987       speex_bits_reset (&speexenc->bits);
988
989       GST_BUFFER_TIMESTAMP (outbuf) =
990           (speexenc->frameno * frame_size -
991           speexenc->lookahead) * GST_SECOND / speexenc->rate;
992       GST_BUFFER_DURATION (outbuf) = frame_size * GST_SECOND / speexenc->rate;
993       GST_BUFFER_OFFSET (outbuf) = speexenc->bytes_out;
994       GST_BUFFER_OFFSET_END (outbuf) =
995           speexenc->frameno * frame_size - speexenc->lookahead;
996
997       gst_speexenc_push_buffer (speexenc, outbuf);
998     }
999   }
1000
1001   return GST_FLOW_OK;
1002 }
1003
1004 static void
1005 gst_speexenc_get_property (GObject * object, guint prop_id, GValue * value,
1006     GParamSpec * pspec)
1007 {
1008   GstSpeexEnc *speexenc;
1009
1010   g_return_if_fail (GST_IS_SPEEXENC (object));
1011
1012   speexenc = GST_SPEEXENC (object);
1013
1014   switch (prop_id) {
1015     case ARG_QUALITY:
1016       g_value_set_float (value, speexenc->quality);
1017       break;
1018     case ARG_BITRATE:
1019       g_value_set_int (value, speexenc->bitrate);
1020       break;
1021     case ARG_VBR:
1022       g_value_set_boolean (value, speexenc->vbr);
1023       break;
1024     case ARG_ABR:
1025       g_value_set_int (value, speexenc->abr);
1026       break;
1027     case ARG_VAD:
1028       g_value_set_boolean (value, speexenc->vad);
1029       break;
1030     case ARG_DTX:
1031       g_value_set_boolean (value, speexenc->dtx);
1032       break;
1033     case ARG_COMPLEXITY:
1034       g_value_set_int (value, speexenc->complexity);
1035       break;
1036     case ARG_NFRAMES:
1037       g_value_set_int (value, speexenc->nframes);
1038       break;
1039     case ARG_LAST_MESSAGE:
1040       g_value_set_string (value, speexenc->last_message);
1041       break;
1042     default:
1043       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1044       break;
1045   }
1046 }
1047
1048 static void
1049 gst_speexenc_set_property (GObject * object, guint prop_id,
1050     const GValue * value, GParamSpec * pspec)
1051 {
1052   GstSpeexEnc *speexenc;
1053
1054   g_return_if_fail (GST_IS_SPEEXENC (object));
1055
1056   speexenc = GST_SPEEXENC (object);
1057
1058   switch (prop_id) {
1059     case ARG_QUALITY:
1060       speexenc->quality = g_value_get_float (value);
1061       break;
1062     case ARG_BITRATE:
1063       speexenc->bitrate = g_value_get_int (value);
1064       break;
1065     case ARG_VBR:
1066       speexenc->vbr = g_value_get_boolean (value);
1067       break;
1068     case ARG_ABR:
1069       speexenc->abr = g_value_get_int (value);
1070       break;
1071     case ARG_VAD:
1072       speexenc->vad = g_value_get_boolean (value);
1073       break;
1074     case ARG_DTX:
1075       speexenc->dtx = g_value_get_boolean (value);
1076       break;
1077     case ARG_COMPLEXITY:
1078       speexenc->complexity = g_value_get_int (value);
1079       break;
1080     case ARG_NFRAMES:
1081       speexenc->nframes = g_value_get_int (value);
1082       break;
1083     default:
1084       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1085       break;
1086   }
1087 }
1088
1089 static GstStateChangeReturn
1090 gst_speexenc_change_state (GstElement * element, GstStateChange transition)
1091 {
1092   GstSpeexEnc *speexenc = GST_SPEEXENC (element);
1093   GstStateChangeReturn res;
1094
1095   switch (transition) {
1096     case GST_STATE_CHANGE_NULL_TO_READY:
1097       speexenc->tags = gst_tag_list_new ();
1098       break;
1099     case GST_STATE_CHANGE_READY_TO_PAUSED:
1100       speexenc->frameno = 0;
1101       speexenc->samples_in = 0;
1102       break;
1103     case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
1104       /* fall through */
1105     default:
1106       break;
1107   }
1108
1109   res = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1110
1111   switch (transition) {
1112     case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
1113       break;
1114     case GST_STATE_CHANGE_PAUSED_TO_READY:
1115       speexenc->setup = FALSE;
1116       speexenc->header_sent = FALSE;
1117       break;
1118     case GST_STATE_CHANGE_READY_TO_NULL:
1119       gst_tag_list_free (speexenc->tags);
1120       speexenc->tags = NULL;
1121     default:
1122       break;
1123   }
1124
1125   return res;
1126 }