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