1 /* GStreamer Speex Encoder
2 * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
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.
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.
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.
21 * SECTION:element-speexenc
22 * @see_also: speexdec, oggmux
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
30 * <title>Example pipelines</title>
32 * gst-launch audiotestsrc num-buffers=100 ! speexenc ! oggmux ! filesink location=beep.ogg
33 * ]| Encode an Ogg/Speex file.
44 #include <speex/speex.h>
45 #include <speex/speex_stereo.h>
47 #include <gst/gsttagsetter.h>
48 #include <gst/tag/tag.h>
49 #include <gst/audio/audio.h>
50 #include "gstspeexenc.h"
52 GST_DEBUG_CATEGORY_STATIC (speexenc_debug);
53 #define GST_CAT_DEFAULT speexenc_debug
55 #define FORMAT_STR GST_AUDIO_NE(S16)
57 static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
60 GST_STATIC_CAPS ("audio/x-raw, "
61 "format = (string) " FORMAT_STR ", "
62 "rate = (int) [ 6000, 48000 ], " "channels = (int) [ 1, 2 ]")
65 static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
68 GST_STATIC_CAPS ("audio/x-speex, "
69 "rate = (int) [ 6000, 48000 ], " "channels = (int) [ 1, 2]")
72 #define DEFAULT_QUALITY 8.0
73 #define DEFAULT_BITRATE 0
74 #define DEFAULT_MODE GST_SPEEX_ENC_MODE_AUTO
75 #define DEFAULT_VBR FALSE
77 #define DEFAULT_VAD FALSE
78 #define DEFAULT_DTX FALSE
79 #define DEFAULT_COMPLEXITY 3
80 #define DEFAULT_NFRAMES 1
97 #define GST_TYPE_SPEEX_ENC_MODE (gst_speex_enc_mode_get_type())
99 gst_speex_enc_mode_get_type (void)
101 static GType speex_enc_mode_type = 0;
102 static const GEnumValue speex_enc_modes[] = {
103 {GST_SPEEX_ENC_MODE_AUTO, "Auto", "auto"},
104 {GST_SPEEX_ENC_MODE_UWB, "Ultra Wide Band", "uwb"},
105 {GST_SPEEX_ENC_MODE_WB, "Wide Band", "wb"},
106 {GST_SPEEX_ENC_MODE_NB, "Narrow Band", "nb"},
109 if (G_UNLIKELY (speex_enc_mode_type == 0)) {
110 speex_enc_mode_type = g_enum_register_static ("GstSpeexEncMode",
113 return speex_enc_mode_type;
116 static void gst_speex_enc_finalize (GObject * object);
118 static gboolean gst_speex_enc_setup (GstSpeexEnc * enc);
120 static void gst_speex_enc_get_property (GObject * object, guint prop_id,
121 GValue * value, GParamSpec * pspec);
122 static void gst_speex_enc_set_property (GObject * object, guint prop_id,
123 const GValue * value, GParamSpec * pspec);
125 static GstFlowReturn gst_speex_enc_encode (GstSpeexEnc * enc, GstBuffer * buf);
127 static gboolean gst_speex_enc_start (GstAudioEncoder * enc);
128 static gboolean gst_speex_enc_stop (GstAudioEncoder * enc);
129 static gboolean gst_speex_enc_set_format (GstAudioEncoder * enc,
130 GstAudioInfo * info);
131 static GstFlowReturn gst_speex_enc_handle_frame (GstAudioEncoder * enc,
133 static gboolean gst_speex_enc_sink_event (GstAudioEncoder * enc,
136 #define gst_speex_enc_parent_class parent_class
137 G_DEFINE_TYPE_WITH_CODE (GstSpeexEnc, gst_speex_enc, GST_TYPE_AUDIO_ENCODER,
138 G_IMPLEMENT_INTERFACE (GST_TYPE_TAG_SETTER, NULL);
139 G_IMPLEMENT_INTERFACE (GST_TYPE_PRESET, NULL));
142 gst_speex_enc_class_init (GstSpeexEncClass * klass)
144 GObjectClass *gobject_class;
145 GstElementClass *gstelement_class;
146 GstAudioEncoderClass *base_class;
148 gobject_class = (GObjectClass *) klass;
149 gstelement_class = (GstElementClass *) klass;
150 base_class = (GstAudioEncoderClass *) klass;
152 gobject_class->finalize = gst_speex_enc_finalize;
153 gobject_class->set_property = gst_speex_enc_set_property;
154 gobject_class->get_property = gst_speex_enc_get_property;
156 base_class->start = GST_DEBUG_FUNCPTR (gst_speex_enc_start);
157 base_class->stop = GST_DEBUG_FUNCPTR (gst_speex_enc_stop);
158 base_class->set_format = GST_DEBUG_FUNCPTR (gst_speex_enc_set_format);
159 base_class->handle_frame = GST_DEBUG_FUNCPTR (gst_speex_enc_handle_frame);
160 base_class->event = GST_DEBUG_FUNCPTR (gst_speex_enc_sink_event);
162 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_QUALITY,
163 g_param_spec_float ("quality", "Quality", "Encoding quality",
164 0.0, 10.0, DEFAULT_QUALITY,
165 G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
166 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_BITRATE,
167 g_param_spec_int ("bitrate", "Encoding Bit-rate",
168 "Specify an encoding bit-rate (in bps). (0 = automatic)",
169 0, G_MAXINT, DEFAULT_BITRATE,
170 G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
171 g_object_class_install_property (gobject_class, PROP_MODE,
172 g_param_spec_enum ("mode", "Mode", "The encoding mode",
173 GST_TYPE_SPEEX_ENC_MODE, GST_SPEEX_ENC_MODE_AUTO,
174 G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
175 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_VBR,
176 g_param_spec_boolean ("vbr", "VBR",
177 "Enable variable bit-rate", DEFAULT_VBR,
178 G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
179 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_ABR,
180 g_param_spec_int ("abr", "ABR",
181 "Enable average bit-rate (0 = disabled)",
182 0, G_MAXINT, DEFAULT_ABR,
183 G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
184 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_VAD,
185 g_param_spec_boolean ("vad", "VAD",
186 "Enable voice activity detection", DEFAULT_VAD,
187 G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
188 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_DTX,
189 g_param_spec_boolean ("dtx", "DTX",
190 "Enable discontinuous transmission", DEFAULT_DTX,
191 G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
192 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_COMPLEXITY,
193 g_param_spec_int ("complexity", "Complexity",
194 "Set encoding complexity",
195 0, G_MAXINT, DEFAULT_COMPLEXITY,
196 G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
197 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_NFRAMES,
198 g_param_spec_int ("nframes", "NFrames",
199 "Number of frames per buffer",
200 0, G_MAXINT, DEFAULT_NFRAMES,
201 G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
202 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_LAST_MESSAGE,
203 g_param_spec_string ("last-message", "last-message",
204 "The last status message", NULL,
205 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
207 gst_element_class_add_pad_template (gstelement_class,
208 gst_static_pad_template_get (&src_factory));
209 gst_element_class_add_pad_template (gstelement_class,
210 gst_static_pad_template_get (&sink_factory));
211 gst_element_class_set_details_simple (gstelement_class, "Speex audio encoder",
212 "Codec/Encoder/Audio",
213 "Encodes audio in Speex format", "Wim Taymans <wim@fluendo.com>");
215 GST_DEBUG_CATEGORY_INIT (speexenc_debug, "speexenc", 0, "Speex encoder");
219 gst_speex_enc_finalize (GObject * object)
223 enc = GST_SPEEX_ENC (object);
225 g_free (enc->last_message);
227 G_OBJECT_CLASS (parent_class)->finalize (object);
231 gst_speex_enc_init (GstSpeexEnc * enc)
233 GstAudioEncoder *benc = GST_AUDIO_ENCODER (enc);
235 /* arrange granulepos marking (and required perfect ts) */
236 gst_audio_encoder_set_mark_granule (benc, TRUE);
237 gst_audio_encoder_set_perfect_timestamp (benc, TRUE);
241 gst_speex_enc_start (GstAudioEncoder * benc)
243 GstSpeexEnc *enc = GST_SPEEX_ENC (benc);
245 GST_DEBUG_OBJECT (enc, "start");
246 speex_bits_init (&enc->bits);
247 enc->tags = gst_tag_list_new ();
248 enc->header_sent = FALSE;
254 gst_speex_enc_stop (GstAudioEncoder * benc)
256 GstSpeexEnc *enc = GST_SPEEX_ENC (benc);
258 GST_DEBUG_OBJECT (enc, "stop");
259 enc->header_sent = FALSE;
261 speex_encoder_destroy (enc->state);
264 speex_bits_destroy (&enc->bits);
265 gst_tag_list_free (enc->tags);
272 gst_speex_enc_get_latency (GstSpeexEnc * enc)
274 /* See the Speex manual section "Latency and algorithmic delay" */
275 if (enc->rate == 8000)
276 return 30 * GST_MSECOND;
278 return 34 * GST_MSECOND;
282 gst_speex_enc_set_format (GstAudioEncoder * benc, GstAudioInfo * info)
286 enc = GST_SPEEX_ENC (benc);
288 enc->channels = GST_AUDIO_INFO_CHANNELS (info);
289 enc->rate = GST_AUDIO_INFO_RATE (info);
291 /* handle reconfigure */
293 speex_encoder_destroy (enc->state);
297 if (!gst_speex_enc_setup (enc))
300 /* feedback to base class */
301 gst_audio_encoder_set_latency (benc,
302 gst_speex_enc_get_latency (enc), gst_speex_enc_get_latency (enc));
303 gst_audio_encoder_set_lookahead (benc, enc->lookahead);
305 if (enc->nframes == 0) {
306 /* as many frames as available input allows */
307 gst_audio_encoder_set_frame_samples_min (benc, enc->frame_size);
308 gst_audio_encoder_set_frame_samples_max (benc, enc->frame_size);
309 gst_audio_encoder_set_frame_max (benc, 0);
311 /* exactly as many frames as configured */
312 gst_audio_encoder_set_frame_samples_min (benc,
313 enc->frame_size * enc->nframes);
314 gst_audio_encoder_set_frame_samples_max (benc,
315 enc->frame_size * enc->nframes);
316 gst_audio_encoder_set_frame_max (benc, 1);
323 gst_speex_enc_create_metadata_buffer (GstSpeexEnc * enc)
325 const GstTagList *user_tags;
326 GstTagList *merged_tags;
327 GstBuffer *comments = NULL;
329 user_tags = gst_tag_setter_get_tag_list (GST_TAG_SETTER (enc));
331 GST_DEBUG_OBJECT (enc, "upstream tags = %" GST_PTR_FORMAT, enc->tags);
332 GST_DEBUG_OBJECT (enc, "user-set tags = %" GST_PTR_FORMAT, user_tags);
334 /* gst_tag_list_merge() will handle NULL for either or both lists fine */
335 merged_tags = gst_tag_list_merge (user_tags, enc->tags,
336 gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (enc)));
338 if (merged_tags == NULL)
339 merged_tags = gst_tag_list_new ();
341 GST_DEBUG_OBJECT (enc, "merged tags = %" GST_PTR_FORMAT, merged_tags);
342 comments = gst_tag_list_to_vorbiscomment_buffer (merged_tags, NULL,
343 0, "Encoded with GStreamer Speexenc");
344 gst_tag_list_free (merged_tags);
346 GST_BUFFER_OFFSET (comments) = 0;
347 GST_BUFFER_OFFSET_END (comments) = 0;
353 gst_speex_enc_set_last_msg (GstSpeexEnc * enc, const gchar * msg)
355 g_free (enc->last_message);
356 enc->last_message = g_strdup (msg);
357 GST_WARNING_OBJECT (enc, "%s", msg);
358 g_object_notify (G_OBJECT (enc), "last-message");
362 gst_speex_enc_setup (GstSpeexEnc * enc)
365 case GST_SPEEX_ENC_MODE_UWB:
366 GST_LOG_OBJECT (enc, "configuring for requested UWB mode");
367 enc->speex_mode = speex_lib_get_mode (SPEEX_MODEID_UWB);
369 case GST_SPEEX_ENC_MODE_WB:
370 GST_LOG_OBJECT (enc, "configuring for requested WB mode");
371 enc->speex_mode = speex_lib_get_mode (SPEEX_MODEID_WB);
373 case GST_SPEEX_ENC_MODE_NB:
374 GST_LOG_OBJECT (enc, "configuring for requested NB mode");
375 enc->speex_mode = speex_lib_get_mode (SPEEX_MODEID_NB);
377 case GST_SPEEX_ENC_MODE_AUTO:
379 GST_LOG_OBJECT (enc, "finding best mode");
384 if (enc->rate > 25000) {
385 if (enc->mode == GST_SPEEX_ENC_MODE_AUTO) {
386 GST_LOG_OBJECT (enc, "selected UWB mode for samplerate %d", enc->rate);
387 enc->speex_mode = speex_lib_get_mode (SPEEX_MODEID_UWB);
389 if (enc->speex_mode != speex_lib_get_mode (SPEEX_MODEID_UWB)) {
390 gst_speex_enc_set_last_msg (enc,
391 "Warning: suggest to use ultra wide band mode for this rate");
394 } else if (enc->rate > 12500) {
395 if (enc->mode == GST_SPEEX_ENC_MODE_AUTO) {
396 GST_LOG_OBJECT (enc, "selected WB mode for samplerate %d", enc->rate);
397 enc->speex_mode = speex_lib_get_mode (SPEEX_MODEID_WB);
399 if (enc->speex_mode != speex_lib_get_mode (SPEEX_MODEID_WB)) {
400 gst_speex_enc_set_last_msg (enc,
401 "Warning: suggest to use wide band mode for this rate");
405 if (enc->mode == GST_SPEEX_ENC_MODE_AUTO) {
406 GST_LOG_OBJECT (enc, "selected NB mode for samplerate %d", enc->rate);
407 enc->speex_mode = speex_lib_get_mode (SPEEX_MODEID_NB);
409 if (enc->speex_mode != speex_lib_get_mode (SPEEX_MODEID_NB)) {
410 gst_speex_enc_set_last_msg (enc,
411 "Warning: suggest to use narrow band mode for this rate");
416 if (enc->rate != 8000 && enc->rate != 16000 && enc->rate != 32000) {
417 gst_speex_enc_set_last_msg (enc,
418 "Warning: speex is optimized for 8, 16 and 32 KHz");
421 speex_init_header (&enc->header, enc->rate, 1, enc->speex_mode);
422 enc->header.frames_per_packet = enc->nframes;
423 enc->header.vbr = enc->vbr;
424 enc->header.nb_channels = enc->channels;
426 /*Initialize Speex encoder */
427 enc->state = speex_encoder_init (enc->speex_mode);
429 speex_encoder_ctl (enc->state, SPEEX_GET_FRAME_SIZE, &enc->frame_size);
430 speex_encoder_ctl (enc->state, SPEEX_SET_COMPLEXITY, &enc->complexity);
431 speex_encoder_ctl (enc->state, SPEEX_SET_SAMPLING_RATE, &enc->rate);
434 speex_encoder_ctl (enc->state, SPEEX_SET_VBR_QUALITY, &enc->quality);
436 gint tmp = floor (enc->quality);
438 speex_encoder_ctl (enc->state, SPEEX_SET_QUALITY, &tmp);
441 if (enc->quality >= 0.0 && enc->vbr) {
442 gst_speex_enc_set_last_msg (enc,
443 "Warning: bitrate option is overriding quality");
445 speex_encoder_ctl (enc->state, SPEEX_SET_BITRATE, &enc->bitrate);
450 speex_encoder_ctl (enc->state, SPEEX_SET_VBR, &tmp);
451 } else if (enc->vad) {
454 speex_encoder_ctl (enc->state, SPEEX_SET_VAD, &tmp);
460 speex_encoder_ctl (enc->state, SPEEX_SET_DTX, &tmp);
463 if (enc->dtx && !(enc->vbr || enc->abr || enc->vad)) {
464 gst_speex_enc_set_last_msg (enc,
465 "Warning: dtx is useless without vad, vbr or abr");
466 } else if ((enc->vbr || enc->abr) && (enc->vad)) {
467 gst_speex_enc_set_last_msg (enc,
468 "Warning: vad is already implied by vbr or abr");
472 speex_encoder_ctl (enc->state, SPEEX_SET_ABR, &enc->abr);
475 speex_encoder_ctl (enc->state, SPEEX_GET_LOOKAHEAD, &enc->lookahead);
477 GST_LOG_OBJECT (enc, "we have frame size %d, lookahead %d", enc->frame_size,
483 /* push out the buffer */
485 gst_speex_enc_push_buffer (GstSpeexEnc * enc, GstBuffer * buffer)
487 GST_DEBUG_OBJECT (enc, "pushing output buffer of size %u",
488 gst_buffer_get_size (buffer));
490 return gst_pad_push (GST_AUDIO_ENCODER_SRC_PAD (enc), buffer);
494 gst_speex_enc_sink_event (GstAudioEncoder * benc, GstEvent * event)
498 enc = GST_SPEEX_ENC (benc);
500 switch (GST_EVENT_TYPE (event)) {
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)));
510 g_assert_not_reached ();
518 /* we only peeked, let base class handle it */
523 gst_speex_enc_encode (GstSpeexEnc * enc, GstBuffer * buf)
525 gint frame_size = enc->frame_size;
526 gint bytes = frame_size * 2 * enc->channels, samples;
527 gint outsize, written, dtx_ret = 0;
528 guint8 *data, *bdata, *outdata;
531 GstFlowReturn ret = GST_FLOW_OK;
533 if (G_LIKELY (buf)) {
534 bdata = gst_buffer_map (buf, &bsize, NULL, GST_MAP_READ);
536 if (G_UNLIKELY (bsize % bytes)) {
537 GST_DEBUG_OBJECT (enc, "draining; adding silence samples");
539 size = ((bsize / bytes) + 1) * bytes;
540 data = g_malloc0 (size);
541 memcpy (data, bdata, bsize);
542 gst_buffer_unmap (buf, bdata, bsize);
549 GST_DEBUG_OBJECT (enc, "nothing to drain");
553 samples = size / (2 * enc->channels);
554 speex_bits_reset (&enc->bits);
556 /* FIXME what about dropped samples if DTS enabled ?? */
559 GST_DEBUG_OBJECT (enc, "encoding %d samples (%d bytes)", frame_size, bytes);
561 if (enc->channels == 2) {
562 speex_encode_stereo_int ((gint16 *) data, frame_size, &enc->bits);
564 dtx_ret += speex_encode_int (enc->state, (gint16 *) data, &enc->bits);
570 speex_bits_insert_terminator (&enc->bits);
571 outsize = speex_bits_nbytes (&enc->bits);
574 gst_buffer_unmap (buf, bdata, bsize);
577 ret = gst_pad_alloc_buffer_and_set_caps (GST_AUDIO_ENCODER_SRC_PAD (enc),
578 GST_BUFFER_OFFSET_NONE, outsize,
579 GST_PAD_CAPS (GST_AUDIO_ENCODER_SRC_PAD (enc)), &outbuf);
581 if ((GST_FLOW_OK != ret))
584 outbuf = gst_buffer_new_allocate (NULL, outsize, 0);
585 outdata = gst_buffer_map (outbuf, NULL, NULL, GST_MAP_WRITE);
587 written = speex_bits_write (&enc->bits, (gchar *) outdata, outsize);
589 if (G_UNLIKELY (written < outsize)) {
590 GST_ERROR_OBJECT (enc, "short write: %d < %d bytes", written, outsize);
591 } else if (G_UNLIKELY (written > outsize)) {
592 GST_ERROR_OBJECT (enc, "overrun: %d > %d bytes", written, outsize);
595 gst_buffer_unmap (outbuf, outdata, written);
598 GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_GAP);
600 ret = gst_audio_encoder_finish_frame (GST_AUDIO_ENCODER (enc),
608 * (really really) FIXME: move into core (dixit tpm)
611 * _gst_caps_set_buffer_array:
613 * @field: field in caps to set
614 * @buf: header buffers
616 * Adds given buffers to an array of buffers set as the given @field
617 * on the given @caps. List of buffer arguments must be NULL-terminated.
619 * Returns: input caps with a streamheader field added, or NULL if some error
622 _gst_caps_set_buffer_array (GstCaps * caps, const gchar * field,
623 GstBuffer * buf, ...)
625 GstStructure *structure = NULL;
627 GValue array = { 0 };
628 GValue value = { 0 };
630 g_return_val_if_fail (caps != NULL, NULL);
631 g_return_val_if_fail (gst_caps_is_fixed (caps), NULL);
632 g_return_val_if_fail (field != NULL, NULL);
634 caps = gst_caps_make_writable (caps);
635 structure = gst_caps_get_structure (caps, 0);
637 g_value_init (&array, GST_TYPE_ARRAY);
640 /* put buffers in a fixed list */
642 g_assert (gst_buffer_is_writable (buf));
645 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_IN_CAPS);
647 g_value_init (&value, GST_TYPE_BUFFER);
648 buf = gst_buffer_copy (buf);
649 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_IN_CAPS);
650 gst_value_set_buffer (&value, buf);
651 gst_buffer_unref (buf);
652 gst_value_array_append_value (&array, &value);
653 g_value_unset (&value);
655 buf = va_arg (va, GstBuffer *);
658 gst_structure_set_value (structure, field, &array);
659 g_value_unset (&array);
665 gst_speex_enc_handle_frame (GstAudioEncoder * benc, GstBuffer * buf)
668 GstFlowReturn ret = GST_FLOW_OK;
670 enc = GST_SPEEX_ENC (benc);
672 if (!enc->header_sent) {
673 /* Speex streams begin with two headers; the initial header (with
674 most of the codec setup parameters) which is mandated by the Ogg
675 bitstream spec. The second header holds any comment fields.
676 We merely need to make the headers, then pass them to libspeex
677 one at a time; libspeex handles the additional Ogg bitstream
679 GstBuffer *buf1, *buf2;
684 /* create header buffer */
685 data = (guint8 *) speex_header_to_packet (&enc->header, &data_len);
686 buf1 = gst_buffer_new_wrapped (data, data_len);
687 GST_BUFFER_OFFSET_END (buf1) = 0;
688 GST_BUFFER_OFFSET (buf1) = 0;
690 /* create comment buffer */
691 buf2 = gst_speex_enc_create_metadata_buffer (enc);
693 /* mark and put on caps */
694 caps = gst_caps_new_simple ("audio/x-speex", "rate", G_TYPE_INT, enc->rate,
695 "channels", G_TYPE_INT, enc->channels, NULL);
696 caps = _gst_caps_set_buffer_array (caps, "streamheader", buf1, buf2, NULL);
698 /* negotiate with these caps */
699 GST_DEBUG_OBJECT (enc, "here are the caps: %" GST_PTR_FORMAT, caps);
701 /* push out buffers */
702 ret = gst_speex_enc_push_buffer (enc, buf1);
704 if (ret != GST_FLOW_OK) {
705 gst_buffer_unref (buf2);
709 ret = gst_speex_enc_push_buffer (enc, buf2);
711 if (ret != GST_FLOW_OK)
714 enc->header_sent = TRUE;
717 GST_DEBUG_OBJECT (enc, "received buffer %p of %u bytes", buf,
718 buf ? gst_buffer_get_size (buf) : 0);
720 ret = gst_speex_enc_encode (enc, buf);
728 gst_speex_enc_get_property (GObject * object, guint prop_id, GValue * value,
733 enc = GST_SPEEX_ENC (object);
737 g_value_set_float (value, enc->quality);
740 g_value_set_int (value, enc->bitrate);
743 g_value_set_enum (value, enc->mode);
746 g_value_set_boolean (value, enc->vbr);
749 g_value_set_int (value, enc->abr);
752 g_value_set_boolean (value, enc->vad);
755 g_value_set_boolean (value, enc->dtx);
757 case PROP_COMPLEXITY:
758 g_value_set_int (value, enc->complexity);
761 g_value_set_int (value, enc->nframes);
763 case PROP_LAST_MESSAGE:
764 g_value_set_string (value, enc->last_message);
767 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
773 gst_speex_enc_set_property (GObject * object, guint prop_id,
774 const GValue * value, GParamSpec * pspec)
778 enc = GST_SPEEX_ENC (object);
782 enc->quality = g_value_get_float (value);
785 enc->bitrate = g_value_get_int (value);
788 enc->mode = g_value_get_enum (value);
791 enc->vbr = g_value_get_boolean (value);
794 enc->abr = g_value_get_int (value);
797 enc->vad = g_value_get_boolean (value);
800 enc->dtx = g_value_get_boolean (value);
802 case PROP_COMPLEXITY:
803 enc->complexity = g_value_get_int (value);
806 enc->nframes = g_value_get_int (value);
809 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);