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