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