Tizen 2.0 Release
[framework/multimedia/gst-plugins-good0.10.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_static_pad_template (element_class, &src_factory);
158   gst_element_class_add_static_pad_template (element_class, &sink_factory);
159   gst_element_class_set_details_simple (element_class, "Speex audio encoder",
160       "Codec/Encoder/Audio",
161       "Encodes audio in Speex format", "Wim Taymans <wim@fluendo.com>");
162 }
163
164 static void
165 gst_speex_enc_class_init (GstSpeexEncClass * klass)
166 {
167   GObjectClass *gobject_class;
168   GstAudioEncoderClass *base_class;
169
170   gobject_class = (GObjectClass *) klass;
171   base_class = (GstAudioEncoderClass *) klass;
172
173   gobject_class->set_property = gst_speex_enc_set_property;
174   gobject_class->get_property = gst_speex_enc_get_property;
175
176   base_class->start = GST_DEBUG_FUNCPTR (gst_speex_enc_start);
177   base_class->stop = GST_DEBUG_FUNCPTR (gst_speex_enc_stop);
178   base_class->set_format = GST_DEBUG_FUNCPTR (gst_speex_enc_set_format);
179   base_class->handle_frame = GST_DEBUG_FUNCPTR (gst_speex_enc_handle_frame);
180   base_class->event = GST_DEBUG_FUNCPTR (gst_speex_enc_sink_event);
181   base_class->pre_push = GST_DEBUG_FUNCPTR (gst_speex_enc_pre_push);
182
183   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_QUALITY,
184       g_param_spec_float ("quality", "Quality", "Encoding quality",
185           0.0, 10.0, DEFAULT_QUALITY,
186           G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
187   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_BITRATE,
188       g_param_spec_int ("bitrate", "Encoding Bit-rate",
189           "Specify an encoding bit-rate (in bps). (0 = automatic)",
190           0, G_MAXINT, DEFAULT_BITRATE,
191           G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
192   g_object_class_install_property (gobject_class, PROP_MODE,
193       g_param_spec_enum ("mode", "Mode", "The encoding mode",
194           GST_TYPE_SPEEX_ENC_MODE, GST_SPEEX_ENC_MODE_AUTO,
195           G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
196   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_VBR,
197       g_param_spec_boolean ("vbr", "VBR",
198           "Enable variable bit-rate", DEFAULT_VBR,
199           G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
200   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_ABR,
201       g_param_spec_int ("abr", "ABR",
202           "Enable average bit-rate (0 = disabled)",
203           0, G_MAXINT, DEFAULT_ABR,
204           G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
205   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_VAD,
206       g_param_spec_boolean ("vad", "VAD",
207           "Enable voice activity detection", DEFAULT_VAD,
208           G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
209   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_DTX,
210       g_param_spec_boolean ("dtx", "DTX",
211           "Enable discontinuous transmission", DEFAULT_DTX,
212           G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
213   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_COMPLEXITY,
214       g_param_spec_int ("complexity", "Complexity",
215           "Set encoding complexity",
216           0, G_MAXINT, DEFAULT_COMPLEXITY,
217           G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
218   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_NFRAMES,
219       g_param_spec_int ("nframes", "NFrames",
220           "Number of frames per buffer",
221           0, G_MAXINT, DEFAULT_NFRAMES,
222           G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
223   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_LAST_MESSAGE,
224       g_param_spec_string ("last-message", "last-message",
225           "The last status message", NULL,
226           G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
227
228   gobject_class->finalize = gst_speex_enc_finalize;
229 }
230
231 static void
232 gst_speex_enc_finalize (GObject * object)
233 {
234   GstSpeexEnc *enc;
235
236   enc = GST_SPEEX_ENC (object);
237
238   g_free (enc->last_message);
239
240   G_OBJECT_CLASS (parent_class)->finalize (object);
241 }
242
243 static void
244 gst_speex_enc_init (GstSpeexEnc * enc, GstSpeexEncClass * klass)
245 {
246   GstAudioEncoder *benc = GST_AUDIO_ENCODER (enc);
247
248   /* arrange granulepos marking (and required perfect ts) */
249   gst_audio_encoder_set_mark_granule (benc, TRUE);
250   gst_audio_encoder_set_perfect_timestamp (benc, TRUE);
251 }
252
253 static gboolean
254 gst_speex_enc_start (GstAudioEncoder * benc)
255 {
256   GstSpeexEnc *enc = GST_SPEEX_ENC (benc);
257
258   GST_DEBUG_OBJECT (enc, "start");
259   speex_bits_init (&enc->bits);
260   enc->tags = gst_tag_list_new ();
261   enc->header_sent = FALSE;
262
263   return TRUE;
264 }
265
266 static gboolean
267 gst_speex_enc_stop (GstAudioEncoder * benc)
268 {
269   GstSpeexEnc *enc = GST_SPEEX_ENC (benc);
270
271   GST_DEBUG_OBJECT (enc, "stop");
272   enc->header_sent = FALSE;
273   if (enc->state) {
274     speex_encoder_destroy (enc->state);
275     enc->state = NULL;
276   }
277   speex_bits_destroy (&enc->bits);
278   gst_tag_list_free (enc->tags);
279   enc->tags = NULL;
280   g_slist_foreach (enc->headers, (GFunc) gst_buffer_unref, NULL);
281   enc->headers = NULL;
282
283   gst_tag_setter_reset_tags (GST_TAG_SETTER (enc));
284
285   return TRUE;
286 }
287
288 static gint64
289 gst_speex_enc_get_latency (GstSpeexEnc * enc)
290 {
291   /* See the Speex manual section "Latency and algorithmic delay" */
292   if (enc->rate == 8000)
293     return 30 * GST_MSECOND;
294   else
295     return 34 * GST_MSECOND;
296 }
297
298 static gboolean
299 gst_speex_enc_set_format (GstAudioEncoder * benc, GstAudioInfo * info)
300 {
301   GstSpeexEnc *enc;
302
303   enc = GST_SPEEX_ENC (benc);
304
305   enc->channels = GST_AUDIO_INFO_CHANNELS (info);
306   enc->rate = GST_AUDIO_INFO_RATE (info);
307
308   /* handle reconfigure */
309   if (enc->state) {
310     speex_encoder_destroy (enc->state);
311     enc->state = NULL;
312   }
313
314   if (!gst_speex_enc_setup (enc))
315     return FALSE;
316
317   /* feedback to base class */
318   gst_audio_encoder_set_latency (benc,
319       gst_speex_enc_get_latency (enc), gst_speex_enc_get_latency (enc));
320   gst_audio_encoder_set_lookahead (benc, enc->lookahead);
321
322   if (enc->nframes == 0) {
323     /* as many frames as available input allows */
324     gst_audio_encoder_set_frame_samples_min (benc, enc->frame_size);
325     gst_audio_encoder_set_frame_samples_max (benc, enc->frame_size);
326     gst_audio_encoder_set_frame_max (benc, 0);
327   } else {
328     /* exactly as many frames as configured */
329     gst_audio_encoder_set_frame_samples_min (benc,
330         enc->frame_size * enc->nframes);
331     gst_audio_encoder_set_frame_samples_max (benc,
332         enc->frame_size * enc->nframes);
333     gst_audio_encoder_set_frame_max (benc, 1);
334   }
335
336   return TRUE;
337 }
338
339 static GstBuffer *
340 gst_speex_enc_create_metadata_buffer (GstSpeexEnc * enc)
341 {
342   const GstTagList *user_tags;
343   GstTagList *merged_tags;
344   GstBuffer *comments = NULL;
345
346   user_tags = gst_tag_setter_get_tag_list (GST_TAG_SETTER (enc));
347
348   GST_DEBUG_OBJECT (enc, "upstream tags = %" GST_PTR_FORMAT, enc->tags);
349   GST_DEBUG_OBJECT (enc, "user-set tags = %" GST_PTR_FORMAT, user_tags);
350
351   /* gst_tag_list_merge() will handle NULL for either or both lists fine */
352   merged_tags = gst_tag_list_merge (user_tags, enc->tags,
353       gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (enc)));
354
355   if (merged_tags == NULL)
356     merged_tags = gst_tag_list_new ();
357
358   GST_DEBUG_OBJECT (enc, "merged   tags = %" GST_PTR_FORMAT, merged_tags);
359   comments = gst_tag_list_to_vorbiscomment_buffer (merged_tags, NULL,
360       0, "Encoded with GStreamer Speexenc");
361   gst_tag_list_free (merged_tags);
362
363   GST_BUFFER_OFFSET (comments) = 0;
364   GST_BUFFER_OFFSET_END (comments) = 0;
365
366   return comments;
367 }
368
369 static void
370 gst_speex_enc_set_last_msg (GstSpeexEnc * enc, const gchar * msg)
371 {
372   g_free (enc->last_message);
373   enc->last_message = g_strdup (msg);
374   GST_WARNING_OBJECT (enc, "%s", msg);
375   g_object_notify (G_OBJECT (enc), "last-message");
376 }
377
378 static gboolean
379 gst_speex_enc_setup (GstSpeexEnc * enc)
380 {
381   switch (enc->mode) {
382     case GST_SPEEX_ENC_MODE_UWB:
383       GST_LOG_OBJECT (enc, "configuring for requested UWB mode");
384       enc->speex_mode = speex_lib_get_mode (SPEEX_MODEID_UWB);
385       break;
386     case GST_SPEEX_ENC_MODE_WB:
387       GST_LOG_OBJECT (enc, "configuring for requested WB mode");
388       enc->speex_mode = speex_lib_get_mode (SPEEX_MODEID_WB);
389       break;
390     case GST_SPEEX_ENC_MODE_NB:
391       GST_LOG_OBJECT (enc, "configuring for requested NB mode");
392       enc->speex_mode = speex_lib_get_mode (SPEEX_MODEID_NB);
393       break;
394     case GST_SPEEX_ENC_MODE_AUTO:
395       /* fall through */
396       GST_LOG_OBJECT (enc, "finding best mode");
397     default:
398       break;
399   }
400
401   if (enc->rate > 25000) {
402     if (enc->mode == GST_SPEEX_ENC_MODE_AUTO) {
403       GST_LOG_OBJECT (enc, "selected UWB mode for samplerate %d", enc->rate);
404       enc->speex_mode = speex_lib_get_mode (SPEEX_MODEID_UWB);
405     } else {
406       if (enc->speex_mode != speex_lib_get_mode (SPEEX_MODEID_UWB)) {
407         gst_speex_enc_set_last_msg (enc,
408             "Warning: suggest to use ultra wide band mode for this rate");
409       }
410     }
411   } else if (enc->rate > 12500) {
412     if (enc->mode == GST_SPEEX_ENC_MODE_AUTO) {
413       GST_LOG_OBJECT (enc, "selected WB mode for samplerate %d", enc->rate);
414       enc->speex_mode = speex_lib_get_mode (SPEEX_MODEID_WB);
415     } else {
416       if (enc->speex_mode != speex_lib_get_mode (SPEEX_MODEID_WB)) {
417         gst_speex_enc_set_last_msg (enc,
418             "Warning: suggest to use wide band mode for this rate");
419       }
420     }
421   } else {
422     if (enc->mode == GST_SPEEX_ENC_MODE_AUTO) {
423       GST_LOG_OBJECT (enc, "selected NB mode for samplerate %d", enc->rate);
424       enc->speex_mode = speex_lib_get_mode (SPEEX_MODEID_NB);
425     } else {
426       if (enc->speex_mode != speex_lib_get_mode (SPEEX_MODEID_NB)) {
427         gst_speex_enc_set_last_msg (enc,
428             "Warning: suggest to use narrow band mode for this rate");
429       }
430     }
431   }
432
433   if (enc->rate != 8000 && enc->rate != 16000 && enc->rate != 32000) {
434     gst_speex_enc_set_last_msg (enc,
435         "Warning: speex is optimized for 8, 16 and 32 KHz");
436   }
437
438   speex_init_header (&enc->header, enc->rate, 1, enc->speex_mode);
439   enc->header.frames_per_packet = enc->nframes;
440   enc->header.vbr = enc->vbr;
441   enc->header.nb_channels = enc->channels;
442
443   /*Initialize Speex encoder */
444   enc->state = speex_encoder_init (enc->speex_mode);
445
446   speex_encoder_ctl (enc->state, SPEEX_GET_FRAME_SIZE, &enc->frame_size);
447   speex_encoder_ctl (enc->state, SPEEX_SET_COMPLEXITY, &enc->complexity);
448   speex_encoder_ctl (enc->state, SPEEX_SET_SAMPLING_RATE, &enc->rate);
449
450   if (enc->vbr)
451     speex_encoder_ctl (enc->state, SPEEX_SET_VBR_QUALITY, &enc->quality);
452   else {
453     gint tmp = floor (enc->quality);
454
455     speex_encoder_ctl (enc->state, SPEEX_SET_QUALITY, &tmp);
456   }
457   if (enc->bitrate) {
458     if (enc->quality >= 0.0 && enc->vbr) {
459       gst_speex_enc_set_last_msg (enc,
460           "Warning: bitrate option is overriding quality");
461     }
462     speex_encoder_ctl (enc->state, SPEEX_SET_BITRATE, &enc->bitrate);
463   }
464   if (enc->vbr) {
465     gint tmp = 1;
466
467     speex_encoder_ctl (enc->state, SPEEX_SET_VBR, &tmp);
468   } else if (enc->vad) {
469     gint tmp = 1;
470
471     speex_encoder_ctl (enc->state, SPEEX_SET_VAD, &tmp);
472   }
473
474   if (enc->dtx) {
475     gint tmp = 1;
476
477     speex_encoder_ctl (enc->state, SPEEX_SET_DTX, &tmp);
478   }
479
480   if (enc->dtx && !(enc->vbr || enc->abr || enc->vad)) {
481     gst_speex_enc_set_last_msg (enc,
482         "Warning: dtx is useless without vad, vbr or abr");
483   } else if ((enc->vbr || enc->abr) && (enc->vad)) {
484     gst_speex_enc_set_last_msg (enc,
485         "Warning: vad is already implied by vbr or abr");
486   }
487
488   if (enc->abr) {
489     speex_encoder_ctl (enc->state, SPEEX_SET_ABR, &enc->abr);
490   }
491
492   speex_encoder_ctl (enc->state, SPEEX_GET_LOOKAHEAD, &enc->lookahead);
493
494   GST_LOG_OBJECT (enc, "we have frame size %d, lookahead %d", enc->frame_size,
495       enc->lookahead);
496
497   return TRUE;
498 }
499
500 /* push out the buffer */
501 static GstFlowReturn
502 gst_speex_enc_push_buffer (GstSpeexEnc * enc, GstBuffer * buffer)
503 {
504   guint size;
505
506   size = GST_BUFFER_SIZE (buffer);
507   GST_DEBUG_OBJECT (enc, "pushing output buffer of size %u", size);
508
509   gst_buffer_set_caps (buffer, GST_PAD_CAPS (GST_AUDIO_ENCODER_SRC_PAD (enc)));
510   return gst_pad_push (GST_AUDIO_ENCODER_SRC_PAD (enc), buffer);
511 }
512
513 static gboolean
514 gst_speex_enc_sink_event (GstAudioEncoder * benc, GstEvent * event)
515 {
516   GstSpeexEnc *enc;
517
518   enc = GST_SPEEX_ENC (benc);
519
520   switch (GST_EVENT_TYPE (event)) {
521     case GST_EVENT_TAG:
522     {
523       if (enc->tags) {
524         GstTagList *list;
525
526         gst_event_parse_tag (event, &list);
527         gst_tag_list_insert (enc->tags, list,
528             gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (enc)));
529       } else {
530         g_assert_not_reached ();
531       }
532       break;
533     }
534     default:
535       break;
536   }
537
538   /* we only peeked, let base class handle it */
539   return FALSE;
540 }
541
542 static GstFlowReturn
543 gst_speex_enc_encode (GstSpeexEnc * enc, GstBuffer * buf)
544 {
545   gint frame_size = enc->frame_size;
546   gint bytes = frame_size * 2 * enc->channels, samples, size;
547   gint outsize, written, dtx_ret = 0;
548   guint8 *data, *data0 = NULL;
549   GstBuffer *outbuf;
550   GstFlowReturn ret = GST_FLOW_OK;
551
552   if (G_LIKELY (buf)) {
553     data = GST_BUFFER_DATA (buf);
554     size = GST_BUFFER_SIZE (buf);
555
556     if (G_UNLIKELY (size % bytes)) {
557       GST_DEBUG_OBJECT (enc, "draining; adding silence samples");
558       size = ((size / bytes) + 1) * bytes;
559       data0 = data = g_malloc0 (size);
560       memcpy (data, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
561     }
562   } else {
563     GST_DEBUG_OBJECT (enc, "nothing to drain");
564     goto done;
565   }
566
567   samples = size / (2 * enc->channels);
568   speex_bits_reset (&enc->bits);
569
570   /* FIXME what about dropped samples if DTS enabled ?? */
571
572   while (size) {
573     GST_DEBUG_OBJECT (enc, "encoding %d samples (%d bytes)", frame_size, bytes);
574
575     if (enc->channels == 2) {
576       speex_encode_stereo_int ((gint16 *) data, frame_size, &enc->bits);
577     }
578     dtx_ret += speex_encode_int (enc->state, (gint16 *) data, &enc->bits);
579
580     data += bytes;
581     size -= bytes;
582   }
583
584   speex_bits_insert_terminator (&enc->bits);
585   outsize = speex_bits_nbytes (&enc->bits);
586
587   ret = gst_pad_alloc_buffer_and_set_caps (GST_AUDIO_ENCODER_SRC_PAD (enc),
588       GST_BUFFER_OFFSET_NONE, outsize,
589       GST_PAD_CAPS (GST_AUDIO_ENCODER_SRC_PAD (enc)), &outbuf);
590
591   if ((GST_FLOW_OK != ret))
592     goto done;
593
594   written = speex_bits_write (&enc->bits,
595       (gchar *) GST_BUFFER_DATA (outbuf), outsize);
596
597   if (G_UNLIKELY (written < outsize)) {
598     GST_ERROR_OBJECT (enc, "short write: %d < %d bytes", written, outsize);
599     GST_BUFFER_SIZE (outbuf) = written;
600   } else if (G_UNLIKELY (written > outsize)) {
601     GST_ERROR_OBJECT (enc, "overrun: %d > %d bytes", written, outsize);
602   }
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_metadata_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 ();
695     GST_BUFFER_DATA (buf1) = GST_BUFFER_MALLOCDATA (buf1) = data;
696     GST_BUFFER_SIZE (buf1) = data_len;
697     GST_BUFFER_OFFSET_END (buf1) = 0;
698     GST_BUFFER_OFFSET (buf1) = 0;
699
700     /* create comment buffer */
701     buf2 = gst_speex_enc_create_metadata_buffer (enc);
702
703     /* mark and put on caps */
704     caps = gst_caps_new_simple ("audio/x-speex", "rate", G_TYPE_INT, enc->rate,
705         "channels", G_TYPE_INT, enc->channels, NULL);
706     caps = _gst_caps_set_buffer_array (caps, "streamheader", buf1, buf2, NULL);
707
708     /* negotiate with these caps */
709     GST_DEBUG_OBJECT (enc, "here are the caps: %" GST_PTR_FORMAT, caps);
710
711     gst_buffer_set_caps (buf1, caps);
712     gst_buffer_set_caps (buf2, caps);
713     gst_pad_set_caps (GST_AUDIO_ENCODER_SRC_PAD (enc), caps);
714     gst_caps_unref (caps);
715
716     /* push out buffers */
717     /* store buffers for later pre_push sending */
718     g_slist_foreach (enc->headers, (GFunc) gst_buffer_unref, NULL);
719     enc->headers = NULL;
720     GST_DEBUG_OBJECT (enc, "storing header buffers");
721     enc->headers = g_slist_prepend (enc->headers, buf2);
722     enc->headers = g_slist_prepend (enc->headers, buf1);
723
724     enc->header_sent = TRUE;
725   }
726
727   GST_DEBUG_OBJECT (enc, "received buffer %p of %u bytes", buf,
728       buf ? GST_BUFFER_SIZE (buf) : 0);
729
730   ret = gst_speex_enc_encode (enc, buf);
731
732   return ret;
733 }
734
735 static GstFlowReturn
736 gst_speex_enc_pre_push (GstAudioEncoder * benc, GstBuffer ** buffer)
737 {
738   GstSpeexEnc *enc;
739   GstFlowReturn ret = GST_FLOW_OK;
740
741   enc = GST_SPEEX_ENC (benc);
742
743   /* FIXME 0.11 ? get rid of this special ogg stuff and have it
744    * put and use 'codec data' in caps like anything else,
745    * with all the usual out-of-band advantage etc */
746   if (G_UNLIKELY (enc->headers)) {
747     GSList *header = enc->headers;
748
749     /* try to push all of these, if we lose one, might as well lose all */
750     while (header) {
751       if (ret == GST_FLOW_OK)
752         ret = gst_speex_enc_push_buffer (enc, header->data);
753       else
754         gst_speex_enc_push_buffer (enc, header->data);
755       header = g_slist_next (header);
756     }
757
758     g_slist_free (enc->headers);
759     enc->headers = NULL;
760   }
761
762   return ret;
763 }
764
765 static void
766 gst_speex_enc_get_property (GObject * object, guint prop_id, GValue * value,
767     GParamSpec * pspec)
768 {
769   GstSpeexEnc *enc;
770
771   enc = GST_SPEEX_ENC (object);
772
773   switch (prop_id) {
774     case PROP_QUALITY:
775       g_value_set_float (value, enc->quality);
776       break;
777     case PROP_BITRATE:
778       g_value_set_int (value, enc->bitrate);
779       break;
780     case PROP_MODE:
781       g_value_set_enum (value, enc->mode);
782       break;
783     case PROP_VBR:
784       g_value_set_boolean (value, enc->vbr);
785       break;
786     case PROP_ABR:
787       g_value_set_int (value, enc->abr);
788       break;
789     case PROP_VAD:
790       g_value_set_boolean (value, enc->vad);
791       break;
792     case PROP_DTX:
793       g_value_set_boolean (value, enc->dtx);
794       break;
795     case PROP_COMPLEXITY:
796       g_value_set_int (value, enc->complexity);
797       break;
798     case PROP_NFRAMES:
799       g_value_set_int (value, enc->nframes);
800       break;
801     case PROP_LAST_MESSAGE:
802       g_value_set_string (value, enc->last_message);
803       break;
804     default:
805       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
806       break;
807   }
808 }
809
810 static void
811 gst_speex_enc_set_property (GObject * object, guint prop_id,
812     const GValue * value, GParamSpec * pspec)
813 {
814   GstSpeexEnc *enc;
815
816   enc = GST_SPEEX_ENC (object);
817
818   switch (prop_id) {
819     case PROP_QUALITY:
820       enc->quality = g_value_get_float (value);
821       break;
822     case PROP_BITRATE:
823       enc->bitrate = g_value_get_int (value);
824       break;
825     case PROP_MODE:
826       enc->mode = g_value_get_enum (value);
827       break;
828     case PROP_VBR:
829       enc->vbr = g_value_get_boolean (value);
830       break;
831     case PROP_ABR:
832       enc->abr = g_value_get_int (value);
833       break;
834     case PROP_VAD:
835       enc->vad = g_value_get_boolean (value);
836       break;
837     case PROP_DTX:
838       enc->dtx = g_value_get_boolean (value);
839       break;
840     case PROP_COMPLEXITY:
841       enc->complexity = g_value_get_int (value);
842       break;
843     case PROP_NFRAMES:
844       enc->nframes = g_value_get_int (value);
845       break;
846     default:
847       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
848       break;
849   }
850 }