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