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