Merge branch 'master' into 0.11
[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 #define FORMAT_STR GST_AUDIO_NE(S16)
56
57 static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
58     GST_PAD_SINK,
59     GST_PAD_ALWAYS,
60     GST_STATIC_CAPS ("audio/x-raw, "
61         "format = (string) " FORMAT_STR ", "
62         "rate = (int) [ 6000, 48000 ], " "channels = (int) [ 1, 2 ]")
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 static void gst_speex_enc_finalize (GObject * object);
117
118 static gboolean gst_speex_enc_setup (GstSpeexEnc * enc);
119
120 static void gst_speex_enc_get_property (GObject * object, guint prop_id,
121     GValue * value, GParamSpec * pspec);
122 static void gst_speex_enc_set_property (GObject * object, guint prop_id,
123     const GValue * value, GParamSpec * pspec);
124
125 static GstFlowReturn gst_speex_enc_encode (GstSpeexEnc * enc, GstBuffer * buf);
126
127 static gboolean gst_speex_enc_start (GstAudioEncoder * enc);
128 static gboolean gst_speex_enc_stop (GstAudioEncoder * enc);
129 static gboolean gst_speex_enc_set_format (GstAudioEncoder * enc,
130     GstAudioInfo * info);
131 static GstFlowReturn gst_speex_enc_handle_frame (GstAudioEncoder * enc,
132     GstBuffer * in_buf);
133 static gboolean gst_speex_enc_sink_event (GstAudioEncoder * enc,
134     GstEvent * event);
135 static GstFlowReturn
136 gst_speex_enc_pre_push (GstAudioEncoder * benc, GstBuffer ** buffer);
137
138 #define gst_speex_enc_parent_class parent_class
139 G_DEFINE_TYPE_WITH_CODE (GstSpeexEnc, gst_speex_enc, GST_TYPE_AUDIO_ENCODER,
140     G_IMPLEMENT_INTERFACE (GST_TYPE_TAG_SETTER, NULL);
141     G_IMPLEMENT_INTERFACE (GST_TYPE_PRESET, NULL));
142
143 static void
144 gst_speex_enc_class_init (GstSpeexEncClass * klass)
145 {
146   GObjectClass *gobject_class;
147   GstElementClass *gstelement_class;
148   GstAudioEncoderClass *base_class;
149
150   gobject_class = (GObjectClass *) klass;
151   gstelement_class = (GstElementClass *) klass;
152   base_class = (GstAudioEncoderClass *) klass;
153
154   gobject_class->finalize = gst_speex_enc_finalize;
155   gobject_class->set_property = gst_speex_enc_set_property;
156   gobject_class->get_property = gst_speex_enc_get_property;
157
158   base_class->start = GST_DEBUG_FUNCPTR (gst_speex_enc_start);
159   base_class->stop = GST_DEBUG_FUNCPTR (gst_speex_enc_stop);
160   base_class->set_format = GST_DEBUG_FUNCPTR (gst_speex_enc_set_format);
161   base_class->handle_frame = GST_DEBUG_FUNCPTR (gst_speex_enc_handle_frame);
162   base_class->event = GST_DEBUG_FUNCPTR (gst_speex_enc_sink_event);
163   base_class->pre_push = GST_DEBUG_FUNCPTR (gst_speex_enc_pre_push);
164
165   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_QUALITY,
166       g_param_spec_float ("quality", "Quality", "Encoding quality",
167           0.0, 10.0, DEFAULT_QUALITY,
168           G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
169   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_BITRATE,
170       g_param_spec_int ("bitrate", "Encoding Bit-rate",
171           "Specify an encoding bit-rate (in bps). (0 = automatic)",
172           0, G_MAXINT, DEFAULT_BITRATE,
173           G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
174   g_object_class_install_property (gobject_class, PROP_MODE,
175       g_param_spec_enum ("mode", "Mode", "The encoding mode",
176           GST_TYPE_SPEEX_ENC_MODE, GST_SPEEX_ENC_MODE_AUTO,
177           G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
178   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_VBR,
179       g_param_spec_boolean ("vbr", "VBR",
180           "Enable variable bit-rate", DEFAULT_VBR,
181           G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
182   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_ABR,
183       g_param_spec_int ("abr", "ABR",
184           "Enable average bit-rate (0 = disabled)",
185           0, G_MAXINT, DEFAULT_ABR,
186           G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
187   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_VAD,
188       g_param_spec_boolean ("vad", "VAD",
189           "Enable voice activity detection", DEFAULT_VAD,
190           G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
191   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_DTX,
192       g_param_spec_boolean ("dtx", "DTX",
193           "Enable discontinuous transmission", DEFAULT_DTX,
194           G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
195   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_COMPLEXITY,
196       g_param_spec_int ("complexity", "Complexity",
197           "Set encoding complexity",
198           0, G_MAXINT, DEFAULT_COMPLEXITY,
199           G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
200   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_NFRAMES,
201       g_param_spec_int ("nframes", "NFrames",
202           "Number of frames per buffer",
203           0, G_MAXINT, DEFAULT_NFRAMES,
204           G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
205   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_LAST_MESSAGE,
206       g_param_spec_string ("last-message", "last-message",
207           "The last status message", NULL,
208           G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
209
210   gst_element_class_add_pad_template (gstelement_class,
211       gst_static_pad_template_get (&src_factory));
212   gst_element_class_add_pad_template (gstelement_class,
213       gst_static_pad_template_get (&sink_factory));
214   gst_element_class_set_details_simple (gstelement_class, "Speex audio encoder",
215       "Codec/Encoder/Audio",
216       "Encodes audio in Speex format", "Wim Taymans <wim@fluendo.com>");
217
218   GST_DEBUG_CATEGORY_INIT (speexenc_debug, "speexenc", 0, "Speex encoder");
219 }
220
221 static void
222 gst_speex_enc_finalize (GObject * object)
223 {
224   GstSpeexEnc *enc;
225
226   enc = GST_SPEEX_ENC (object);
227
228   g_free (enc->last_message);
229
230   G_OBJECT_CLASS (parent_class)->finalize (object);
231 }
232
233 static void
234 gst_speex_enc_init (GstSpeexEnc * enc)
235 {
236   GstAudioEncoder *benc = GST_AUDIO_ENCODER (enc);
237
238   /* arrange granulepos marking (and required perfect ts) */
239   gst_audio_encoder_set_mark_granule (benc, TRUE);
240   gst_audio_encoder_set_perfect_timestamp (benc, TRUE);
241 }
242
243 static gboolean
244 gst_speex_enc_start (GstAudioEncoder * benc)
245 {
246   GstSpeexEnc *enc = GST_SPEEX_ENC (benc);
247
248   GST_DEBUG_OBJECT (enc, "start");
249   speex_bits_init (&enc->bits);
250   enc->tags = gst_tag_list_new ();
251   enc->header_sent = FALSE;
252
253   return TRUE;
254 }
255
256 static gboolean
257 gst_speex_enc_stop (GstAudioEncoder * benc)
258 {
259   GstSpeexEnc *enc = GST_SPEEX_ENC (benc);
260
261   GST_DEBUG_OBJECT (enc, "stop");
262   enc->header_sent = FALSE;
263   if (enc->state) {
264     speex_encoder_destroy (enc->state);
265     enc->state = NULL;
266   }
267   speex_bits_destroy (&enc->bits);
268   gst_tag_list_free (enc->tags);
269   enc->tags = NULL;
270   g_slist_foreach (enc->headers, (GFunc) gst_buffer_unref, NULL);
271   enc->headers = NULL;
272
273   return TRUE;
274 }
275
276 static gint64
277 gst_speex_enc_get_latency (GstSpeexEnc * enc)
278 {
279   /* See the Speex manual section "Latency and algorithmic delay" */
280   if (enc->rate == 8000)
281     return 30 * GST_MSECOND;
282   else
283     return 34 * GST_MSECOND;
284 }
285
286 static gboolean
287 gst_speex_enc_set_format (GstAudioEncoder * benc, GstAudioInfo * info)
288 {
289   GstSpeexEnc *enc;
290
291   enc = GST_SPEEX_ENC (benc);
292
293   enc->channels = GST_AUDIO_INFO_CHANNELS (info);
294   enc->rate = GST_AUDIO_INFO_RATE (info);
295
296   /* handle reconfigure */
297   if (enc->state) {
298     speex_encoder_destroy (enc->state);
299     enc->state = NULL;
300   }
301
302   if (!gst_speex_enc_setup (enc))
303     return FALSE;
304
305   /* feedback to base class */
306   gst_audio_encoder_set_latency (benc,
307       gst_speex_enc_get_latency (enc), gst_speex_enc_get_latency (enc));
308   gst_audio_encoder_set_lookahead (benc, enc->lookahead);
309
310   if (enc->nframes == 0) {
311     /* as many frames as available input allows */
312     gst_audio_encoder_set_frame_samples_min (benc, enc->frame_size);
313     gst_audio_encoder_set_frame_samples_max (benc, enc->frame_size);
314     gst_audio_encoder_set_frame_max (benc, 0);
315   } else {
316     /* exactly as many frames as configured */
317     gst_audio_encoder_set_frame_samples_min (benc,
318         enc->frame_size * enc->nframes);
319     gst_audio_encoder_set_frame_samples_max (benc,
320         enc->frame_size * enc->nframes);
321     gst_audio_encoder_set_frame_max (benc, 1);
322   }
323
324   return TRUE;
325 }
326
327 static GstBuffer *
328 gst_speex_enc_create_metadata_buffer (GstSpeexEnc * enc)
329 {
330   const GstTagList *user_tags;
331   GstTagList *merged_tags;
332   GstBuffer *comments = NULL;
333
334   user_tags = gst_tag_setter_get_tag_list (GST_TAG_SETTER (enc));
335
336   GST_DEBUG_OBJECT (enc, "upstream tags = %" GST_PTR_FORMAT, enc->tags);
337   GST_DEBUG_OBJECT (enc, "user-set tags = %" GST_PTR_FORMAT, user_tags);
338
339   /* gst_tag_list_merge() will handle NULL for either or both lists fine */
340   merged_tags = gst_tag_list_merge (user_tags, enc->tags,
341       gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (enc)));
342
343   if (merged_tags == NULL)
344     merged_tags = gst_tag_list_new ();
345
346   GST_DEBUG_OBJECT (enc, "merged   tags = %" GST_PTR_FORMAT, merged_tags);
347   comments = gst_tag_list_to_vorbiscomment_buffer (merged_tags, NULL,
348       0, "Encoded with GStreamer Speexenc");
349   gst_tag_list_free (merged_tags);
350
351   GST_BUFFER_OFFSET (comments) = 0;
352   GST_BUFFER_OFFSET_END (comments) = 0;
353
354   return comments;
355 }
356
357 static void
358 gst_speex_enc_set_last_msg (GstSpeexEnc * enc, const gchar * msg)
359 {
360   g_free (enc->last_message);
361   enc->last_message = g_strdup (msg);
362   GST_WARNING_OBJECT (enc, "%s", msg);
363   g_object_notify (G_OBJECT (enc), "last-message");
364 }
365
366 static gboolean
367 gst_speex_enc_setup (GstSpeexEnc * enc)
368 {
369   switch (enc->mode) {
370     case GST_SPEEX_ENC_MODE_UWB:
371       GST_LOG_OBJECT (enc, "configuring for requested UWB mode");
372       enc->speex_mode = speex_lib_get_mode (SPEEX_MODEID_UWB);
373       break;
374     case GST_SPEEX_ENC_MODE_WB:
375       GST_LOG_OBJECT (enc, "configuring for requested WB mode");
376       enc->speex_mode = speex_lib_get_mode (SPEEX_MODEID_WB);
377       break;
378     case GST_SPEEX_ENC_MODE_NB:
379       GST_LOG_OBJECT (enc, "configuring for requested NB mode");
380       enc->speex_mode = speex_lib_get_mode (SPEEX_MODEID_NB);
381       break;
382     case GST_SPEEX_ENC_MODE_AUTO:
383       /* fall through */
384       GST_LOG_OBJECT (enc, "finding best mode");
385     default:
386       break;
387   }
388
389   if (enc->rate > 25000) {
390     if (enc->mode == GST_SPEEX_ENC_MODE_AUTO) {
391       GST_LOG_OBJECT (enc, "selected UWB mode for samplerate %d", enc->rate);
392       enc->speex_mode = speex_lib_get_mode (SPEEX_MODEID_UWB);
393     } else {
394       if (enc->speex_mode != speex_lib_get_mode (SPEEX_MODEID_UWB)) {
395         gst_speex_enc_set_last_msg (enc,
396             "Warning: suggest to use ultra wide band mode for this rate");
397       }
398     }
399   } else if (enc->rate > 12500) {
400     if (enc->mode == GST_SPEEX_ENC_MODE_AUTO) {
401       GST_LOG_OBJECT (enc, "selected WB mode for samplerate %d", enc->rate);
402       enc->speex_mode = speex_lib_get_mode (SPEEX_MODEID_WB);
403     } else {
404       if (enc->speex_mode != speex_lib_get_mode (SPEEX_MODEID_WB)) {
405         gst_speex_enc_set_last_msg (enc,
406             "Warning: suggest to use wide band mode for this rate");
407       }
408     }
409   } else {
410     if (enc->mode == GST_SPEEX_ENC_MODE_AUTO) {
411       GST_LOG_OBJECT (enc, "selected NB mode for samplerate %d", enc->rate);
412       enc->speex_mode = speex_lib_get_mode (SPEEX_MODEID_NB);
413     } else {
414       if (enc->speex_mode != speex_lib_get_mode (SPEEX_MODEID_NB)) {
415         gst_speex_enc_set_last_msg (enc,
416             "Warning: suggest to use narrow band mode for this rate");
417       }
418     }
419   }
420
421   if (enc->rate != 8000 && enc->rate != 16000 && enc->rate != 32000) {
422     gst_speex_enc_set_last_msg (enc,
423         "Warning: speex is optimized for 8, 16 and 32 KHz");
424   }
425
426   speex_init_header (&enc->header, enc->rate, 1, enc->speex_mode);
427   enc->header.frames_per_packet = enc->nframes;
428   enc->header.vbr = enc->vbr;
429   enc->header.nb_channels = enc->channels;
430
431   /*Initialize Speex encoder */
432   enc->state = speex_encoder_init (enc->speex_mode);
433
434   speex_encoder_ctl (enc->state, SPEEX_GET_FRAME_SIZE, &enc->frame_size);
435   speex_encoder_ctl (enc->state, SPEEX_SET_COMPLEXITY, &enc->complexity);
436   speex_encoder_ctl (enc->state, SPEEX_SET_SAMPLING_RATE, &enc->rate);
437
438   if (enc->vbr)
439     speex_encoder_ctl (enc->state, SPEEX_SET_VBR_QUALITY, &enc->quality);
440   else {
441     gint tmp = floor (enc->quality);
442
443     speex_encoder_ctl (enc->state, SPEEX_SET_QUALITY, &tmp);
444   }
445   if (enc->bitrate) {
446     if (enc->quality >= 0.0 && enc->vbr) {
447       gst_speex_enc_set_last_msg (enc,
448           "Warning: bitrate option is overriding quality");
449     }
450     speex_encoder_ctl (enc->state, SPEEX_SET_BITRATE, &enc->bitrate);
451   }
452   if (enc->vbr) {
453     gint tmp = 1;
454
455     speex_encoder_ctl (enc->state, SPEEX_SET_VBR, &tmp);
456   } else if (enc->vad) {
457     gint tmp = 1;
458
459     speex_encoder_ctl (enc->state, SPEEX_SET_VAD, &tmp);
460   }
461
462   if (enc->dtx) {
463     gint tmp = 1;
464
465     speex_encoder_ctl (enc->state, SPEEX_SET_DTX, &tmp);
466   }
467
468   if (enc->dtx && !(enc->vbr || enc->abr || enc->vad)) {
469     gst_speex_enc_set_last_msg (enc,
470         "Warning: dtx is useless without vad, vbr or abr");
471   } else if ((enc->vbr || enc->abr) && (enc->vad)) {
472     gst_speex_enc_set_last_msg (enc,
473         "Warning: vad is already implied by vbr or abr");
474   }
475
476   if (enc->abr) {
477     speex_encoder_ctl (enc->state, SPEEX_SET_ABR, &enc->abr);
478   }
479
480   speex_encoder_ctl (enc->state, SPEEX_GET_LOOKAHEAD, &enc->lookahead);
481
482   GST_LOG_OBJECT (enc, "we have frame size %d, lookahead %d", enc->frame_size,
483       enc->lookahead);
484
485   return TRUE;
486 }
487
488 /* push out the buffer */
489 static GstFlowReturn
490 gst_speex_enc_push_buffer (GstSpeexEnc * enc, GstBuffer * buffer)
491 {
492   GST_DEBUG_OBJECT (enc, "pushing output buffer of size %u",
493       gst_buffer_get_size (buffer));
494
495   return gst_pad_push (GST_AUDIO_ENCODER_SRC_PAD (enc), buffer);
496 }
497
498 static gboolean
499 gst_speex_enc_sink_event (GstAudioEncoder * benc, GstEvent * event)
500 {
501   GstSpeexEnc *enc;
502
503   enc = GST_SPEEX_ENC (benc);
504
505   switch (GST_EVENT_TYPE (event)) {
506     case GST_EVENT_TAG:
507     {
508       if (enc->tags) {
509         GstTagList *list;
510
511         gst_event_parse_tag (event, &list);
512         gst_tag_list_insert (enc->tags, list,
513             gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (enc)));
514       } else {
515         g_assert_not_reached ();
516       }
517       break;
518     }
519     default:
520       break;
521   }
522
523   /* we only peeked, let base class handle it */
524   return FALSE;
525 }
526
527 static GstFlowReturn
528 gst_speex_enc_encode (GstSpeexEnc * enc, GstBuffer * buf)
529 {
530   gint frame_size = enc->frame_size;
531   gint bytes = frame_size * 2 * enc->channels, samples;
532   gint outsize, written, dtx_ret = 0;
533   guint8 *data, *bdata, *outdata;
534   gsize bsize, size;
535   GstBuffer *outbuf;
536   GstFlowReturn ret = GST_FLOW_OK;
537
538   if (G_LIKELY (buf)) {
539     bdata = gst_buffer_map (buf, &bsize, NULL, GST_MAP_READ);
540
541     if (G_UNLIKELY (bsize % bytes)) {
542       GST_DEBUG_OBJECT (enc, "draining; adding silence samples");
543
544       size = ((bsize / bytes) + 1) * bytes;
545       data = g_malloc0 (size);
546       memcpy (data, bdata, bsize);
547       gst_buffer_unmap (buf, bdata, bsize);
548       bdata = NULL;
549     } else {
550       data = bdata;
551       size = bsize;
552     }
553   } else {
554     GST_DEBUG_OBJECT (enc, "nothing to drain");
555     goto done;
556   }
557
558   samples = size / (2 * enc->channels);
559   speex_bits_reset (&enc->bits);
560
561   /* FIXME what about dropped samples if DTS enabled ?? */
562
563   while (size) {
564     GST_DEBUG_OBJECT (enc, "encoding %d samples (%d bytes)", frame_size, bytes);
565
566     if (enc->channels == 2) {
567       speex_encode_stereo_int ((gint16 *) data, frame_size, &enc->bits);
568     }
569     dtx_ret += speex_encode_int (enc->state, (gint16 *) data, &enc->bits);
570
571     data += bytes;
572     size -= bytes;
573   }
574
575   speex_bits_insert_terminator (&enc->bits);
576   outsize = speex_bits_nbytes (&enc->bits);
577
578   if (bdata)
579     gst_buffer_unmap (buf, bdata, bsize);
580
581 #if 0
582   ret = gst_pad_alloc_buffer_and_set_caps (GST_AUDIO_ENCODER_SRC_PAD (enc),
583       GST_BUFFER_OFFSET_NONE, outsize,
584       GST_PAD_CAPS (GST_AUDIO_ENCODER_SRC_PAD (enc)), &outbuf);
585
586   if ((GST_FLOW_OK != ret))
587     goto done;
588 #endif
589   outbuf = gst_buffer_new_allocate (NULL, outsize, 0);
590   outdata = gst_buffer_map (outbuf, NULL, NULL, GST_MAP_WRITE);
591
592   written = speex_bits_write (&enc->bits, (gchar *) outdata, outsize);
593
594   if (G_UNLIKELY (written < outsize)) {
595     GST_ERROR_OBJECT (enc, "short write: %d < %d bytes", written, outsize);
596   } else if (G_UNLIKELY (written > outsize)) {
597     GST_ERROR_OBJECT (enc, "overrun: %d > %d bytes", written, outsize);
598     written = outsize;
599   }
600   gst_buffer_unmap (outbuf, outdata, written);
601
602   if (!dtx_ret)
603     GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_GAP);
604
605   ret = gst_audio_encoder_finish_frame (GST_AUDIO_ENCODER (enc),
606       outbuf, samples);
607
608 done:
609   return ret;
610 }
611
612 /*
613  * (really really) FIXME: move into core (dixit tpm)
614  */
615 /**
616  * _gst_caps_set_buffer_array:
617  * @caps: a #GstCaps
618  * @field: field in caps to set
619  * @buf: header buffers
620  *
621  * Adds given buffers to an array of buffers set as the given @field
622  * on the given @caps.  List of buffer arguments must be NULL-terminated.
623  *
624  * Returns: input caps with a streamheader field added, or NULL if some error
625  */
626 static GstCaps *
627 _gst_caps_set_buffer_array (GstCaps * caps, const gchar * field,
628     GstBuffer * buf, ...)
629 {
630   GstStructure *structure = NULL;
631   va_list va;
632   GValue array = { 0 };
633   GValue value = { 0 };
634
635   g_return_val_if_fail (caps != NULL, NULL);
636   g_return_val_if_fail (gst_caps_is_fixed (caps), NULL);
637   g_return_val_if_fail (field != NULL, NULL);
638
639   caps = gst_caps_make_writable (caps);
640   structure = gst_caps_get_structure (caps, 0);
641
642   g_value_init (&array, GST_TYPE_ARRAY);
643
644   va_start (va, buf);
645   /* put buffers in a fixed list */
646   while (buf) {
647     g_assert (gst_buffer_is_writable (buf));
648
649     /* mark buffer */
650     GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_IN_CAPS);
651
652     g_value_init (&value, GST_TYPE_BUFFER);
653     buf = gst_buffer_copy (buf);
654     GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_IN_CAPS);
655     gst_value_set_buffer (&value, buf);
656     gst_buffer_unref (buf);
657     gst_value_array_append_value (&array, &value);
658     g_value_unset (&value);
659
660     buf = va_arg (va, GstBuffer *);
661   }
662
663   gst_structure_set_value (structure, field, &array);
664   g_value_unset (&array);
665
666   return caps;
667 }
668
669 static GstFlowReturn
670 gst_speex_enc_handle_frame (GstAudioEncoder * benc, GstBuffer * buf)
671 {
672   GstSpeexEnc *enc;
673   GstFlowReturn ret = GST_FLOW_OK;
674
675   enc = GST_SPEEX_ENC (benc);
676
677   if (!enc->header_sent) {
678     /* Speex streams begin with two headers; the initial header (with
679        most of the codec setup parameters) which is mandated by the Ogg
680        bitstream spec.  The second header holds any comment fields.
681        We merely need to make the headers, then pass them to libspeex 
682        one at a time; libspeex handles the additional Ogg bitstream 
683        constraints */
684     GstBuffer *buf1, *buf2;
685     GstCaps *caps;
686     guchar *data;
687     gint data_len;
688
689     /* create header buffer */
690     data = (guint8 *) speex_header_to_packet (&enc->header, &data_len);
691     buf1 = gst_buffer_new_wrapped (data, data_len);
692     GST_BUFFER_OFFSET_END (buf1) = 0;
693     GST_BUFFER_OFFSET (buf1) = 0;
694
695     /* create comment buffer */
696     buf2 = gst_speex_enc_create_metadata_buffer (enc);
697
698     /* mark and put on caps */
699     caps = gst_caps_new_simple ("audio/x-speex", "rate", G_TYPE_INT, enc->rate,
700         "channels", G_TYPE_INT, enc->channels, NULL);
701     caps = _gst_caps_set_buffer_array (caps, "streamheader", buf1, buf2, NULL);
702
703     /* negotiate with these caps */
704     GST_DEBUG_OBJECT (enc, "here are the caps: %" GST_PTR_FORMAT, caps);
705
706     gst_pad_set_caps (GST_AUDIO_ENCODER_SRC_PAD (enc), caps);
707     gst_caps_unref (caps);
708
709     /* push out buffers */
710     /* store buffers for later pre_push sending */
711     g_slist_foreach (enc->headers, (GFunc) gst_buffer_unref, NULL);
712     enc->headers = NULL;
713     GST_DEBUG_OBJECT (enc, "storing header buffers");
714     enc->headers = g_slist_prepend (enc->headers, buf2);
715     enc->headers = g_slist_prepend (enc->headers, buf1);
716
717     enc->header_sent = TRUE;
718   }
719
720   GST_DEBUG_OBJECT (enc, "received buffer %p of %u bytes", buf,
721       buf ? gst_buffer_get_size (buf) : 0);
722
723   ret = gst_speex_enc_encode (enc, buf);
724
725   return ret;
726 }
727
728 static GstFlowReturn
729 gst_speex_enc_pre_push (GstAudioEncoder * benc, GstBuffer ** buffer)
730 {
731   GstSpeexEnc *enc;
732   GstFlowReturn ret = GST_FLOW_OK;
733
734   enc = GST_SPEEX_ENC (benc);
735
736   /* FIXME 0.11 ? get rid of this special ogg stuff and have it
737    * put and use 'codec data' in caps like anything else,
738    * with all the usual out-of-band advantage etc */
739   if (G_UNLIKELY (enc->headers)) {
740     GSList *header = enc->headers;
741
742     /* try to push all of these, if we lose one, might as well lose all */
743     while (header) {
744       if (ret == GST_FLOW_OK)
745         ret = gst_speex_enc_push_buffer (enc, header->data);
746       else
747         gst_speex_enc_push_buffer (enc, header->data);
748       header = g_slist_next (header);
749     }
750
751     g_slist_free (enc->headers);
752     enc->headers = NULL;
753   }
754
755   return ret;
756 }
757
758 static void
759 gst_speex_enc_get_property (GObject * object, guint prop_id, GValue * value,
760     GParamSpec * pspec)
761 {
762   GstSpeexEnc *enc;
763
764   enc = GST_SPEEX_ENC (object);
765
766   switch (prop_id) {
767     case PROP_QUALITY:
768       g_value_set_float (value, enc->quality);
769       break;
770     case PROP_BITRATE:
771       g_value_set_int (value, enc->bitrate);
772       break;
773     case PROP_MODE:
774       g_value_set_enum (value, enc->mode);
775       break;
776     case PROP_VBR:
777       g_value_set_boolean (value, enc->vbr);
778       break;
779     case PROP_ABR:
780       g_value_set_int (value, enc->abr);
781       break;
782     case PROP_VAD:
783       g_value_set_boolean (value, enc->vad);
784       break;
785     case PROP_DTX:
786       g_value_set_boolean (value, enc->dtx);
787       break;
788     case PROP_COMPLEXITY:
789       g_value_set_int (value, enc->complexity);
790       break;
791     case PROP_NFRAMES:
792       g_value_set_int (value, enc->nframes);
793       break;
794     case PROP_LAST_MESSAGE:
795       g_value_set_string (value, enc->last_message);
796       break;
797     default:
798       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
799       break;
800   }
801 }
802
803 static void
804 gst_speex_enc_set_property (GObject * object, guint prop_id,
805     const GValue * value, GParamSpec * pspec)
806 {
807   GstSpeexEnc *enc;
808
809   enc = GST_SPEEX_ENC (object);
810
811   switch (prop_id) {
812     case PROP_QUALITY:
813       enc->quality = g_value_get_float (value);
814       break;
815     case PROP_BITRATE:
816       enc->bitrate = g_value_get_int (value);
817       break;
818     case PROP_MODE:
819       enc->mode = g_value_get_enum (value);
820       break;
821     case PROP_VBR:
822       enc->vbr = g_value_get_boolean (value);
823       break;
824     case PROP_ABR:
825       enc->abr = g_value_get_int (value);
826       break;
827     case PROP_VAD:
828       enc->vad = g_value_get_boolean (value);
829       break;
830     case PROP_DTX:
831       enc->dtx = g_value_get_boolean (value);
832       break;
833     case PROP_COMPLEXITY:
834       enc->complexity = g_value_get_int (value);
835       break;
836     case PROP_NFRAMES:
837       enc->nframes = g_value_get_int (value);
838       break;
839     default:
840       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
841       break;
842   }
843 }