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