speexenc: small taglist handling cleanup
[platform/upstream/gstreamer.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       if (enc->tags) {
856         GstTagList *list;
857
858         gst_event_parse_tag (event, &list);
859         gst_tag_list_insert (enc->tags, list,
860             gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (enc)));
861       } else {
862         g_assert_not_reached ();
863       }
864       res = gst_pad_event_default (pad, event);
865       break;
866     }
867     default:
868       res = gst_pad_event_default (pad, event);
869       break;
870   }
871
872   gst_object_unref (enc);
873
874   return res;
875 }
876
877 static GstFlowReturn
878 gst_speex_enc_encode (GstSpeexEnc * enc, gboolean flush)
879 {
880   gint frame_size = enc->frame_size;
881   gint bytes = frame_size * 2 * enc->channels;
882   GstFlowReturn ret = GST_FLOW_OK;
883
884   if (flush && gst_adapter_available (enc->adapter) % bytes != 0) {
885     guint diff = gst_adapter_available (enc->adapter) % bytes;
886     GstBuffer *buf = gst_buffer_new_and_alloc (diff);
887
888     memset (GST_BUFFER_DATA (buf), 0, diff);
889     gst_adapter_push (enc->adapter, buf);
890   }
891
892   while (gst_adapter_available (enc->adapter) >= bytes) {
893     gint16 *data;
894     gint outsize, written;
895     GstBuffer *outbuf;
896
897     data = (gint16 *) gst_adapter_take (enc->adapter, bytes);
898
899     enc->samples_in += frame_size;
900
901     GST_DEBUG_OBJECT (enc, "encoding %d samples (%d bytes)", frame_size, bytes);
902
903     if (enc->channels == 2) {
904       speex_encode_stereo_int (data, frame_size, &enc->bits);
905     }
906     speex_encode_int (enc->state, data, &enc->bits);
907
908     g_free (data);
909
910     enc->frameno++;
911     enc->frameno_out++;
912
913     if ((enc->frameno % enc->nframes) != 0)
914       continue;
915
916     speex_bits_insert_terminator (&enc->bits);
917     outsize = speex_bits_nbytes (&enc->bits);
918
919     ret = gst_pad_alloc_buffer_and_set_caps (enc->srcpad,
920         GST_BUFFER_OFFSET_NONE, outsize, GST_PAD_CAPS (enc->srcpad), &outbuf);
921
922     if ((GST_FLOW_OK != ret))
923       goto done;
924
925     written = speex_bits_write (&enc->bits,
926         (gchar *) GST_BUFFER_DATA (outbuf), outsize);
927     g_assert (written == outsize);
928     speex_bits_reset (&enc->bits);
929
930     GST_BUFFER_TIMESTAMP (outbuf) = enc->start_ts +
931         gst_util_uint64_scale_int ((enc->frameno_out - 1) * frame_size -
932         enc->lookahead, GST_SECOND, enc->rate);
933     GST_BUFFER_DURATION (outbuf) = gst_util_uint64_scale_int (frame_size,
934         GST_SECOND, enc->rate);
935     /* set gp time and granulepos; see gst-plugins-base/ext/ogg/README */
936     GST_BUFFER_OFFSET_END (outbuf) = enc->granulepos_offset +
937         ((enc->frameno_out) * frame_size - enc->lookahead);
938     GST_BUFFER_OFFSET (outbuf) =
939         gst_util_uint64_scale_int (GST_BUFFER_OFFSET_END (outbuf), GST_SECOND,
940         enc->rate);
941
942     ret = gst_speex_enc_push_buffer (enc, outbuf);
943
944     if ((GST_FLOW_OK != ret) && (GST_FLOW_NOT_LINKED != ret))
945       goto done;
946   }
947
948 done:
949
950   return ret;
951 }
952
953 static GstFlowReturn
954 gst_speex_enc_chain (GstPad * pad, GstBuffer * buf)
955 {
956   GstSpeexEnc *enc;
957   GstFlowReturn ret = GST_FLOW_OK;
958
959   enc = GST_SPEEX_ENC (GST_PAD_PARENT (pad));
960
961   if (!enc->setup)
962     goto not_setup;
963
964   if (!enc->header_sent) {
965     /* Speex streams begin with two headers; the initial header (with
966        most of the codec setup parameters) which is mandated by the Ogg
967        bitstream spec.  The second header holds any comment fields.
968        We merely need to make the headers, then pass them to libspeex 
969        one at a time; libspeex handles the additional Ogg bitstream 
970        constraints */
971     GstBuffer *buf1, *buf2;
972     GstCaps *caps;
973     guchar *data;
974     gint data_len;
975
976     /* create header buffer */
977     data = (guint8 *) speex_header_to_packet (&enc->header, &data_len);
978     buf1 = gst_speex_enc_buffer_from_data (enc, data, data_len, 0);
979     free (data);
980
981     /* create comment buffer */
982     buf2 = gst_speex_enc_create_metadata_buffer (enc);
983
984     /* mark and put on caps */
985     caps = gst_pad_get_caps (enc->srcpad);
986     caps = gst_speex_enc_set_header_on_caps (caps, buf1, buf2);
987
988     gst_caps_set_simple (caps,
989         "rate", G_TYPE_INT, enc->rate,
990         "channels", G_TYPE_INT, enc->channels, NULL);
991
992     /* negotiate with these caps */
993     GST_DEBUG_OBJECT (enc, "here are the caps: %" GST_PTR_FORMAT, caps);
994     gst_pad_set_caps (enc->srcpad, caps);
995
996     gst_buffer_set_caps (buf1, caps);
997     gst_buffer_set_caps (buf2, caps);
998     gst_caps_unref (caps);
999
1000     /* push out buffers */
1001     ret = gst_speex_enc_push_buffer (enc, buf1);
1002
1003     if (ret != GST_FLOW_OK) {
1004       gst_buffer_unref (buf2);
1005       goto done;
1006     }
1007
1008     ret = gst_speex_enc_push_buffer (enc, buf2);
1009
1010     if (ret != GST_FLOW_OK)
1011       goto done;
1012
1013     speex_bits_reset (&enc->bits);
1014
1015     enc->header_sent = TRUE;
1016   }
1017
1018   /* Save the timestamp of the first buffer. This will be later
1019    * used as offset for all following buffers */
1020   if (enc->start_ts == GST_CLOCK_TIME_NONE) {
1021     if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)) {
1022       enc->start_ts = GST_BUFFER_TIMESTAMP (buf);
1023       enc->granulepos_offset = gst_util_uint64_scale
1024           (GST_BUFFER_TIMESTAMP (buf), enc->rate, GST_SECOND);
1025     } else {
1026       enc->start_ts = 0;
1027       enc->granulepos_offset = 0;
1028     }
1029   }
1030
1031   /* Check if we have a continous stream, if not drop some samples or the buffer or
1032    * insert some silence samples */
1033   if (enc->next_ts != GST_CLOCK_TIME_NONE &&
1034       GST_BUFFER_TIMESTAMP (buf) < enc->next_ts) {
1035     guint64 diff = enc->next_ts - GST_BUFFER_TIMESTAMP (buf);
1036     guint64 diff_bytes;
1037
1038     GST_WARNING_OBJECT (enc, "Buffer is older than previous "
1039         "timestamp + duration (%" GST_TIME_FORMAT "< %" GST_TIME_FORMAT
1040         "), cannot handle. Clipping buffer.",
1041         GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
1042         GST_TIME_ARGS (enc->next_ts));
1043
1044     diff_bytes = GST_CLOCK_TIME_TO_FRAMES (diff, enc->rate) * enc->channels * 2;
1045     if (diff_bytes >= GST_BUFFER_SIZE (buf)) {
1046       gst_buffer_unref (buf);
1047       return GST_FLOW_OK;
1048     }
1049     buf = gst_buffer_make_metadata_writable (buf);
1050     GST_BUFFER_DATA (buf) += diff_bytes;
1051     GST_BUFFER_SIZE (buf) -= diff_bytes;
1052
1053     GST_BUFFER_TIMESTAMP (buf) += diff;
1054     if (GST_BUFFER_DURATION_IS_VALID (buf))
1055       GST_BUFFER_DURATION (buf) -= diff;
1056   }
1057
1058   if (enc->next_ts != GST_CLOCK_TIME_NONE
1059       && GST_BUFFER_TIMESTAMP_IS_VALID (buf)) {
1060     guint64 max_diff =
1061         gst_util_uint64_scale (enc->frame_size, GST_SECOND, enc->rate);
1062
1063     if (GST_BUFFER_TIMESTAMP (buf) != enc->next_ts &&
1064         GST_BUFFER_TIMESTAMP (buf) - enc->next_ts > max_diff) {
1065       GST_WARNING_OBJECT (enc,
1066           "Discontinuity detected: %" G_GUINT64_FORMAT " > %" G_GUINT64_FORMAT,
1067           GST_BUFFER_TIMESTAMP (buf) - enc->next_ts, max_diff);
1068
1069       gst_speex_enc_encode (enc, TRUE);
1070
1071       enc->frameno_out = 0;
1072       enc->start_ts = GST_BUFFER_TIMESTAMP (buf);
1073       enc->granulepos_offset = gst_util_uint64_scale
1074           (GST_BUFFER_TIMESTAMP (buf), enc->rate, GST_SECOND);
1075     }
1076   }
1077
1078   if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)
1079       && GST_BUFFER_DURATION_IS_VALID (buf))
1080     enc->next_ts = GST_BUFFER_TIMESTAMP (buf) + GST_BUFFER_DURATION (buf);
1081   else
1082     enc->next_ts = GST_CLOCK_TIME_NONE;
1083
1084   GST_DEBUG_OBJECT (enc, "received buffer of %u bytes", GST_BUFFER_SIZE (buf));
1085
1086   /* push buffer to adapter */
1087   gst_adapter_push (enc->adapter, buf);
1088   buf = NULL;
1089
1090   ret = gst_speex_enc_encode (enc, FALSE);
1091
1092 done:
1093
1094   if (buf)
1095     gst_buffer_unref (buf);
1096
1097   return ret;
1098
1099   /* ERRORS */
1100 not_setup:
1101   {
1102     GST_ELEMENT_ERROR (enc, CORE, NEGOTIATION, (NULL),
1103         ("encoder not initialized (input is not audio?)"));
1104     ret = GST_FLOW_NOT_NEGOTIATED;
1105     goto done;
1106   }
1107
1108 }
1109
1110
1111 static void
1112 gst_speex_enc_get_property (GObject * object, guint prop_id, GValue * value,
1113     GParamSpec * pspec)
1114 {
1115   GstSpeexEnc *enc;
1116
1117   enc = GST_SPEEX_ENC (object);
1118
1119   switch (prop_id) {
1120     case PROP_QUALITY:
1121       g_value_set_float (value, enc->quality);
1122       break;
1123     case PROP_BITRATE:
1124       g_value_set_int (value, enc->bitrate);
1125       break;
1126     case PROP_MODE:
1127       g_value_set_enum (value, enc->mode);
1128       break;
1129     case PROP_VBR:
1130       g_value_set_boolean (value, enc->vbr);
1131       break;
1132     case PROP_ABR:
1133       g_value_set_int (value, enc->abr);
1134       break;
1135     case PROP_VAD:
1136       g_value_set_boolean (value, enc->vad);
1137       break;
1138     case PROP_DTX:
1139       g_value_set_boolean (value, enc->dtx);
1140       break;
1141     case PROP_COMPLEXITY:
1142       g_value_set_int (value, enc->complexity);
1143       break;
1144     case PROP_NFRAMES:
1145       g_value_set_int (value, enc->nframes);
1146       break;
1147     case PROP_LAST_MESSAGE:
1148       g_value_set_string (value, enc->last_message);
1149       break;
1150     default:
1151       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1152       break;
1153   }
1154 }
1155
1156 static void
1157 gst_speex_enc_set_property (GObject * object, guint prop_id,
1158     const GValue * value, GParamSpec * pspec)
1159 {
1160   GstSpeexEnc *enc;
1161
1162   enc = GST_SPEEX_ENC (object);
1163
1164   switch (prop_id) {
1165     case PROP_QUALITY:
1166       enc->quality = g_value_get_float (value);
1167       break;
1168     case PROP_BITRATE:
1169       enc->bitrate = g_value_get_int (value);
1170       break;
1171     case PROP_MODE:
1172       enc->mode = g_value_get_enum (value);
1173       break;
1174     case PROP_VBR:
1175       enc->vbr = g_value_get_boolean (value);
1176       break;
1177     case PROP_ABR:
1178       enc->abr = g_value_get_int (value);
1179       break;
1180     case PROP_VAD:
1181       enc->vad = g_value_get_boolean (value);
1182       break;
1183     case PROP_DTX:
1184       enc->dtx = g_value_get_boolean (value);
1185       break;
1186     case PROP_COMPLEXITY:
1187       enc->complexity = g_value_get_int (value);
1188       break;
1189     case PROP_NFRAMES:
1190       enc->nframes = g_value_get_int (value);
1191       break;
1192     default:
1193       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1194       break;
1195   }
1196 }
1197
1198 static GstStateChangeReturn
1199 gst_speex_enc_change_state (GstElement * element, GstStateChange transition)
1200 {
1201   GstSpeexEnc *enc = GST_SPEEX_ENC (element);
1202   GstStateChangeReturn res;
1203
1204   switch (transition) {
1205     case GST_STATE_CHANGE_NULL_TO_READY:
1206       enc->tags = gst_tag_list_new ();
1207       break;
1208     case GST_STATE_CHANGE_READY_TO_PAUSED:
1209       speex_bits_init (&enc->bits);
1210       enc->frameno = 0;
1211       enc->frameno_out = 0;
1212       enc->samples_in = 0;
1213       enc->start_ts = GST_CLOCK_TIME_NONE;
1214       enc->next_ts = GST_CLOCK_TIME_NONE;
1215       enc->granulepos_offset = 0;
1216       break;
1217     case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
1218       /* fall through */
1219     default:
1220       break;
1221   }
1222
1223   res = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1224   if (res == GST_STATE_CHANGE_FAILURE)
1225     return res;
1226
1227   switch (transition) {
1228     case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
1229       break;
1230     case GST_STATE_CHANGE_PAUSED_TO_READY:
1231       enc->setup = FALSE;
1232       enc->header_sent = FALSE;
1233       if (enc->state) {
1234         speex_encoder_destroy (enc->state);
1235         enc->state = NULL;
1236       }
1237       speex_bits_destroy (&enc->bits);
1238       break;
1239     case GST_STATE_CHANGE_READY_TO_NULL:
1240       gst_tag_list_free (enc->tags);
1241       enc->tags = NULL;
1242     default:
1243       break;
1244   }
1245
1246   return res;
1247 }