speex: Fix crashes with MSVC
[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 #define DEFAULT_QUALITY         8.0
73 #define DEFAULT_BITRATE         0
74 #define DEFAULT_MODE            GST_SPEEX_ENC_MODE_AUTO
75 #define DEFAULT_VBR             FALSE
76 #define DEFAULT_ABR             0
77 #define DEFAULT_VAD             FALSE
78 #define DEFAULT_DTX             FALSE
79 #define DEFAULT_COMPLEXITY      3
80 #define DEFAULT_NFRAMES         1
81
82 enum
83 {
84   PROP_0,
85   PROP_QUALITY,
86   PROP_BITRATE,
87   PROP_MODE,
88   PROP_VBR,
89   PROP_ABR,
90   PROP_VAD,
91   PROP_DTX,
92   PROP_COMPLEXITY,
93   PROP_NFRAMES,
94   PROP_LAST_MESSAGE
95 };
96
97 #define GST_TYPE_SPEEX_ENC_MODE (gst_speex_enc_mode_get_type())
98 static GType
99 gst_speex_enc_mode_get_type (void)
100 {
101   static GType speex_enc_mode_type = 0;
102   static const GEnumValue speex_enc_modes[] = {
103     {GST_SPEEX_ENC_MODE_AUTO, "Auto", "auto"},
104     {GST_SPEEX_ENC_MODE_UWB, "Ultra Wide Band", "uwb"},
105     {GST_SPEEX_ENC_MODE_WB, "Wide Band", "wb"},
106     {GST_SPEEX_ENC_MODE_NB, "Narrow Band", "nb"},
107     {0, NULL, NULL},
108   };
109   if (G_UNLIKELY (speex_enc_mode_type == 0)) {
110     speex_enc_mode_type = g_enum_register_static ("GstSpeexEncMode",
111         speex_enc_modes);
112   }
113   return speex_enc_mode_type;
114 }
115
116 #if 0
117 static const GstFormat *
118 gst_speex_enc_get_formats (GstPad * pad)
119 {
120   static const GstFormat src_formats[] = {
121     GST_FORMAT_BYTES,
122     GST_FORMAT_TIME,
123     0
124   };
125   static const GstFormat sink_formats[] = {
126     GST_FORMAT_BYTES,
127     GST_FORMAT_DEFAULT,
128     GST_FORMAT_TIME,
129     0
130   };
131
132   return (GST_PAD_IS_SRC (pad) ? src_formats : sink_formats);
133 }
134 #endif
135
136 static void gst_speex_enc_finalize (GObject * object);
137
138 static gboolean gst_speex_enc_sinkevent (GstPad * pad, GstEvent * event);
139 static GstFlowReturn gst_speex_enc_chain (GstPad * pad, GstBuffer * buf);
140 static gboolean gst_speex_enc_setup (GstSpeexEnc * enc);
141
142 static void gst_speex_enc_get_property (GObject * object, guint prop_id,
143     GValue * value, GParamSpec * pspec);
144 static void gst_speex_enc_set_property (GObject * object, guint prop_id,
145     const GValue * value, GParamSpec * pspec);
146 static GstStateChangeReturn gst_speex_enc_change_state (GstElement * element,
147     GstStateChange transition);
148
149 static GstFlowReturn gst_speex_enc_encode (GstSpeexEnc * enc, gboolean flush);
150
151 static void
152 gst_speex_enc_setup_interfaces (GType speexenc_type)
153 {
154   static const GInterfaceInfo tag_setter_info = { NULL, NULL, NULL };
155   const GInterfaceInfo preset_interface_info = {
156     NULL,                       /* interface_init */
157     NULL,                       /* interface_finalize */
158     NULL                        /* interface_data */
159   };
160
161   g_type_add_interface_static (speexenc_type, GST_TYPE_TAG_SETTER,
162       &tag_setter_info);
163   g_type_add_interface_static (speexenc_type, GST_TYPE_PRESET,
164       &preset_interface_info);
165
166   GST_DEBUG_CATEGORY_INIT (speexenc_debug, "speexenc", 0, "Speex encoder");
167 }
168
169 GST_BOILERPLATE_FULL (GstSpeexEnc, gst_speex_enc, GstElement, GST_TYPE_ELEMENT,
170     gst_speex_enc_setup_interfaces);
171
172 static void
173 gst_speex_enc_base_init (gpointer g_class)
174 {
175   GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
176
177   gst_element_class_add_pad_template (element_class,
178       gst_static_pad_template_get (&src_factory));
179   gst_element_class_add_pad_template (element_class,
180       gst_static_pad_template_get (&sink_factory));
181   gst_element_class_set_details_simple (element_class, "Speex audio encoder",
182       "Codec/Encoder/Audio",
183       "Encodes audio in Speex format", "Wim Taymans <wim@fluendo.com>");
184 }
185
186 static void
187 gst_speex_enc_class_init (GstSpeexEncClass * klass)
188 {
189   GObjectClass *gobject_class;
190   GstElementClass *gstelement_class;
191
192   gobject_class = (GObjectClass *) klass;
193   gstelement_class = (GstElementClass *) klass;
194
195   gobject_class->set_property = gst_speex_enc_set_property;
196   gobject_class->get_property = gst_speex_enc_get_property;
197
198   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_QUALITY,
199       g_param_spec_float ("quality", "Quality", "Encoding quality",
200           0.0, 10.0, DEFAULT_QUALITY, G_PARAM_READWRITE));
201   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_BITRATE,
202       g_param_spec_int ("bitrate", "Encoding Bit-rate",
203           "Specify an encoding bit-rate (in bps). (0 = automatic)",
204           0, G_MAXINT, DEFAULT_BITRATE, G_PARAM_READWRITE));
205   g_object_class_install_property (gobject_class, PROP_MODE,
206       g_param_spec_enum ("mode", "Mode", "The encoding mode",
207           GST_TYPE_SPEEX_ENC_MODE, GST_SPEEX_ENC_MODE_AUTO,
208           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
209   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_VBR,
210       g_param_spec_boolean ("vbr", "VBR",
211           "Enable variable bit-rate", DEFAULT_VBR, G_PARAM_READWRITE));
212   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_ABR,
213       g_param_spec_int ("abr", "ABR",
214           "Enable average bit-rate (0 = disabled)",
215           0, G_MAXINT, DEFAULT_ABR, G_PARAM_READWRITE));
216   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_VAD,
217       g_param_spec_boolean ("vad", "VAD",
218           "Enable voice activity detection", DEFAULT_VAD, G_PARAM_READWRITE));
219   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_DTX,
220       g_param_spec_boolean ("dtx", "DTX",
221           "Enable discontinuous transmission", DEFAULT_DTX, G_PARAM_READWRITE));
222   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_COMPLEXITY,
223       g_param_spec_int ("complexity", "Complexity",
224           "Set encoding complexity",
225           0, G_MAXINT, DEFAULT_COMPLEXITY, G_PARAM_READWRITE));
226   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_NFRAMES,
227       g_param_spec_int ("nframes", "NFrames",
228           "Number of frames per buffer",
229           0, G_MAXINT, DEFAULT_NFRAMES, G_PARAM_READWRITE));
230   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_LAST_MESSAGE,
231       g_param_spec_string ("last-message", "last-message",
232           "The last status message", NULL, G_PARAM_READABLE));
233
234   gobject_class->finalize = gst_speex_enc_finalize;
235
236   gstelement_class->change_state =
237       GST_DEBUG_FUNCPTR (gst_speex_enc_change_state);
238 }
239
240 static void
241 gst_speex_enc_finalize (GObject * object)
242 {
243   GstSpeexEnc *enc;
244
245   enc = GST_SPEEX_ENC (object);
246
247   g_free (enc->last_message);
248   g_object_unref (enc->adapter);
249
250   G_OBJECT_CLASS (parent_class)->finalize (object);
251 }
252
253 static gboolean
254 gst_speex_enc_sink_setcaps (GstPad * pad, GstCaps * caps)
255 {
256   GstSpeexEnc *enc;
257   GstStructure *structure;
258
259   enc = GST_SPEEX_ENC (GST_PAD_PARENT (pad));
260   enc->setup = FALSE;
261
262   structure = gst_caps_get_structure (caps, 0);
263   gst_structure_get_int (structure, "channels", &enc->channels);
264   gst_structure_get_int (structure, "rate", &enc->rate);
265
266   gst_speex_enc_setup (enc);
267
268   return enc->setup;
269 }
270
271
272 static GstCaps *
273 gst_speex_enc_sink_getcaps (GstPad * pad)
274 {
275   GstCaps *caps = gst_caps_copy (gst_pad_get_pad_template_caps (pad));
276   GstCaps *peercaps = NULL;
277   GstSpeexEnc *enc = GST_SPEEX_ENC (gst_pad_get_parent_element (pad));
278
279   peercaps = gst_pad_peer_get_caps (enc->srcpad);
280
281   if (peercaps) {
282     if (!gst_caps_is_empty (peercaps) && !gst_caps_is_any (peercaps)) {
283       GstStructure *ps = gst_caps_get_structure (peercaps, 0);
284       GstStructure *s = gst_caps_get_structure (caps, 0);
285       gint rate, channels;
286
287       if (gst_structure_get_int (ps, "rate", &rate)) {
288         gst_structure_fixate_field_nearest_int (s, "rate", rate);
289       }
290
291       if (gst_structure_get_int (ps, "channels", &channels)) {
292         gst_structure_fixate_field_nearest_int (s, "channels", channels);
293       }
294     }
295     gst_caps_unref (peercaps);
296   }
297
298   gst_object_unref (enc);
299
300   return caps;
301 }
302
303
304 static gboolean
305 gst_speex_enc_convert_src (GstPad * pad, GstFormat src_format, gint64 src_value,
306     GstFormat * dest_format, gint64 * dest_value)
307 {
308   gboolean res = TRUE;
309   GstSpeexEnc *enc;
310   gint64 avg;
311
312   enc = GST_SPEEX_ENC (GST_PAD_PARENT (pad));
313
314   if (enc->samples_in == 0 || enc->bytes_out == 0 || enc->rate == 0)
315     return FALSE;
316
317   avg = (enc->bytes_out * enc->rate) / (enc->samples_in);
318
319   switch (src_format) {
320     case GST_FORMAT_BYTES:
321       switch (*dest_format) {
322         case GST_FORMAT_TIME:
323           *dest_value = src_value * GST_SECOND / avg;
324           break;
325         default:
326           res = FALSE;
327       }
328       break;
329     case GST_FORMAT_TIME:
330       switch (*dest_format) {
331         case GST_FORMAT_BYTES:
332           *dest_value = src_value * avg / GST_SECOND;
333           break;
334         default:
335           res = FALSE;
336       }
337       break;
338     default:
339       res = FALSE;
340   }
341   return res;
342 }
343
344 static gboolean
345 gst_speex_enc_convert_sink (GstPad * pad, GstFormat src_format,
346     gint64 src_value, GstFormat * dest_format, gint64 * dest_value)
347 {
348   gboolean res = TRUE;
349   guint scale = 1;
350   gint bytes_per_sample;
351   GstSpeexEnc *enc;
352
353   enc = GST_SPEEX_ENC (GST_PAD_PARENT (pad));
354
355   bytes_per_sample = enc->channels * 2;
356
357   switch (src_format) {
358     case GST_FORMAT_BYTES:
359       switch (*dest_format) {
360         case GST_FORMAT_DEFAULT:
361           if (bytes_per_sample == 0)
362             return FALSE;
363           *dest_value = src_value / bytes_per_sample;
364           break;
365         case GST_FORMAT_TIME:
366         {
367           gint byterate = bytes_per_sample * enc->rate;
368
369           if (byterate == 0)
370             return FALSE;
371           *dest_value = src_value * GST_SECOND / byterate;
372           break;
373         }
374         default:
375           res = FALSE;
376       }
377       break;
378     case GST_FORMAT_DEFAULT:
379       switch (*dest_format) {
380         case GST_FORMAT_BYTES:
381           *dest_value = src_value * bytes_per_sample;
382           break;
383         case GST_FORMAT_TIME:
384           if (enc->rate == 0)
385             return FALSE;
386           *dest_value = src_value * GST_SECOND / enc->rate;
387           break;
388         default:
389           res = FALSE;
390       }
391       break;
392     case GST_FORMAT_TIME:
393       switch (*dest_format) {
394         case GST_FORMAT_BYTES:
395           scale = bytes_per_sample;
396           /* fallthrough */
397         case GST_FORMAT_DEFAULT:
398           *dest_value = src_value * scale * enc->rate / GST_SECOND;
399           break;
400         default:
401           res = FALSE;
402       }
403       break;
404     default:
405       res = FALSE;
406   }
407   return res;
408 }
409
410 static gint64
411 gst_speex_enc_get_latency (GstSpeexEnc * enc)
412 {
413   /* See the Speex manual section "Latency and algorithmic delay" */
414   if (enc->rate == 8000)
415     return 30 * GST_MSECOND;
416   else
417     return 34 * 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 = speex_lib_get_mode (SPEEX_MODEID_UWB);
651       break;
652     case GST_SPEEX_ENC_MODE_WB:
653       GST_LOG_OBJECT (enc, "configuring for requested WB mode");
654       enc->speex_mode = speex_lib_get_mode (SPEEX_MODEID_WB);
655       break;
656     case GST_SPEEX_ENC_MODE_NB:
657       GST_LOG_OBJECT (enc, "configuring for requested NB mode");
658       enc->speex_mode = speex_lib_get_mode (SPEEX_MODEID_NB);
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 = speex_lib_get_mode (SPEEX_MODEID_UWB);
671     } else {
672       if (enc->speex_mode != speex_lib_get_mode (SPEEX_MODEID_UWB)) {
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 = speex_lib_get_mode (SPEEX_MODEID_WB);
681     } else {
682       if (enc->speex_mode != speex_lib_get_mode (SPEEX_MODEID_WB)) {
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 = speex_lib_get_mode (SPEEX_MODEID_NB);
691     } else {
692       if (enc->speex_mode != speex_lib_get_mode (SPEEX_MODEID_NB)) {
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       if (enc->setup)
851         gst_speex_enc_encode (enc, TRUE);
852       res = gst_pad_event_default (pad, event);
853       break;
854     case GST_EVENT_TAG:
855     {
856       if (enc->tags) {
857         GstTagList *list;
858
859         gst_event_parse_tag (event, &list);
860         gst_tag_list_insert (enc->tags, list,
861             gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (enc)));
862       } else {
863         g_assert_not_reached ();
864       }
865       res = gst_pad_event_default (pad, event);
866       break;
867     }
868     default:
869       res = gst_pad_event_default (pad, event);
870       break;
871   }
872
873   gst_object_unref (enc);
874
875   return res;
876 }
877
878 static GstFlowReturn
879 gst_speex_enc_encode (GstSpeexEnc * enc, gboolean flush)
880 {
881   gint frame_size = enc->frame_size;
882   gint bytes = frame_size * 2 * enc->channels;
883   GstFlowReturn ret = GST_FLOW_OK;
884
885   if (flush && gst_adapter_available (enc->adapter) % bytes != 0) {
886     guint diff = gst_adapter_available (enc->adapter) % bytes;
887     GstBuffer *buf = gst_buffer_new_and_alloc (diff);
888
889     memset (GST_BUFFER_DATA (buf), 0, diff);
890     gst_adapter_push (enc->adapter, buf);
891   }
892
893   while (gst_adapter_available (enc->adapter) >= bytes) {
894     gint16 *data;
895     gint outsize, written;
896     GstBuffer *outbuf;
897
898     data = (gint16 *) gst_adapter_take (enc->adapter, bytes);
899
900     enc->samples_in += frame_size;
901
902     GST_DEBUG_OBJECT (enc, "encoding %d samples (%d bytes)", frame_size, bytes);
903
904     if (enc->channels == 2) {
905       speex_encode_stereo_int (data, frame_size, &enc->bits);
906     }
907     speex_encode_int (enc->state, data, &enc->bits);
908
909     g_free (data);
910
911     enc->frameno++;
912     enc->frameno_out++;
913
914     if ((enc->frameno % enc->nframes) != 0)
915       continue;
916
917     speex_bits_insert_terminator (&enc->bits);
918     outsize = speex_bits_nbytes (&enc->bits);
919
920     ret = gst_pad_alloc_buffer_and_set_caps (enc->srcpad,
921         GST_BUFFER_OFFSET_NONE, outsize, GST_PAD_CAPS (enc->srcpad), &outbuf);
922
923     if ((GST_FLOW_OK != ret))
924       goto done;
925
926     written = speex_bits_write (&enc->bits,
927         (gchar *) GST_BUFFER_DATA (outbuf), outsize);
928     g_assert (written == outsize);
929     speex_bits_reset (&enc->bits);
930
931     GST_BUFFER_TIMESTAMP (outbuf) = enc->start_ts +
932         gst_util_uint64_scale_int ((enc->frameno_out -
933             enc->nframes) * frame_size - enc->lookahead, GST_SECOND, enc->rate);
934     GST_BUFFER_DURATION (outbuf) =
935         gst_util_uint64_scale_int (frame_size * enc->nframes, GST_SECOND,
936         enc->rate);
937     /* set gp time and granulepos; see gst-plugins-base/ext/ogg/README */
938     GST_BUFFER_OFFSET_END (outbuf) = enc->granulepos_offset +
939         ((enc->frameno_out) * frame_size - enc->lookahead);
940     GST_BUFFER_OFFSET (outbuf) =
941         gst_util_uint64_scale_int (GST_BUFFER_OFFSET_END (outbuf), GST_SECOND,
942         enc->rate);
943
944     ret = gst_speex_enc_push_buffer (enc, outbuf);
945
946     if ((GST_FLOW_OK != ret) && (GST_FLOW_NOT_LINKED != ret))
947       goto done;
948   }
949
950 done:
951
952   return ret;
953 }
954
955 static GstFlowReturn
956 gst_speex_enc_chain (GstPad * pad, GstBuffer * buf)
957 {
958   GstSpeexEnc *enc;
959   GstFlowReturn ret = GST_FLOW_OK;
960
961   enc = GST_SPEEX_ENC (GST_PAD_PARENT (pad));
962
963   if (!enc->setup)
964     goto not_setup;
965
966   if (!enc->header_sent) {
967     /* Speex streams begin with two headers; the initial header (with
968        most of the codec setup parameters) which is mandated by the Ogg
969        bitstream spec.  The second header holds any comment fields.
970        We merely need to make the headers, then pass them to libspeex 
971        one at a time; libspeex handles the additional Ogg bitstream 
972        constraints */
973     GstBuffer *buf1, *buf2;
974     GstCaps *caps;
975     guchar *data;
976     gint data_len;
977
978     /* create header buffer */
979     data = (guint8 *) speex_header_to_packet (&enc->header, &data_len);
980     buf1 = gst_speex_enc_buffer_from_data (enc, data, data_len, 0);
981     free (data);
982
983     /* create comment buffer */
984     buf2 = gst_speex_enc_create_metadata_buffer (enc);
985
986     /* mark and put on caps */
987     caps = gst_pad_get_caps (enc->srcpad);
988     caps = gst_speex_enc_set_header_on_caps (caps, buf1, buf2);
989
990     gst_caps_set_simple (caps,
991         "rate", G_TYPE_INT, enc->rate,
992         "channels", G_TYPE_INT, enc->channels, NULL);
993
994     /* negotiate with these caps */
995     GST_DEBUG_OBJECT (enc, "here are the caps: %" GST_PTR_FORMAT, caps);
996     gst_pad_set_caps (enc->srcpad, caps);
997
998     gst_buffer_set_caps (buf1, caps);
999     gst_buffer_set_caps (buf2, caps);
1000     gst_caps_unref (caps);
1001
1002     /* push out buffers */
1003     ret = gst_speex_enc_push_buffer (enc, buf1);
1004
1005     if (ret != GST_FLOW_OK) {
1006       gst_buffer_unref (buf2);
1007       goto done;
1008     }
1009
1010     ret = gst_speex_enc_push_buffer (enc, buf2);
1011
1012     if (ret != GST_FLOW_OK)
1013       goto done;
1014
1015     speex_bits_reset (&enc->bits);
1016
1017     enc->header_sent = TRUE;
1018   }
1019
1020   /* Save the timestamp of the first buffer. This will be later
1021    * used as offset for all following buffers */
1022   if (enc->start_ts == GST_CLOCK_TIME_NONE) {
1023     if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)) {
1024       enc->start_ts = GST_BUFFER_TIMESTAMP (buf);
1025       enc->granulepos_offset = gst_util_uint64_scale
1026           (GST_BUFFER_TIMESTAMP (buf), enc->rate, GST_SECOND);
1027     } else {
1028       enc->start_ts = 0;
1029       enc->granulepos_offset = 0;
1030     }
1031   }
1032
1033   /* Check if we have a continous stream, if not drop some samples or the buffer or
1034    * insert some silence samples */
1035   if (enc->next_ts != GST_CLOCK_TIME_NONE &&
1036       GST_BUFFER_TIMESTAMP (buf) < enc->next_ts) {
1037     guint64 diff = enc->next_ts - GST_BUFFER_TIMESTAMP (buf);
1038     guint64 diff_bytes;
1039
1040     GST_WARNING_OBJECT (enc, "Buffer is older than previous "
1041         "timestamp + duration (%" GST_TIME_FORMAT "< %" GST_TIME_FORMAT
1042         "), cannot handle. Clipping buffer.",
1043         GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
1044         GST_TIME_ARGS (enc->next_ts));
1045
1046     diff_bytes = GST_CLOCK_TIME_TO_FRAMES (diff, enc->rate) * enc->channels * 2;
1047     if (diff_bytes >= GST_BUFFER_SIZE (buf)) {
1048       gst_buffer_unref (buf);
1049       return GST_FLOW_OK;
1050     }
1051     buf = gst_buffer_make_metadata_writable (buf);
1052     GST_BUFFER_DATA (buf) += diff_bytes;
1053     GST_BUFFER_SIZE (buf) -= diff_bytes;
1054
1055     GST_BUFFER_TIMESTAMP (buf) += diff;
1056     if (GST_BUFFER_DURATION_IS_VALID (buf))
1057       GST_BUFFER_DURATION (buf) -= diff;
1058   }
1059
1060   if (enc->next_ts != GST_CLOCK_TIME_NONE
1061       && GST_BUFFER_TIMESTAMP_IS_VALID (buf)) {
1062     guint64 max_diff =
1063         gst_util_uint64_scale (enc->frame_size, GST_SECOND, enc->rate);
1064
1065     if (GST_BUFFER_TIMESTAMP (buf) != enc->next_ts &&
1066         GST_BUFFER_TIMESTAMP (buf) - enc->next_ts > max_diff) {
1067       GST_WARNING_OBJECT (enc,
1068           "Discontinuity detected: %" G_GUINT64_FORMAT " > %" G_GUINT64_FORMAT,
1069           GST_BUFFER_TIMESTAMP (buf) - enc->next_ts, max_diff);
1070
1071       gst_speex_enc_encode (enc, TRUE);
1072
1073       enc->frameno_out = 0;
1074       enc->start_ts = GST_BUFFER_TIMESTAMP (buf);
1075       enc->granulepos_offset = gst_util_uint64_scale
1076           (GST_BUFFER_TIMESTAMP (buf), enc->rate, GST_SECOND);
1077     }
1078   }
1079
1080   if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)
1081       && GST_BUFFER_DURATION_IS_VALID (buf))
1082     enc->next_ts = GST_BUFFER_TIMESTAMP (buf) + GST_BUFFER_DURATION (buf);
1083   else
1084     enc->next_ts = GST_CLOCK_TIME_NONE;
1085
1086   GST_DEBUG_OBJECT (enc, "received buffer of %u bytes", GST_BUFFER_SIZE (buf));
1087
1088   /* push buffer to adapter */
1089   gst_adapter_push (enc->adapter, buf);
1090   buf = NULL;
1091
1092   ret = gst_speex_enc_encode (enc, FALSE);
1093
1094 done:
1095
1096   if (buf)
1097     gst_buffer_unref (buf);
1098
1099   return ret;
1100
1101   /* ERRORS */
1102 not_setup:
1103   {
1104     GST_ELEMENT_ERROR (enc, CORE, NEGOTIATION, (NULL),
1105         ("encoder not initialized (input is not audio?)"));
1106     ret = GST_FLOW_NOT_NEGOTIATED;
1107     goto done;
1108   }
1109
1110 }
1111
1112
1113 static void
1114 gst_speex_enc_get_property (GObject * object, guint prop_id, GValue * value,
1115     GParamSpec * pspec)
1116 {
1117   GstSpeexEnc *enc;
1118
1119   enc = GST_SPEEX_ENC (object);
1120
1121   switch (prop_id) {
1122     case PROP_QUALITY:
1123       g_value_set_float (value, enc->quality);
1124       break;
1125     case PROP_BITRATE:
1126       g_value_set_int (value, enc->bitrate);
1127       break;
1128     case PROP_MODE:
1129       g_value_set_enum (value, enc->mode);
1130       break;
1131     case PROP_VBR:
1132       g_value_set_boolean (value, enc->vbr);
1133       break;
1134     case PROP_ABR:
1135       g_value_set_int (value, enc->abr);
1136       break;
1137     case PROP_VAD:
1138       g_value_set_boolean (value, enc->vad);
1139       break;
1140     case PROP_DTX:
1141       g_value_set_boolean (value, enc->dtx);
1142       break;
1143     case PROP_COMPLEXITY:
1144       g_value_set_int (value, enc->complexity);
1145       break;
1146     case PROP_NFRAMES:
1147       g_value_set_int (value, enc->nframes);
1148       break;
1149     case PROP_LAST_MESSAGE:
1150       g_value_set_string (value, enc->last_message);
1151       break;
1152     default:
1153       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1154       break;
1155   }
1156 }
1157
1158 static void
1159 gst_speex_enc_set_property (GObject * object, guint prop_id,
1160     const GValue * value, GParamSpec * pspec)
1161 {
1162   GstSpeexEnc *enc;
1163
1164   enc = GST_SPEEX_ENC (object);
1165
1166   switch (prop_id) {
1167     case PROP_QUALITY:
1168       enc->quality = g_value_get_float (value);
1169       break;
1170     case PROP_BITRATE:
1171       enc->bitrate = g_value_get_int (value);
1172       break;
1173     case PROP_MODE:
1174       enc->mode = g_value_get_enum (value);
1175       break;
1176     case PROP_VBR:
1177       enc->vbr = g_value_get_boolean (value);
1178       break;
1179     case PROP_ABR:
1180       enc->abr = g_value_get_int (value);
1181       break;
1182     case PROP_VAD:
1183       enc->vad = g_value_get_boolean (value);
1184       break;
1185     case PROP_DTX:
1186       enc->dtx = g_value_get_boolean (value);
1187       break;
1188     case PROP_COMPLEXITY:
1189       enc->complexity = g_value_get_int (value);
1190       break;
1191     case PROP_NFRAMES:
1192       enc->nframes = g_value_get_int (value);
1193       break;
1194     default:
1195       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1196       break;
1197   }
1198 }
1199
1200 static GstStateChangeReturn
1201 gst_speex_enc_change_state (GstElement * element, GstStateChange transition)
1202 {
1203   GstSpeexEnc *enc = GST_SPEEX_ENC (element);
1204   GstStateChangeReturn res;
1205
1206   switch (transition) {
1207     case GST_STATE_CHANGE_NULL_TO_READY:
1208       enc->tags = gst_tag_list_new ();
1209       break;
1210     case GST_STATE_CHANGE_READY_TO_PAUSED:
1211       speex_bits_init (&enc->bits);
1212       enc->frameno = 0;
1213       enc->frameno_out = 0;
1214       enc->samples_in = 0;
1215       enc->start_ts = GST_CLOCK_TIME_NONE;
1216       enc->next_ts = GST_CLOCK_TIME_NONE;
1217       enc->granulepos_offset = 0;
1218       break;
1219     case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
1220       /* fall through */
1221     default:
1222       break;
1223   }
1224
1225   res = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1226   if (res == GST_STATE_CHANGE_FAILURE)
1227     return res;
1228
1229   switch (transition) {
1230     case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
1231       break;
1232     case GST_STATE_CHANGE_PAUSED_TO_READY:
1233       enc->setup = FALSE;
1234       enc->header_sent = FALSE;
1235       if (enc->state) {
1236         speex_encoder_destroy (enc->state);
1237         enc->state = NULL;
1238       }
1239       speex_bits_destroy (&enc->bits);
1240       break;
1241     case GST_STATE_CHANGE_READY_TO_NULL:
1242       gst_tag_list_free (enc->tags);
1243       enc->tags = NULL;
1244     default:
1245       break;
1246   }
1247
1248   return res;
1249 }