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