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