speex: Implement preset interface
[platform/upstream/gst-plugins-good.git] / ext / speex / gstspeexenc.c
1 /* GStreamer Speex Encoder
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  * SECTION:element-speexenc
22  * @see_also: speexdec, oggmux
23  *
24  * This element encodes audio as a Speex stream.
25  * <ulink url="http://www.speex.org/">Speex</ulink> is a royalty-free
26  * audio codec maintained by the <ulink url="http://www.xiph.org/">Xiph.org
27  * Foundation</ulink>.
28  *
29  * <refsect2>
30  * <title>Example pipelines</title>
31  * |[
32  * gst-launch audiotestsrc num-buffers=100 ! speexenc ! oggmux ! filesink location=beep.ogg
33  * ]| Encode an Ogg/Speex file.
34  * </refsect2>
35  */
36
37 #ifdef HAVE_CONFIG_H
38 #include "config.h"
39 #endif
40 #include <stdlib.h>
41 #include <string.h>
42 #include <time.h>
43 #include <math.h>
44 #include <speex/speex.h>
45 #include <speex/speex_stereo.h>
46
47 #include <gst/gsttagsetter.h>
48 #include <gst/tag/tag.h>
49 #include <gst/audio/audio.h>
50 #include "gstspeexenc.h"
51
52 GST_DEBUG_CATEGORY_STATIC (speexenc_debug);
53 #define GST_CAT_DEFAULT speexenc_debug
54
55 static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
56     GST_PAD_SINK,
57     GST_PAD_ALWAYS,
58     GST_STATIC_CAPS ("audio/x-raw-int, "
59         "rate = (int) [ 6000, 48000 ], "
60         "channels = (int) [ 1, 2 ], "
61         "endianness = (int) BYTE_ORDER, "
62         "signed = (boolean) TRUE, " "width = (int) 16, " "depth = (int) 16")
63     );
64
65 static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
66     GST_PAD_SRC,
67     GST_PAD_ALWAYS,
68     GST_STATIC_CAPS ("audio/x-speex, "
69         "rate = (int) [ 6000, 48000 ], " "channels = (int) [ 1, 2]")
70     );
71
72 static const GstElementDetails speexenc_details =
73 GST_ELEMENT_DETAILS ("Speex audio encoder",
74     "Codec/Encoder/Audio",
75     "Encodes audio in Speex format",
76     "Wim Taymans <wim@fluendo.com>");
77
78 #define DEFAULT_QUALITY         8.0
79 #define DEFAULT_BITRATE         0
80 #define DEFAULT_MODE            GST_SPEEX_ENC_MODE_AUTO
81 #define DEFAULT_VBR             FALSE
82 #define DEFAULT_ABR             0
83 #define DEFAULT_VAD             FALSE
84 #define DEFAULT_DTX             FALSE
85 #define DEFAULT_COMPLEXITY      3
86 #define DEFAULT_NFRAMES         1
87
88 enum
89 {
90   PROP_0,
91   PROP_QUALITY,
92   PROP_BITRATE,
93   PROP_MODE,
94   PROP_VBR,
95   PROP_ABR,
96   PROP_VAD,
97   PROP_DTX,
98   PROP_COMPLEXITY,
99   PROP_NFRAMES,
100   PROP_LAST_MESSAGE
101 };
102
103 #define GST_TYPE_SPEEX_ENC_MODE (gst_speex_enc_mode_get_type())
104 static GType
105 gst_speex_enc_mode_get_type (void)
106 {
107   static GType speex_enc_mode_type = 0;
108   static const GEnumValue speex_enc_modes[] = {
109     {GST_SPEEX_ENC_MODE_AUTO, "Auto", "auto"},
110     {GST_SPEEX_ENC_MODE_UWB, "Ultra Wide Band", "uwb"},
111     {GST_SPEEX_ENC_MODE_WB, "Wide Band", "wb"},
112     {GST_SPEEX_ENC_MODE_NB, "Narrow Band", "nb"},
113     {0, NULL, NULL},
114   };
115   if (G_UNLIKELY (speex_enc_mode_type == 0)) {
116     speex_enc_mode_type = g_enum_register_static ("GstSpeexEncMode",
117         speex_enc_modes);
118   }
119   return speex_enc_mode_type;
120 }
121
122 #if 0
123 static const GstFormat *
124 gst_speex_enc_get_formats (GstPad * pad)
125 {
126   static const GstFormat src_formats[] = {
127     GST_FORMAT_BYTES,
128     GST_FORMAT_TIME,
129     0
130   };
131   static const GstFormat sink_formats[] = {
132     GST_FORMAT_BYTES,
133     GST_FORMAT_DEFAULT,
134     GST_FORMAT_TIME,
135     0
136   };
137
138   return (GST_PAD_IS_SRC (pad) ? src_formats : sink_formats);
139 }
140 #endif
141
142 static void gst_speex_enc_finalize (GObject * object);
143
144 static gboolean gst_speex_enc_sinkevent (GstPad * pad, GstEvent * event);
145 static GstFlowReturn gst_speex_enc_chain (GstPad * pad, GstBuffer * buf);
146 static gboolean gst_speex_enc_setup (GstSpeexEnc * enc);
147
148 static void gst_speex_enc_get_property (GObject * object, guint prop_id,
149     GValue * value, GParamSpec * pspec);
150 static void gst_speex_enc_set_property (GObject * object, guint prop_id,
151     const GValue * value, GParamSpec * pspec);
152 static GstStateChangeReturn gst_speex_enc_change_state (GstElement * element,
153     GstStateChange transition);
154
155 static GstFlowReturn gst_speex_enc_encode (GstSpeexEnc * enc, gboolean flush);
156
157 static void
158 gst_speex_enc_setup_interfaces (GType speexenc_type)
159 {
160   static const GInterfaceInfo tag_setter_info = { NULL, NULL, NULL };
161   const GInterfaceInfo preset_interface_info = {
162     NULL,                       /* interface_init */
163     NULL,                       /* interface_finalize */
164     NULL                        /* interface_data */
165   };
166
167   g_type_add_interface_static (speexenc_type, GST_TYPE_TAG_SETTER,
168       &tag_setter_info);
169   g_type_add_interface_static (speexenc_type, GST_TYPE_PRESET,
170       &preset_interface_info);
171
172   GST_DEBUG_CATEGORY_INIT (speexenc_debug, "speexenc", 0, "Speex encoder");
173 }
174
175 GST_BOILERPLATE_FULL (GstSpeexEnc, gst_speex_enc, GstElement, GST_TYPE_ELEMENT,
176     gst_speex_enc_setup_interfaces);
177
178 static void
179 gst_speex_enc_base_init (gpointer g_class)
180 {
181   GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
182
183   gst_element_class_add_pad_template (element_class,
184       gst_static_pad_template_get (&src_factory));
185   gst_element_class_add_pad_template (element_class,
186       gst_static_pad_template_get (&sink_factory));
187   gst_element_class_set_details (element_class, &speexenc_details);
188 }
189
190 static void
191 gst_speex_enc_class_init (GstSpeexEncClass * klass)
192 {
193   GObjectClass *gobject_class;
194   GstElementClass *gstelement_class;
195
196   gobject_class = (GObjectClass *) klass;
197   gstelement_class = (GstElementClass *) klass;
198
199   gobject_class->set_property = gst_speex_enc_set_property;
200   gobject_class->get_property = gst_speex_enc_get_property;
201
202   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_QUALITY,
203       g_param_spec_float ("quality", "Quality", "Encoding quality",
204           0.0, 10.0, DEFAULT_QUALITY, G_PARAM_READWRITE));
205   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_BITRATE,
206       g_param_spec_int ("bitrate", "Encoding Bit-rate",
207           "Specify an encoding bit-rate (in bps). (0 = automatic)",
208           0, G_MAXINT, DEFAULT_BITRATE, G_PARAM_READWRITE));
209   g_object_class_install_property (gobject_class, PROP_MODE,
210       g_param_spec_enum ("mode", "Mode", "The encoding mode",
211           GST_TYPE_SPEEX_ENC_MODE, GST_SPEEX_ENC_MODE_AUTO,
212           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
213   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_VBR,
214       g_param_spec_boolean ("vbr", "VBR",
215           "Enable variable bit-rate", DEFAULT_VBR, G_PARAM_READWRITE));
216   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_ABR,
217       g_param_spec_int ("abr", "ABR",
218           "Enable average bit-rate (0 = disabled)",
219           0, G_MAXINT, DEFAULT_ABR, G_PARAM_READWRITE));
220   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_VAD,
221       g_param_spec_boolean ("vad", "VAD",
222           "Enable voice activity detection", DEFAULT_VAD, G_PARAM_READWRITE));
223   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_DTX,
224       g_param_spec_boolean ("dtx", "DTX",
225           "Enable discontinuous transmission", DEFAULT_DTX, G_PARAM_READWRITE));
226   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_COMPLEXITY,
227       g_param_spec_int ("complexity", "Complexity",
228           "Set encoding complexity",
229           0, G_MAXINT, DEFAULT_COMPLEXITY, G_PARAM_READWRITE));
230   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_NFRAMES,
231       g_param_spec_int ("nframes", "NFrames",
232           "Number of frames per buffer",
233           0, G_MAXINT, DEFAULT_NFRAMES, G_PARAM_READWRITE));
234   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_LAST_MESSAGE,
235       g_param_spec_string ("last-message", "last-message",
236           "The last status message", NULL, G_PARAM_READABLE));
237
238   gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_speex_enc_finalize);
239
240   gstelement_class->change_state =
241       GST_DEBUG_FUNCPTR (gst_speex_enc_change_state);
242 }
243
244 static void
245 gst_speex_enc_finalize (GObject * object)
246 {
247   GstSpeexEnc *enc;
248
249   enc = GST_SPEEX_ENC (object);
250
251   g_free (enc->last_message);
252   g_object_unref (enc->adapter);
253
254   G_OBJECT_CLASS (parent_class)->finalize (object);
255 }
256
257 static gboolean
258 gst_speex_enc_sink_setcaps (GstPad * pad, GstCaps * caps)
259 {
260   GstSpeexEnc *enc;
261   GstStructure *structure;
262
263   enc = GST_SPEEX_ENC (GST_PAD_PARENT (pad));
264   enc->setup = FALSE;
265
266   structure = gst_caps_get_structure (caps, 0);
267   gst_structure_get_int (structure, "channels", &enc->channels);
268   gst_structure_get_int (structure, "rate", &enc->rate);
269
270   gst_speex_enc_setup (enc);
271
272   return enc->setup;
273 }
274
275
276 static GstCaps *
277 gst_speex_enc_sink_getcaps (GstPad * pad)
278 {
279   GstCaps *caps = gst_caps_copy (gst_pad_get_pad_template_caps (pad));
280   GstCaps *peercaps = NULL;
281   GstSpeexEnc *enc = GST_SPEEX_ENC (gst_pad_get_parent_element (pad));
282
283   peercaps = gst_pad_peer_get_caps (enc->srcpad);
284
285   if (peercaps) {
286     if (!gst_caps_is_empty (peercaps) && !gst_caps_is_any (peercaps)) {
287       GstStructure *ps = gst_caps_get_structure (peercaps, 0);
288       GstStructure *s = gst_caps_get_structure (caps, 0);
289       gint rate, channels;
290
291       if (gst_structure_get_int (ps, "rate", &rate)) {
292         gst_structure_fixate_field_nearest_int (s, "rate", rate);
293       }
294
295       if (gst_structure_get_int (ps, "channels", &channels)) {
296         gst_structure_fixate_field_nearest_int (s, "channels", channels);
297       }
298     }
299     gst_caps_unref (peercaps);
300   }
301
302   gst_object_unref (enc);
303
304   return caps;
305 }
306
307
308 static gboolean
309 gst_speex_enc_convert_src (GstPad * pad, GstFormat src_format, gint64 src_value,
310     GstFormat * dest_format, gint64 * dest_value)
311 {
312   gboolean res = TRUE;
313   GstSpeexEnc *enc;
314   gint64 avg;
315
316   enc = GST_SPEEX_ENC (GST_PAD_PARENT (pad));
317
318   if (enc->samples_in == 0 || enc->bytes_out == 0 || enc->rate == 0)
319     return FALSE;
320
321   avg = (enc->bytes_out * enc->rate) / (enc->samples_in);
322
323   switch (src_format) {
324     case GST_FORMAT_BYTES:
325       switch (*dest_format) {
326         case GST_FORMAT_TIME:
327           *dest_value = src_value * GST_SECOND / avg;
328           break;
329         default:
330           res = FALSE;
331       }
332       break;
333     case GST_FORMAT_TIME:
334       switch (*dest_format) {
335         case GST_FORMAT_BYTES:
336           *dest_value = src_value * avg / GST_SECOND;
337           break;
338         default:
339           res = FALSE;
340       }
341       break;
342     default:
343       res = FALSE;
344   }
345   return res;
346 }
347
348 static gboolean
349 gst_speex_enc_convert_sink (GstPad * pad, GstFormat src_format,
350     gint64 src_value, GstFormat * dest_format, gint64 * dest_value)
351 {
352   gboolean res = TRUE;
353   guint scale = 1;
354   gint bytes_per_sample;
355   GstSpeexEnc *enc;
356
357   enc = GST_SPEEX_ENC (GST_PAD_PARENT (pad));
358
359   bytes_per_sample = enc->channels * 2;
360
361   switch (src_format) {
362     case GST_FORMAT_BYTES:
363       switch (*dest_format) {
364         case GST_FORMAT_DEFAULT:
365           if (bytes_per_sample == 0)
366             return FALSE;
367           *dest_value = src_value / bytes_per_sample;
368           break;
369         case GST_FORMAT_TIME:
370         {
371           gint byterate = bytes_per_sample * enc->rate;
372
373           if (byterate == 0)
374             return FALSE;
375           *dest_value = src_value * GST_SECOND / byterate;
376           break;
377         }
378         default:
379           res = FALSE;
380       }
381       break;
382     case GST_FORMAT_DEFAULT:
383       switch (*dest_format) {
384         case GST_FORMAT_BYTES:
385           *dest_value = src_value * bytes_per_sample;
386           break;
387         case GST_FORMAT_TIME:
388           if (enc->rate == 0)
389             return FALSE;
390           *dest_value = src_value * GST_SECOND / enc->rate;
391           break;
392         default:
393           res = FALSE;
394       }
395       break;
396     case GST_FORMAT_TIME:
397       switch (*dest_format) {
398         case GST_FORMAT_BYTES:
399           scale = bytes_per_sample;
400           /* fallthrough */
401         case GST_FORMAT_DEFAULT:
402           *dest_value = src_value * scale * enc->rate / GST_SECOND;
403           break;
404         default:
405           res = FALSE;
406       }
407       break;
408     default:
409       res = FALSE;
410   }
411   return res;
412 }
413
414 static gint64
415 gst_speex_enc_get_latency (GstSpeexEnc * enc)
416 {
417   return 30 * GST_MSECOND;
418 }
419
420 static const GstQueryType *
421 gst_speex_enc_get_query_types (GstPad * pad)
422 {
423   static const GstQueryType gst_speex_enc_src_query_types[] = {
424     GST_QUERY_POSITION,
425     GST_QUERY_DURATION,
426     GST_QUERY_CONVERT,
427     GST_QUERY_LATENCY,
428     0
429   };
430
431   return gst_speex_enc_src_query_types;
432 }
433
434 static gboolean
435 gst_speex_enc_src_query (GstPad * pad, GstQuery * query)
436 {
437   gboolean res = TRUE;
438   GstSpeexEnc *enc;
439
440   enc = GST_SPEEX_ENC (gst_pad_get_parent (pad));
441
442   switch (GST_QUERY_TYPE (query)) {
443     case GST_QUERY_POSITION:
444     {
445       GstFormat fmt, req_fmt;
446       gint64 pos, val;
447
448       gst_query_parse_position (query, &req_fmt, NULL);
449       if ((res = gst_pad_query_peer_position (enc->sinkpad, &req_fmt, &val))) {
450         gst_query_set_position (query, req_fmt, val);
451         break;
452       }
453
454       fmt = GST_FORMAT_TIME;
455       if (!(res = gst_pad_query_peer_position (enc->sinkpad, &fmt, &pos)))
456         break;
457
458       if ((res =
459               gst_pad_query_peer_convert (enc->sinkpad, fmt, pos, &req_fmt,
460                   &val)))
461         gst_query_set_position (query, req_fmt, val);
462
463       break;
464     }
465     case GST_QUERY_DURATION:
466     {
467       GstFormat fmt, req_fmt;
468       gint64 dur, val;
469
470       gst_query_parse_duration (query, &req_fmt, NULL);
471       if ((res = gst_pad_query_peer_duration (enc->sinkpad, &req_fmt, &val))) {
472         gst_query_set_duration (query, req_fmt, val);
473         break;
474       }
475
476       fmt = GST_FORMAT_TIME;
477       if (!(res = gst_pad_query_peer_duration (enc->sinkpad, &fmt, &dur)))
478         break;
479
480       if ((res =
481               gst_pad_query_peer_convert (enc->sinkpad, fmt, dur, &req_fmt,
482                   &val))) {
483         gst_query_set_duration (query, req_fmt, val);
484       }
485       break;
486     }
487     case GST_QUERY_CONVERT:
488     {
489       GstFormat src_fmt, dest_fmt;
490       gint64 src_val, dest_val;
491
492       gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, &dest_val);
493       if (!(res = gst_speex_enc_convert_src (pad, src_fmt, src_val, &dest_fmt,
494                   &dest_val)))
495         goto error;
496       gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val);
497       break;
498     }
499     case GST_QUERY_LATENCY:
500     {
501       gboolean live;
502       GstClockTime min_latency, max_latency;
503       gint64 latency;
504
505       if ((res = gst_pad_peer_query (enc->sinkpad, query))) {
506         gst_query_parse_latency (query, &live, &min_latency, &max_latency);
507         GST_LOG_OBJECT (pad, "Upstream latency: %" GST_PTR_FORMAT, query);
508
509         latency = gst_speex_enc_get_latency (enc);
510
511         /* add our latency */
512         min_latency += latency;
513         if (max_latency != -1)
514           max_latency += latency;
515
516         gst_query_set_latency (query, live, min_latency, max_latency);
517         GST_LOG_OBJECT (pad, "Adjusted latency: %" GST_PTR_FORMAT, query);
518       }
519       break;
520     }
521     default:
522       res = gst_pad_peer_query (enc->sinkpad, query);
523       break;
524   }
525
526 error:
527
528   gst_object_unref (enc);
529
530   return res;
531 }
532
533 static gboolean
534 gst_speex_enc_sink_query (GstPad * pad, GstQuery * query)
535 {
536   gboolean res = TRUE;
537
538   switch (GST_QUERY_TYPE (query)) {
539     case GST_QUERY_CONVERT:
540     {
541       GstFormat src_fmt, dest_fmt;
542       gint64 src_val, dest_val;
543
544       gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, &dest_val);
545       if (!(res =
546               gst_speex_enc_convert_sink (pad, src_fmt, src_val, &dest_fmt,
547                   &dest_val)))
548         goto error;
549       gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val);
550       break;
551     }
552     default:
553       res = gst_pad_query_default (pad, query);
554       break;
555   }
556
557 error:
558   return res;
559 }
560
561 static void
562 gst_speex_enc_init (GstSpeexEnc * enc, GstSpeexEncClass * klass)
563 {
564   enc->sinkpad = gst_pad_new_from_static_template (&sink_factory, "sink");
565   gst_element_add_pad (GST_ELEMENT (enc), enc->sinkpad);
566   gst_pad_set_event_function (enc->sinkpad,
567       GST_DEBUG_FUNCPTR (gst_speex_enc_sinkevent));
568   gst_pad_set_chain_function (enc->sinkpad,
569       GST_DEBUG_FUNCPTR (gst_speex_enc_chain));
570   gst_pad_set_setcaps_function (enc->sinkpad,
571       GST_DEBUG_FUNCPTR (gst_speex_enc_sink_setcaps));
572   gst_pad_set_getcaps_function (enc->sinkpad,
573       GST_DEBUG_FUNCPTR (gst_speex_enc_sink_getcaps));
574   gst_pad_set_query_function (enc->sinkpad,
575       GST_DEBUG_FUNCPTR (gst_speex_enc_sink_query));
576
577   enc->srcpad = gst_pad_new_from_static_template (&src_factory, "src");
578   gst_pad_set_query_function (enc->srcpad,
579       GST_DEBUG_FUNCPTR (gst_speex_enc_src_query));
580   gst_pad_set_query_type_function (enc->srcpad,
581       GST_DEBUG_FUNCPTR (gst_speex_enc_get_query_types));
582   gst_element_add_pad (GST_ELEMENT (enc), enc->srcpad);
583
584   enc->channels = -1;
585   enc->rate = -1;
586
587   enc->quality = DEFAULT_QUALITY;
588   enc->bitrate = DEFAULT_BITRATE;
589   enc->mode = DEFAULT_MODE;
590   enc->vbr = DEFAULT_VBR;
591   enc->abr = DEFAULT_ABR;
592   enc->vad = DEFAULT_VAD;
593   enc->dtx = DEFAULT_DTX;
594   enc->complexity = DEFAULT_COMPLEXITY;
595   enc->nframes = DEFAULT_NFRAMES;
596
597   enc->setup = FALSE;
598   enc->header_sent = FALSE;
599
600   enc->adapter = gst_adapter_new ();
601 }
602
603 static GstBuffer *
604 gst_speex_enc_create_metadata_buffer (GstSpeexEnc * enc)
605 {
606   const GstTagList *user_tags;
607   GstTagList *merged_tags;
608   GstBuffer *comments = NULL;
609
610   user_tags = gst_tag_setter_get_tag_list (GST_TAG_SETTER (enc));
611
612   GST_DEBUG_OBJECT (enc, "upstream tags = %" GST_PTR_FORMAT, enc->tags);
613   GST_DEBUG_OBJECT (enc, "user-set tags = %" GST_PTR_FORMAT, user_tags);
614
615   /* gst_tag_list_merge() will handle NULL for either or both lists fine */
616   merged_tags = gst_tag_list_merge (user_tags, enc->tags,
617       gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (enc)));
618
619   if (merged_tags == NULL)
620     merged_tags = gst_tag_list_new ();
621
622   GST_DEBUG_OBJECT (enc, "merged   tags = %" GST_PTR_FORMAT, merged_tags);
623   comments = gst_tag_list_to_vorbiscomment_buffer (merged_tags, NULL,
624       0, "Encoded with GStreamer Speexenc");
625   gst_tag_list_free (merged_tags);
626
627   GST_BUFFER_OFFSET (comments) = enc->bytes_out;
628   GST_BUFFER_OFFSET_END (comments) = 0;
629
630   return comments;
631 }
632
633 static void
634 gst_speex_enc_set_last_msg (GstSpeexEnc * enc, const gchar * msg)
635 {
636   g_free (enc->last_message);
637   enc->last_message = g_strdup (msg);
638   GST_WARNING_OBJECT (enc, "%s", msg);
639   g_object_notify (G_OBJECT (enc), "last-message");
640 }
641
642 static gboolean
643 gst_speex_enc_setup (GstSpeexEnc * enc)
644 {
645   enc->setup = FALSE;
646
647   switch (enc->mode) {
648     case GST_SPEEX_ENC_MODE_UWB:
649       GST_LOG_OBJECT (enc, "configuring for requested UWB mode");
650       enc->speex_mode = (SpeexMode *) & speex_uwb_mode;
651       break;
652     case GST_SPEEX_ENC_MODE_WB:
653       GST_LOG_OBJECT (enc, "configuring for requested WB mode");
654       enc->speex_mode = (SpeexMode *) & speex_wb_mode;
655       break;
656     case GST_SPEEX_ENC_MODE_NB:
657       GST_LOG_OBJECT (enc, "configuring for requested NB mode");
658       enc->speex_mode = (SpeexMode *) & speex_nb_mode;
659       break;
660     case GST_SPEEX_ENC_MODE_AUTO:
661       /* fall through */
662       GST_LOG_OBJECT (enc, "finding best mode");
663     default:
664       break;
665   }
666
667   if (enc->rate > 25000) {
668     if (enc->mode == GST_SPEEX_ENC_MODE_AUTO) {
669       GST_LOG_OBJECT (enc, "selected UWB mode for samplerate %d", enc->rate);
670       enc->speex_mode = (SpeexMode *) & speex_uwb_mode;
671     } else {
672       if (enc->speex_mode != &speex_uwb_mode) {
673         gst_speex_enc_set_last_msg (enc,
674             "Warning: suggest to use ultra wide band mode for this rate");
675       }
676     }
677   } else if (enc->rate > 12500) {
678     if (enc->mode == GST_SPEEX_ENC_MODE_AUTO) {
679       GST_LOG_OBJECT (enc, "selected WB mode for samplerate %d", enc->rate);
680       enc->speex_mode = (SpeexMode *) & speex_wb_mode;
681     } else {
682       if (enc->speex_mode != &speex_wb_mode) {
683         gst_speex_enc_set_last_msg (enc,
684             "Warning: suggest to use wide band mode for this rate");
685       }
686     }
687   } else {
688     if (enc->mode == GST_SPEEX_ENC_MODE_AUTO) {
689       GST_LOG_OBJECT (enc, "selected NB mode for samplerate %d", enc->rate);
690       enc->speex_mode = (SpeexMode *) & speex_nb_mode;
691     } else {
692       if (enc->speex_mode != &speex_nb_mode) {
693         gst_speex_enc_set_last_msg (enc,
694             "Warning: suggest to use narrow band mode for this rate");
695       }
696     }
697   }
698
699   if (enc->rate != 8000 && enc->rate != 16000 && enc->rate != 32000) {
700     gst_speex_enc_set_last_msg (enc,
701         "Warning: speex is optimized for 8, 16 and 32 KHz");
702   }
703
704   speex_init_header (&enc->header, enc->rate, 1, enc->speex_mode);
705   enc->header.frames_per_packet = enc->nframes;
706   enc->header.vbr = enc->vbr;
707   enc->header.nb_channels = enc->channels;
708
709   /*Initialize Speex encoder */
710   enc->state = speex_encoder_init (enc->speex_mode);
711
712   speex_encoder_ctl (enc->state, SPEEX_GET_FRAME_SIZE, &enc->frame_size);
713   speex_encoder_ctl (enc->state, SPEEX_SET_COMPLEXITY, &enc->complexity);
714   speex_encoder_ctl (enc->state, SPEEX_SET_SAMPLING_RATE, &enc->rate);
715
716   if (enc->vbr)
717     speex_encoder_ctl (enc->state, SPEEX_SET_VBR_QUALITY, &enc->quality);
718   else {
719     gint tmp = floor (enc->quality);
720
721     speex_encoder_ctl (enc->state, SPEEX_SET_QUALITY, &tmp);
722   }
723   if (enc->bitrate) {
724     if (enc->quality >= 0.0 && enc->vbr) {
725       gst_speex_enc_set_last_msg (enc,
726           "Warning: bitrate option is overriding quality");
727     }
728     speex_encoder_ctl (enc->state, SPEEX_SET_BITRATE, &enc->bitrate);
729   }
730   if (enc->vbr) {
731     gint tmp = 1;
732
733     speex_encoder_ctl (enc->state, SPEEX_SET_VBR, &tmp);
734   } else if (enc->vad) {
735     gint tmp = 1;
736
737     speex_encoder_ctl (enc->state, SPEEX_SET_VAD, &tmp);
738   }
739
740   if (enc->dtx) {
741     gint tmp = 1;
742
743     speex_encoder_ctl (enc->state, SPEEX_SET_DTX, &tmp);
744   }
745
746   if (enc->dtx && !(enc->vbr || enc->abr || enc->vad)) {
747     gst_speex_enc_set_last_msg (enc,
748         "Warning: dtx is useless without vad, vbr or abr");
749   } else if ((enc->vbr || enc->abr) && (enc->vad)) {
750     gst_speex_enc_set_last_msg (enc,
751         "Warning: vad is already implied by vbr or abr");
752   }
753
754   if (enc->abr) {
755     speex_encoder_ctl (enc->state, SPEEX_SET_ABR, &enc->abr);
756   }
757
758   speex_encoder_ctl (enc->state, SPEEX_GET_LOOKAHEAD, &enc->lookahead);
759
760   GST_LOG_OBJECT (enc, "we have frame size %d, lookahead %d", enc->frame_size,
761       enc->lookahead);
762
763   enc->setup = TRUE;
764
765   return TRUE;
766 }
767
768 /* prepare a buffer for transmission */
769 static GstBuffer *
770 gst_speex_enc_buffer_from_data (GstSpeexEnc * enc, guchar * data,
771     gint data_len, guint64 granulepos)
772 {
773   GstBuffer *outbuf;
774
775   outbuf = gst_buffer_new_and_alloc (data_len);
776   memcpy (GST_BUFFER_DATA (outbuf), data, data_len);
777   GST_BUFFER_OFFSET (outbuf) = enc->bytes_out;
778   GST_BUFFER_OFFSET_END (outbuf) = granulepos;
779
780   GST_LOG_OBJECT (enc, "encoded buffer of %d bytes", GST_BUFFER_SIZE (outbuf));
781   return outbuf;
782 }
783
784
785 /* push out the buffer and do internal bookkeeping */
786 static GstFlowReturn
787 gst_speex_enc_push_buffer (GstSpeexEnc * enc, GstBuffer * buffer)
788 {
789   guint size;
790
791   size = GST_BUFFER_SIZE (buffer);
792
793   enc->bytes_out += size;
794
795   GST_DEBUG_OBJECT (enc, "pushing output buffer of size %u", size);
796
797   return gst_pad_push (enc->srcpad, buffer);
798 }
799
800 static GstCaps *
801 gst_speex_enc_set_header_on_caps (GstCaps * caps, GstBuffer * buf1,
802     GstBuffer * buf2)
803 {
804   GstStructure *structure = NULL;
805   GstBuffer *buf;
806   GValue array = { 0 };
807   GValue value = { 0 };
808
809   caps = gst_caps_make_writable (caps);
810   structure = gst_caps_get_structure (caps, 0);
811
812   g_assert (gst_buffer_is_metadata_writable (buf1));
813   g_assert (gst_buffer_is_metadata_writable (buf2));
814
815   /* mark buffers */
816   GST_BUFFER_FLAG_SET (buf1, GST_BUFFER_FLAG_IN_CAPS);
817   GST_BUFFER_FLAG_SET (buf2, GST_BUFFER_FLAG_IN_CAPS);
818
819   /* put buffers in a fixed list */
820   g_value_init (&array, GST_TYPE_ARRAY);
821   g_value_init (&value, GST_TYPE_BUFFER);
822   buf = gst_buffer_copy (buf1);
823   gst_value_set_buffer (&value, buf);
824   gst_buffer_unref (buf);
825   gst_value_array_append_value (&array, &value);
826   g_value_unset (&value);
827   g_value_init (&value, GST_TYPE_BUFFER);
828   buf = gst_buffer_copy (buf2);
829   gst_value_set_buffer (&value, buf);
830   gst_buffer_unref (buf);
831   gst_value_array_append_value (&array, &value);
832   gst_structure_set_value (structure, "streamheader", &array);
833   g_value_unset (&value);
834   g_value_unset (&array);
835
836   return caps;
837 }
838
839
840 static gboolean
841 gst_speex_enc_sinkevent (GstPad * pad, GstEvent * event)
842 {
843   gboolean res = TRUE;
844   GstSpeexEnc *enc;
845
846   enc = GST_SPEEX_ENC (gst_pad_get_parent (pad));
847
848   switch (GST_EVENT_TYPE (event)) {
849     case GST_EVENT_EOS:
850       gst_speex_enc_encode (enc, TRUE);
851       res = gst_pad_event_default (pad, event);
852       break;
853     case GST_EVENT_TAG:
854     {
855       GstTagList *list;
856
857       gst_event_parse_tag (event, &list);
858       if (enc->tags) {
859         gst_tag_list_insert (enc->tags, list,
860             gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (enc)));
861       }
862       res = gst_pad_event_default (pad, event);
863       break;
864     }
865     default:
866       res = gst_pad_event_default (pad, event);
867       break;
868   }
869
870   gst_object_unref (enc);
871
872   return res;
873 }
874
875 static GstFlowReturn
876 gst_speex_enc_encode (GstSpeexEnc * enc, gboolean flush)
877 {
878   gint frame_size = enc->frame_size;
879   gint bytes = frame_size * 2 * enc->channels;
880   GstFlowReturn ret = GST_FLOW_OK;
881
882   if (flush && gst_adapter_available (enc->adapter) % bytes != 0) {
883     guint diff = gst_adapter_available (enc->adapter) % bytes;
884     GstBuffer *buf = gst_buffer_new_and_alloc (diff);
885
886     memset (GST_BUFFER_DATA (buf), 0, diff);
887     gst_adapter_push (enc->adapter, buf);
888   }
889
890   while (gst_adapter_available (enc->adapter) >= bytes) {
891     gint16 *data;
892     gint outsize, written;
893     GstBuffer *outbuf;
894
895     data = (gint16 *) gst_adapter_take (enc->adapter, bytes);
896
897     enc->samples_in += frame_size;
898
899     GST_DEBUG_OBJECT (enc, "encoding %d samples (%d bytes)", frame_size, bytes);
900
901     if (enc->channels == 2) {
902       speex_encode_stereo_int (data, frame_size, &enc->bits);
903     }
904     speex_encode_int (enc->state, data, &enc->bits);
905
906     g_free (data);
907
908     enc->frameno++;
909     enc->frameno_out++;
910
911     if ((enc->frameno % enc->nframes) != 0)
912       continue;
913
914     speex_bits_insert_terminator (&enc->bits);
915     outsize = speex_bits_nbytes (&enc->bits);
916
917     ret = gst_pad_alloc_buffer_and_set_caps (enc->srcpad,
918         GST_BUFFER_OFFSET_NONE, outsize, GST_PAD_CAPS (enc->srcpad), &outbuf);
919
920     if ((GST_FLOW_OK != ret))
921       goto done;
922
923     written = speex_bits_write (&enc->bits,
924         (gchar *) GST_BUFFER_DATA (outbuf), outsize);
925     g_assert (written == outsize);
926     speex_bits_reset (&enc->bits);
927
928     GST_BUFFER_TIMESTAMP (outbuf) = enc->start_ts +
929         gst_util_uint64_scale_int ((enc->frameno_out - 1) * frame_size -
930         enc->lookahead, GST_SECOND, enc->rate);
931     GST_BUFFER_DURATION (outbuf) = gst_util_uint64_scale_int (frame_size,
932         GST_SECOND, enc->rate);
933     /* set gp time and granulepos; see gst-plugins-base/ext/ogg/README */
934     GST_BUFFER_OFFSET_END (outbuf) = enc->granulepos_offset +
935         ((enc->frameno_out) * frame_size - enc->lookahead);
936     GST_BUFFER_OFFSET (outbuf) =
937         gst_util_uint64_scale_int (GST_BUFFER_OFFSET_END (outbuf), GST_SECOND,
938         enc->rate);
939
940     ret = gst_speex_enc_push_buffer (enc, outbuf);
941
942     if ((GST_FLOW_OK != ret) && (GST_FLOW_NOT_LINKED != ret))
943       goto done;
944   }
945
946 done:
947
948   return ret;
949 }
950
951 static GstFlowReturn
952 gst_speex_enc_chain (GstPad * pad, GstBuffer * buf)
953 {
954   GstSpeexEnc *enc;
955   GstFlowReturn ret = GST_FLOW_OK;
956
957   enc = GST_SPEEX_ENC (GST_PAD_PARENT (pad));
958
959   if (!enc->setup)
960     goto not_setup;
961
962   if (!enc->header_sent) {
963     /* Speex streams begin with two headers; the initial header (with
964        most of the codec setup parameters) which is mandated by the Ogg
965        bitstream spec.  The second header holds any comment fields.
966        We merely need to make the headers, then pass them to libspeex 
967        one at a time; libspeex handles the additional Ogg bitstream 
968        constraints */
969     GstBuffer *buf1, *buf2;
970     GstCaps *caps;
971     guchar *data;
972     gint data_len;
973
974     /* create header buffer */
975     data = (guint8 *) speex_header_to_packet (&enc->header, &data_len);
976     buf1 = gst_speex_enc_buffer_from_data (enc, data, data_len, 0);
977     free (data);
978
979     /* create comment buffer */
980     buf2 = gst_speex_enc_create_metadata_buffer (enc);
981
982     /* mark and put on caps */
983     caps = gst_pad_get_caps (enc->srcpad);
984     caps = gst_speex_enc_set_header_on_caps (caps, buf1, buf2);
985
986     gst_caps_set_simple (caps,
987         "rate", G_TYPE_INT, enc->rate,
988         "channels", G_TYPE_INT, enc->channels, NULL);
989
990     /* negotiate with these caps */
991     GST_DEBUG_OBJECT (enc, "here are the caps: %" GST_PTR_FORMAT, caps);
992     gst_pad_set_caps (enc->srcpad, caps);
993
994     gst_buffer_set_caps (buf1, caps);
995     gst_buffer_set_caps (buf2, caps);
996     gst_caps_unref (caps);
997
998     /* push out buffers */
999     ret = gst_speex_enc_push_buffer (enc, buf1);
1000
1001     if (ret != GST_FLOW_OK) {
1002       gst_buffer_unref (buf2);
1003       goto done;
1004     }
1005
1006     ret = gst_speex_enc_push_buffer (enc, buf2);
1007
1008     if (ret != GST_FLOW_OK)
1009       goto done;
1010
1011     speex_bits_reset (&enc->bits);
1012
1013     enc->header_sent = TRUE;
1014   }
1015
1016   /* Save the timestamp of the first buffer. This will be later
1017    * used as offset for all following buffers */
1018   if (enc->start_ts == GST_CLOCK_TIME_NONE) {
1019     if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)) {
1020       enc->start_ts = GST_BUFFER_TIMESTAMP (buf);
1021       enc->granulepos_offset = gst_util_uint64_scale
1022           (GST_BUFFER_TIMESTAMP (buf), enc->rate, GST_SECOND);
1023     } else {
1024       enc->start_ts = 0;
1025       enc->granulepos_offset = 0;
1026     }
1027   }
1028
1029   /* Check if we have a continous stream, if not drop some samples or the buffer or
1030    * insert some silence samples */
1031   if (enc->next_ts != GST_CLOCK_TIME_NONE &&
1032       GST_BUFFER_TIMESTAMP (buf) < enc->next_ts) {
1033     guint64 diff = enc->next_ts - GST_BUFFER_TIMESTAMP (buf);
1034     guint64 diff_bytes;
1035
1036     GST_WARNING_OBJECT (enc, "Buffer is older than previous "
1037         "timestamp + duration (%" GST_TIME_FORMAT "< %" GST_TIME_FORMAT
1038         "), cannot handle. Clipping buffer.",
1039         GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
1040         GST_TIME_ARGS (enc->next_ts));
1041
1042     diff_bytes = GST_CLOCK_TIME_TO_FRAMES (diff, enc->rate) * enc->channels * 2;
1043     if (diff_bytes >= GST_BUFFER_SIZE (buf)) {
1044       gst_buffer_unref (buf);
1045       return GST_FLOW_OK;
1046     }
1047     buf = gst_buffer_make_metadata_writable (buf);
1048     GST_BUFFER_DATA (buf) += diff_bytes;
1049     GST_BUFFER_SIZE (buf) -= diff_bytes;
1050
1051     GST_BUFFER_TIMESTAMP (buf) += diff;
1052     if (GST_BUFFER_DURATION_IS_VALID (buf))
1053       GST_BUFFER_DURATION (buf) -= diff;
1054   }
1055
1056   if (enc->next_ts != GST_CLOCK_TIME_NONE
1057       && GST_BUFFER_TIMESTAMP_IS_VALID (buf)) {
1058     guint64 max_diff =
1059         gst_util_uint64_scale (enc->frame_size, GST_SECOND, enc->rate);
1060
1061     if (GST_BUFFER_TIMESTAMP (buf) != enc->next_ts &&
1062         GST_BUFFER_TIMESTAMP (buf) - enc->next_ts > max_diff) {
1063       GST_WARNING_OBJECT (enc,
1064           "Discontinuity detected: %" G_GUINT64_FORMAT " > %" G_GUINT64_FORMAT,
1065           GST_BUFFER_TIMESTAMP (buf) - enc->next_ts, max_diff);
1066
1067       gst_speex_enc_encode (enc, TRUE);
1068
1069       enc->frameno_out = 0;
1070       enc->start_ts = GST_BUFFER_TIMESTAMP (buf);
1071       enc->granulepos_offset = gst_util_uint64_scale
1072           (GST_BUFFER_TIMESTAMP (buf), enc->rate, GST_SECOND);
1073     }
1074   }
1075
1076   if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)
1077       && GST_BUFFER_DURATION_IS_VALID (buf))
1078     enc->next_ts = GST_BUFFER_TIMESTAMP (buf) + GST_BUFFER_DURATION (buf);
1079   else
1080     enc->next_ts = GST_CLOCK_TIME_NONE;
1081
1082   GST_DEBUG_OBJECT (enc, "received buffer of %u bytes", GST_BUFFER_SIZE (buf));
1083
1084   /* push buffer to adapter */
1085   gst_adapter_push (enc->adapter, buf);
1086   buf = NULL;
1087
1088   ret = gst_speex_enc_encode (enc, FALSE);
1089
1090 done:
1091
1092   if (buf)
1093     gst_buffer_unref (buf);
1094
1095   return ret;
1096
1097   /* ERRORS */
1098 not_setup:
1099   {
1100     GST_ELEMENT_ERROR (enc, CORE, NEGOTIATION, (NULL),
1101         ("encoder not initialized (input is not audio?)"));
1102     ret = GST_FLOW_NOT_NEGOTIATED;
1103     goto done;
1104   }
1105
1106 }
1107
1108
1109 static void
1110 gst_speex_enc_get_property (GObject * object, guint prop_id, GValue * value,
1111     GParamSpec * pspec)
1112 {
1113   GstSpeexEnc *enc;
1114
1115   enc = GST_SPEEX_ENC (object);
1116
1117   switch (prop_id) {
1118     case PROP_QUALITY:
1119       g_value_set_float (value, enc->quality);
1120       break;
1121     case PROP_BITRATE:
1122       g_value_set_int (value, enc->bitrate);
1123       break;
1124     case PROP_MODE:
1125       g_value_set_enum (value, enc->mode);
1126       break;
1127     case PROP_VBR:
1128       g_value_set_boolean (value, enc->vbr);
1129       break;
1130     case PROP_ABR:
1131       g_value_set_int (value, enc->abr);
1132       break;
1133     case PROP_VAD:
1134       g_value_set_boolean (value, enc->vad);
1135       break;
1136     case PROP_DTX:
1137       g_value_set_boolean (value, enc->dtx);
1138       break;
1139     case PROP_COMPLEXITY:
1140       g_value_set_int (value, enc->complexity);
1141       break;
1142     case PROP_NFRAMES:
1143       g_value_set_int (value, enc->nframes);
1144       break;
1145     case PROP_LAST_MESSAGE:
1146       g_value_set_string (value, enc->last_message);
1147       break;
1148     default:
1149       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1150       break;
1151   }
1152 }
1153
1154 static void
1155 gst_speex_enc_set_property (GObject * object, guint prop_id,
1156     const GValue * value, GParamSpec * pspec)
1157 {
1158   GstSpeexEnc *enc;
1159
1160   enc = GST_SPEEX_ENC (object);
1161
1162   switch (prop_id) {
1163     case PROP_QUALITY:
1164       enc->quality = g_value_get_float (value);
1165       break;
1166     case PROP_BITRATE:
1167       enc->bitrate = g_value_get_int (value);
1168       break;
1169     case PROP_MODE:
1170       enc->mode = g_value_get_enum (value);
1171       break;
1172     case PROP_VBR:
1173       enc->vbr = g_value_get_boolean (value);
1174       break;
1175     case PROP_ABR:
1176       enc->abr = g_value_get_int (value);
1177       break;
1178     case PROP_VAD:
1179       enc->vad = g_value_get_boolean (value);
1180       break;
1181     case PROP_DTX:
1182       enc->dtx = g_value_get_boolean (value);
1183       break;
1184     case PROP_COMPLEXITY:
1185       enc->complexity = g_value_get_int (value);
1186       break;
1187     case PROP_NFRAMES:
1188       enc->nframes = g_value_get_int (value);
1189       break;
1190     default:
1191       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1192       break;
1193   }
1194 }
1195
1196 static GstStateChangeReturn
1197 gst_speex_enc_change_state (GstElement * element, GstStateChange transition)
1198 {
1199   GstSpeexEnc *enc = GST_SPEEX_ENC (element);
1200   GstStateChangeReturn res;
1201
1202   switch (transition) {
1203     case GST_STATE_CHANGE_NULL_TO_READY:
1204       enc->tags = gst_tag_list_new ();
1205       break;
1206     case GST_STATE_CHANGE_READY_TO_PAUSED:
1207       speex_bits_init (&enc->bits);
1208       enc->frameno = 0;
1209       enc->frameno_out = 0;
1210       enc->samples_in = 0;
1211       enc->start_ts = GST_CLOCK_TIME_NONE;
1212       enc->next_ts = GST_CLOCK_TIME_NONE;
1213       enc->granulepos_offset = 0;
1214       break;
1215     case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
1216       /* fall through */
1217     default:
1218       break;
1219   }
1220
1221   res = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1222   if (res == GST_STATE_CHANGE_FAILURE)
1223     return res;
1224
1225   switch (transition) {
1226     case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
1227       break;
1228     case GST_STATE_CHANGE_PAUSED_TO_READY:
1229       enc->setup = FALSE;
1230       enc->header_sent = FALSE;
1231       if (enc->state) {
1232         speex_encoder_destroy (enc->state);
1233         enc->state = NULL;
1234       }
1235       speex_bits_destroy (&enc->bits);
1236       break;
1237     case GST_STATE_CHANGE_READY_TO_NULL:
1238       gst_tag_list_free (enc->tags);
1239       enc->tags = NULL;
1240     default:
1241       break;
1242   }
1243
1244   return res;
1245 }