Merge remote-tracking branch 'origin/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_empty ();
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   gst_tag_setter_reset_tags (GST_TAG_SETTER (enc));
274
275   return TRUE;
276 }
277
278 static gint64
279 gst_speex_enc_get_latency (GstSpeexEnc * enc)
280 {
281   /* See the Speex manual section "Latency and algorithmic delay" */
282   if (enc->rate == 8000)
283     return 30 * GST_MSECOND;
284   else
285     return 34 * GST_MSECOND;
286 }
287
288 static gboolean
289 gst_speex_enc_set_format (GstAudioEncoder * benc, GstAudioInfo * info)
290 {
291   GstSpeexEnc *enc;
292
293   enc = GST_SPEEX_ENC (benc);
294
295   enc->channels = GST_AUDIO_INFO_CHANNELS (info);
296   enc->rate = GST_AUDIO_INFO_RATE (info);
297
298   /* handle reconfigure */
299   if (enc->state) {
300     speex_encoder_destroy (enc->state);
301     enc->state = NULL;
302   }
303
304   if (!gst_speex_enc_setup (enc))
305     return FALSE;
306
307   /* feedback to base class */
308   gst_audio_encoder_set_latency (benc,
309       gst_speex_enc_get_latency (enc), gst_speex_enc_get_latency (enc));
310   gst_audio_encoder_set_lookahead (benc, enc->lookahead);
311
312   if (enc->nframes == 0) {
313     /* as many frames as available input allows */
314     gst_audio_encoder_set_frame_samples_min (benc, enc->frame_size);
315     gst_audio_encoder_set_frame_samples_max (benc, enc->frame_size);
316     gst_audio_encoder_set_frame_max (benc, 0);
317   } else {
318     /* exactly as many frames as configured */
319     gst_audio_encoder_set_frame_samples_min (benc,
320         enc->frame_size * enc->nframes);
321     gst_audio_encoder_set_frame_samples_max (benc,
322         enc->frame_size * enc->nframes);
323     gst_audio_encoder_set_frame_max (benc, 1);
324   }
325
326   return TRUE;
327 }
328
329 static GstBuffer *
330 gst_speex_enc_create_metadata_buffer (GstSpeexEnc * enc)
331 {
332   const GstTagList *user_tags;
333   GstTagList *merged_tags;
334   GstBuffer *comments = NULL;
335
336   user_tags = gst_tag_setter_get_tag_list (GST_TAG_SETTER (enc));
337
338   GST_DEBUG_OBJECT (enc, "upstream tags = %" GST_PTR_FORMAT, enc->tags);
339   GST_DEBUG_OBJECT (enc, "user-set tags = %" GST_PTR_FORMAT, user_tags);
340
341   /* gst_tag_list_merge() will handle NULL for either or both lists fine */
342   merged_tags = gst_tag_list_merge (user_tags, enc->tags,
343       gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (enc)));
344
345   if (merged_tags == NULL)
346     merged_tags = gst_tag_list_new_empty ();
347
348   GST_DEBUG_OBJECT (enc, "merged   tags = %" GST_PTR_FORMAT, merged_tags);
349   comments = gst_tag_list_to_vorbiscomment_buffer (merged_tags, NULL,
350       0, "Encoded with GStreamer Speexenc");
351   gst_tag_list_free (merged_tags);
352
353   GST_BUFFER_OFFSET (comments) = 0;
354   GST_BUFFER_OFFSET_END (comments) = 0;
355
356   return comments;
357 }
358
359 static void
360 gst_speex_enc_set_last_msg (GstSpeexEnc * enc, const gchar * msg)
361 {
362   g_free (enc->last_message);
363   enc->last_message = g_strdup (msg);
364   GST_WARNING_OBJECT (enc, "%s", msg);
365   g_object_notify (G_OBJECT (enc), "last-message");
366 }
367
368 static gboolean
369 gst_speex_enc_setup (GstSpeexEnc * enc)
370 {
371   switch (enc->mode) {
372     case GST_SPEEX_ENC_MODE_UWB:
373       GST_LOG_OBJECT (enc, "configuring for requested UWB mode");
374       enc->speex_mode = speex_lib_get_mode (SPEEX_MODEID_UWB);
375       break;
376     case GST_SPEEX_ENC_MODE_WB:
377       GST_LOG_OBJECT (enc, "configuring for requested WB mode");
378       enc->speex_mode = speex_lib_get_mode (SPEEX_MODEID_WB);
379       break;
380     case GST_SPEEX_ENC_MODE_NB:
381       GST_LOG_OBJECT (enc, "configuring for requested NB mode");
382       enc->speex_mode = speex_lib_get_mode (SPEEX_MODEID_NB);
383       break;
384     case GST_SPEEX_ENC_MODE_AUTO:
385       /* fall through */
386       GST_LOG_OBJECT (enc, "finding best mode");
387     default:
388       break;
389   }
390
391   if (enc->rate > 25000) {
392     if (enc->mode == GST_SPEEX_ENC_MODE_AUTO) {
393       GST_LOG_OBJECT (enc, "selected UWB mode for samplerate %d", enc->rate);
394       enc->speex_mode = speex_lib_get_mode (SPEEX_MODEID_UWB);
395     } else {
396       if (enc->speex_mode != speex_lib_get_mode (SPEEX_MODEID_UWB)) {
397         gst_speex_enc_set_last_msg (enc,
398             "Warning: suggest to use ultra wide band mode for this rate");
399       }
400     }
401   } else if (enc->rate > 12500) {
402     if (enc->mode == GST_SPEEX_ENC_MODE_AUTO) {
403       GST_LOG_OBJECT (enc, "selected WB mode for samplerate %d", enc->rate);
404       enc->speex_mode = speex_lib_get_mode (SPEEX_MODEID_WB);
405     } else {
406       if (enc->speex_mode != speex_lib_get_mode (SPEEX_MODEID_WB)) {
407         gst_speex_enc_set_last_msg (enc,
408             "Warning: suggest to use wide band mode for this rate");
409       }
410     }
411   } else {
412     if (enc->mode == GST_SPEEX_ENC_MODE_AUTO) {
413       GST_LOG_OBJECT (enc, "selected NB mode for samplerate %d", enc->rate);
414       enc->speex_mode = speex_lib_get_mode (SPEEX_MODEID_NB);
415     } else {
416       if (enc->speex_mode != speex_lib_get_mode (SPEEX_MODEID_NB)) {
417         gst_speex_enc_set_last_msg (enc,
418             "Warning: suggest to use narrow band mode for this rate");
419       }
420     }
421   }
422
423   if (enc->rate != 8000 && enc->rate != 16000 && enc->rate != 32000) {
424     gst_speex_enc_set_last_msg (enc,
425         "Warning: speex is optimized for 8, 16 and 32 KHz");
426   }
427
428   speex_init_header (&enc->header, enc->rate, 1, enc->speex_mode);
429   enc->header.frames_per_packet = enc->nframes;
430   enc->header.vbr = enc->vbr;
431   enc->header.nb_channels = enc->channels;
432
433   /*Initialize Speex encoder */
434   enc->state = speex_encoder_init (enc->speex_mode);
435
436   speex_encoder_ctl (enc->state, SPEEX_GET_FRAME_SIZE, &enc->frame_size);
437   speex_encoder_ctl (enc->state, SPEEX_SET_COMPLEXITY, &enc->complexity);
438   speex_encoder_ctl (enc->state, SPEEX_SET_SAMPLING_RATE, &enc->rate);
439
440   if (enc->vbr)
441     speex_encoder_ctl (enc->state, SPEEX_SET_VBR_QUALITY, &enc->quality);
442   else {
443     gint tmp = floor (enc->quality);
444
445     speex_encoder_ctl (enc->state, SPEEX_SET_QUALITY, &tmp);
446   }
447   if (enc->bitrate) {
448     if (enc->quality >= 0.0 && enc->vbr) {
449       gst_speex_enc_set_last_msg (enc,
450           "Warning: bitrate option is overriding quality");
451     }
452     speex_encoder_ctl (enc->state, SPEEX_SET_BITRATE, &enc->bitrate);
453   }
454   if (enc->vbr) {
455     gint tmp = 1;
456
457     speex_encoder_ctl (enc->state, SPEEX_SET_VBR, &tmp);
458   } else if (enc->vad) {
459     gint tmp = 1;
460
461     speex_encoder_ctl (enc->state, SPEEX_SET_VAD, &tmp);
462   }
463
464   if (enc->dtx) {
465     gint tmp = 1;
466
467     speex_encoder_ctl (enc->state, SPEEX_SET_DTX, &tmp);
468   }
469
470   if (enc->dtx && !(enc->vbr || enc->abr || enc->vad)) {
471     gst_speex_enc_set_last_msg (enc,
472         "Warning: dtx is useless without vad, vbr or abr");
473   } else if ((enc->vbr || enc->abr) && (enc->vad)) {
474     gst_speex_enc_set_last_msg (enc,
475         "Warning: vad is already implied by vbr or abr");
476   }
477
478   if (enc->abr) {
479     speex_encoder_ctl (enc->state, SPEEX_SET_ABR, &enc->abr);
480   }
481
482   speex_encoder_ctl (enc->state, SPEEX_GET_LOOKAHEAD, &enc->lookahead);
483
484   GST_LOG_OBJECT (enc, "we have frame size %d, lookahead %d", enc->frame_size,
485       enc->lookahead);
486
487   return TRUE;
488 }
489
490 /* push out the buffer */
491 static GstFlowReturn
492 gst_speex_enc_push_buffer (GstSpeexEnc * enc, GstBuffer * buffer)
493 {
494   GST_DEBUG_OBJECT (enc, "pushing output buffer of size %" G_GSIZE_FORMAT,
495       gst_buffer_get_size (buffer));
496
497   return gst_pad_push (GST_AUDIO_ENCODER_SRC_PAD (enc), buffer);
498 }
499
500 static gboolean
501 gst_speex_enc_sink_event (GstAudioEncoder * benc, GstEvent * event)
502 {
503   GstSpeexEnc *enc;
504
505   enc = GST_SPEEX_ENC (benc);
506
507   switch (GST_EVENT_TYPE (event)) {
508     case GST_EVENT_TAG:
509     {
510       if (enc->tags) {
511         GstTagList *list;
512
513         gst_event_parse_tag (event, &list);
514         gst_tag_list_insert (enc->tags, list,
515             gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (enc)));
516       } else {
517         g_assert_not_reached ();
518       }
519       break;
520     }
521     default:
522       break;
523   }
524
525   /* we only peeked, let base class handle it */
526   return FALSE;
527 }
528
529 static GstFlowReturn
530 gst_speex_enc_encode (GstSpeexEnc * enc, GstBuffer * buf)
531 {
532   gint frame_size = enc->frame_size;
533   gint bytes = frame_size * 2 * enc->channels, samples;
534   gint outsize, written, dtx_ret = 0;
535   guint8 *data, *data0 = NULL, *bdata, *outdata;
536   gsize bsize, size;
537   GstBuffer *outbuf;
538   GstFlowReturn ret = GST_FLOW_OK;
539
540   if (G_LIKELY (buf)) {
541     bdata = gst_buffer_map (buf, &bsize, NULL, GST_MAP_READ);
542
543     if (G_UNLIKELY (bsize % bytes)) {
544       GST_DEBUG_OBJECT (enc, "draining; adding silence samples");
545
546       size = ((bsize / bytes) + 1) * bytes;
547       data0 = data = g_malloc0 (size);
548       memcpy (data, bdata, bsize);
549       gst_buffer_unmap (buf, bdata, bsize);
550       bdata = NULL;
551     } else {
552       data = bdata;
553       size = bsize;
554     }
555   } else {
556     GST_DEBUG_OBJECT (enc, "nothing to drain");
557     goto done;
558   }
559
560   samples = size / (2 * enc->channels);
561   speex_bits_reset (&enc->bits);
562
563   /* FIXME what about dropped samples if DTS enabled ?? */
564
565   while (size) {
566     GST_DEBUG_OBJECT (enc, "encoding %d samples (%d bytes)", frame_size, bytes);
567
568     if (enc->channels == 2) {
569       speex_encode_stereo_int ((gint16 *) data, frame_size, &enc->bits);
570     }
571     dtx_ret += speex_encode_int (enc->state, (gint16 *) data, &enc->bits);
572
573     data += bytes;
574     size -= bytes;
575   }
576
577   speex_bits_insert_terminator (&enc->bits);
578   outsize = speex_bits_nbytes (&enc->bits);
579
580   if (bdata)
581     gst_buffer_unmap (buf, bdata, bsize);
582
583 #if 0
584   ret = gst_pad_alloc_buffer_and_set_caps (GST_AUDIO_ENCODER_SRC_PAD (enc),
585       GST_BUFFER_OFFSET_NONE, outsize,
586       GST_PAD_CAPS (GST_AUDIO_ENCODER_SRC_PAD (enc)), &outbuf);
587
588   if ((GST_FLOW_OK != ret))
589     goto done;
590 #endif
591   outbuf = gst_buffer_new_allocate (NULL, outsize, 0);
592   outdata = gst_buffer_map (outbuf, NULL, NULL, GST_MAP_WRITE);
593
594   written = speex_bits_write (&enc->bits, (gchar *) outdata, outsize);
595
596   if (G_UNLIKELY (written < outsize)) {
597     GST_ERROR_OBJECT (enc, "short write: %d < %d bytes", written, outsize);
598   } else if (G_UNLIKELY (written > outsize)) {
599     GST_ERROR_OBJECT (enc, "overrun: %d > %d bytes", written, outsize);
600     written = outsize;
601   }
602   gst_buffer_unmap (outbuf, outdata, written);
603
604   if (!dtx_ret)
605     GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_GAP);
606
607   ret = gst_audio_encoder_finish_frame (GST_AUDIO_ENCODER (enc),
608       outbuf, samples);
609
610 done:
611   g_free (data0);
612   return ret;
613 }
614
615 /*
616  * (really really) FIXME: move into core (dixit tpm)
617  */
618 /**
619  * _gst_caps_set_buffer_array:
620  * @caps: a #GstCaps
621  * @field: field in caps to set
622  * @buf: header buffers
623  *
624  * Adds given buffers to an array of buffers set as the given @field
625  * on the given @caps.  List of buffer arguments must be NULL-terminated.
626  *
627  * Returns: input caps with a streamheader field added, or NULL if some error
628  */
629 static GstCaps *
630 _gst_caps_set_buffer_array (GstCaps * caps, const gchar * field,
631     GstBuffer * buf, ...)
632 {
633   GstStructure *structure = NULL;
634   va_list va;
635   GValue array = { 0 };
636   GValue value = { 0 };
637
638   g_return_val_if_fail (caps != NULL, NULL);
639   g_return_val_if_fail (gst_caps_is_fixed (caps), NULL);
640   g_return_val_if_fail (field != NULL, NULL);
641
642   caps = gst_caps_make_writable (caps);
643   structure = gst_caps_get_structure (caps, 0);
644
645   g_value_init (&array, GST_TYPE_ARRAY);
646
647   va_start (va, buf);
648   /* put buffers in a fixed list */
649   while (buf) {
650     g_assert (gst_buffer_is_writable (buf));
651
652     /* mark buffer */
653     GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_IN_CAPS);
654
655     g_value_init (&value, GST_TYPE_BUFFER);
656     buf = gst_buffer_copy (buf);
657     GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_IN_CAPS);
658     gst_value_set_buffer (&value, buf);
659     gst_buffer_unref (buf);
660     gst_value_array_append_value (&array, &value);
661     g_value_unset (&value);
662
663     buf = va_arg (va, GstBuffer *);
664   }
665
666   gst_structure_set_value (structure, field, &array);
667   g_value_unset (&array);
668
669   return caps;
670 }
671
672 static GstFlowReturn
673 gst_speex_enc_handle_frame (GstAudioEncoder * benc, GstBuffer * buf)
674 {
675   GstSpeexEnc *enc;
676   GstFlowReturn ret = GST_FLOW_OK;
677
678   enc = GST_SPEEX_ENC (benc);
679
680   if (!enc->header_sent) {
681     /* Speex streams begin with two headers; the initial header (with
682        most of the codec setup parameters) which is mandated by the Ogg
683        bitstream spec.  The second header holds any comment fields.
684        We merely need to make the headers, then pass them to libspeex 
685        one at a time; libspeex handles the additional Ogg bitstream 
686        constraints */
687     GstBuffer *buf1, *buf2;
688     GstCaps *caps;
689     guchar *data;
690     gint data_len;
691
692     /* create header buffer */
693     data = (guint8 *) speex_header_to_packet (&enc->header, &data_len);
694     buf1 = gst_buffer_new_wrapped (data, data_len);
695     GST_BUFFER_OFFSET_END (buf1) = 0;
696     GST_BUFFER_OFFSET (buf1) = 0;
697
698     /* create comment buffer */
699     buf2 = gst_speex_enc_create_metadata_buffer (enc);
700
701     /* mark and put on caps */
702     caps = gst_caps_new_simple ("audio/x-speex", "rate", G_TYPE_INT, enc->rate,
703         "channels", G_TYPE_INT, enc->channels, NULL);
704     caps = _gst_caps_set_buffer_array (caps, "streamheader", buf1, buf2, NULL);
705
706     /* negotiate with these caps */
707     GST_DEBUG_OBJECT (enc, "here are the caps: %" GST_PTR_FORMAT, caps);
708
709     gst_pad_set_caps (GST_AUDIO_ENCODER_SRC_PAD (enc), caps);
710     gst_caps_unref (caps);
711
712     /* push out buffers */
713     /* store buffers for later pre_push sending */
714     g_slist_foreach (enc->headers, (GFunc) gst_buffer_unref, NULL);
715     enc->headers = NULL;
716     GST_DEBUG_OBJECT (enc, "storing header buffers");
717     enc->headers = g_slist_prepend (enc->headers, buf2);
718     enc->headers = g_slist_prepend (enc->headers, buf1);
719
720     enc->header_sent = TRUE;
721   }
722
723   GST_DEBUG_OBJECT (enc, "received buffer %p of %" G_GSIZE_FORMAT " bytes", buf,
724       buf ? gst_buffer_get_size (buf) : 0);
725
726   ret = gst_speex_enc_encode (enc, buf);
727
728   return ret;
729 }
730
731 static GstFlowReturn
732 gst_speex_enc_pre_push (GstAudioEncoder * benc, GstBuffer ** buffer)
733 {
734   GstSpeexEnc *enc;
735   GstFlowReturn ret = GST_FLOW_OK;
736
737   enc = GST_SPEEX_ENC (benc);
738
739   /* FIXME 0.11 ? get rid of this special ogg stuff and have it
740    * put and use 'codec data' in caps like anything else,
741    * with all the usual out-of-band advantage etc */
742   if (G_UNLIKELY (enc->headers)) {
743     GSList *header = enc->headers;
744
745     /* try to push all of these, if we lose one, might as well lose all */
746     while (header) {
747       if (ret == GST_FLOW_OK)
748         ret = gst_speex_enc_push_buffer (enc, header->data);
749       else
750         gst_speex_enc_push_buffer (enc, header->data);
751       header = g_slist_next (header);
752     }
753
754     g_slist_free (enc->headers);
755     enc->headers = NULL;
756   }
757
758   return ret;
759 }
760
761 static void
762 gst_speex_enc_get_property (GObject * object, guint prop_id, GValue * value,
763     GParamSpec * pspec)
764 {
765   GstSpeexEnc *enc;
766
767   enc = GST_SPEEX_ENC (object);
768
769   switch (prop_id) {
770     case PROP_QUALITY:
771       g_value_set_float (value, enc->quality);
772       break;
773     case PROP_BITRATE:
774       g_value_set_int (value, enc->bitrate);
775       break;
776     case PROP_MODE:
777       g_value_set_enum (value, enc->mode);
778       break;
779     case PROP_VBR:
780       g_value_set_boolean (value, enc->vbr);
781       break;
782     case PROP_ABR:
783       g_value_set_int (value, enc->abr);
784       break;
785     case PROP_VAD:
786       g_value_set_boolean (value, enc->vad);
787       break;
788     case PROP_DTX:
789       g_value_set_boolean (value, enc->dtx);
790       break;
791     case PROP_COMPLEXITY:
792       g_value_set_int (value, enc->complexity);
793       break;
794     case PROP_NFRAMES:
795       g_value_set_int (value, enc->nframes);
796       break;
797     case PROP_LAST_MESSAGE:
798       g_value_set_string (value, enc->last_message);
799       break;
800     default:
801       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
802       break;
803   }
804 }
805
806 static void
807 gst_speex_enc_set_property (GObject * object, guint prop_id,
808     const GValue * value, GParamSpec * pspec)
809 {
810   GstSpeexEnc *enc;
811
812   enc = GST_SPEEX_ENC (object);
813
814   switch (prop_id) {
815     case PROP_QUALITY:
816       enc->quality = g_value_get_float (value);
817       break;
818     case PROP_BITRATE:
819       enc->bitrate = g_value_get_int (value);
820       break;
821     case PROP_MODE:
822       enc->mode = g_value_get_enum (value);
823       break;
824     case PROP_VBR:
825       enc->vbr = g_value_get_boolean (value);
826       break;
827     case PROP_ABR:
828       enc->abr = g_value_get_int (value);
829       break;
830     case PROP_VAD:
831       enc->vad = g_value_get_boolean (value);
832       break;
833     case PROP_DTX:
834       enc->dtx = g_value_get_boolean (value);
835       break;
836     case PROP_COMPLEXITY:
837       enc->complexity = g_value_get_int (value);
838       break;
839     case PROP_NFRAMES:
840       enc->nframes = g_value_get_int (value);
841       break;
842     default:
843       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
844       break;
845   }
846 }