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 static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
58 GST_STATIC_CAPS ("audio/x-raw-int, "
59 "rate = (int) [ 6000, 48000 ], "
60 "channels = (int) [ 1, 2 ], "
61 "endianness = (int) BYTE_ORDER, "
62 "signed = (boolean) TRUE, " "width = (int) 16, " "depth = (int) 16")
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,
137 gst_speex_enc_setup_interfaces (GType speexenc_type)
139 static const GInterfaceInfo tag_setter_info = { NULL, NULL, NULL };
141 g_type_add_interface_static (speexenc_type, GST_TYPE_TAG_SETTER,
144 GST_DEBUG_CATEGORY_INIT (speexenc_debug, "speexenc", 0, "Speex encoder");
147 GST_BOILERPLATE_FULL (GstSpeexEnc, gst_speex_enc, GstAudioEncoder,
148 GST_TYPE_AUDIO_ENCODER, gst_speex_enc_setup_interfaces);
151 gst_speex_enc_base_init (gpointer g_class)
153 GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
155 gst_element_class_add_pad_template (element_class,
156 gst_static_pad_template_get (&src_factory));
157 gst_element_class_add_pad_template (element_class,
158 gst_static_pad_template_get (&sink_factory));
159 gst_element_class_set_details_simple (element_class, "Speex audio encoder",
160 "Codec/Encoder/Audio",
161 "Encodes audio in Speex format", "Wim Taymans <wim@fluendo.com>");
165 gst_speex_enc_class_init (GstSpeexEncClass * klass)
167 GObjectClass *gobject_class;
168 GstAudioEncoderClass *base_class;
170 gobject_class = (GObjectClass *) klass;
171 base_class = (GstAudioEncoderClass *) klass;
173 gobject_class->set_property = gst_speex_enc_set_property;
174 gobject_class->get_property = gst_speex_enc_get_property;
176 base_class->start = GST_DEBUG_FUNCPTR (gst_speex_enc_start);
177 base_class->stop = GST_DEBUG_FUNCPTR (gst_speex_enc_stop);
178 base_class->set_format = GST_DEBUG_FUNCPTR (gst_speex_enc_set_format);
179 base_class->handle_frame = GST_DEBUG_FUNCPTR (gst_speex_enc_handle_frame);
180 base_class->event = GST_DEBUG_FUNCPTR (gst_speex_enc_sink_event);
182 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_QUALITY,
183 g_param_spec_float ("quality", "Quality", "Encoding quality",
184 0.0, 10.0, DEFAULT_QUALITY,
185 G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
186 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_BITRATE,
187 g_param_spec_int ("bitrate", "Encoding Bit-rate",
188 "Specify an encoding bit-rate (in bps). (0 = automatic)",
189 0, G_MAXINT, DEFAULT_BITRATE,
190 G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
191 g_object_class_install_property (gobject_class, PROP_MODE,
192 g_param_spec_enum ("mode", "Mode", "The encoding mode",
193 GST_TYPE_SPEEX_ENC_MODE, GST_SPEEX_ENC_MODE_AUTO,
194 G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
195 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_VBR,
196 g_param_spec_boolean ("vbr", "VBR",
197 "Enable variable bit-rate", DEFAULT_VBR,
198 G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
199 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_ABR,
200 g_param_spec_int ("abr", "ABR",
201 "Enable average bit-rate (0 = disabled)",
202 0, G_MAXINT, DEFAULT_ABR,
203 G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
204 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_VAD,
205 g_param_spec_boolean ("vad", "VAD",
206 "Enable voice activity detection", DEFAULT_VAD,
207 G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
208 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_DTX,
209 g_param_spec_boolean ("dtx", "DTX",
210 "Enable discontinuous transmission", DEFAULT_DTX,
211 G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
212 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_COMPLEXITY,
213 g_param_spec_int ("complexity", "Complexity",
214 "Set encoding complexity",
215 0, G_MAXINT, DEFAULT_COMPLEXITY,
216 G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
217 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_NFRAMES,
218 g_param_spec_int ("nframes", "NFrames",
219 "Number of frames per buffer",
220 0, G_MAXINT, DEFAULT_NFRAMES,
221 G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
222 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_LAST_MESSAGE,
223 g_param_spec_string ("last-message", "last-message",
224 "The last status message", NULL,
225 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
227 gobject_class->finalize = gst_speex_enc_finalize;
231 gst_speex_enc_finalize (GObject * object)
235 enc = GST_SPEEX_ENC (object);
237 g_free (enc->last_message);
239 G_OBJECT_CLASS (parent_class)->finalize (object);
243 gst_speex_enc_init (GstSpeexEnc * enc, GstSpeexEncClass * klass)
245 GstAudioEncoder *benc = GST_AUDIO_ENCODER (enc);
247 /* arrange granulepos marking (and required perfect ts) */
248 gst_audio_encoder_set_mark_granule (benc, TRUE);
249 gst_audio_encoder_set_perfect_timestamp (benc, TRUE);
253 gst_speex_enc_start (GstAudioEncoder * benc)
255 GstSpeexEnc *enc = GST_SPEEX_ENC (benc);
257 GST_DEBUG_OBJECT (enc, "start");
258 speex_bits_init (&enc->bits);
259 enc->tags = gst_tag_list_new ();
260 enc->header_sent = FALSE;
266 gst_speex_enc_stop (GstAudioEncoder * benc)
268 GstSpeexEnc *enc = GST_SPEEX_ENC (benc);
270 GST_DEBUG_OBJECT (enc, "stop");
271 enc->header_sent = FALSE;
273 speex_encoder_destroy (enc->state);
276 speex_bits_destroy (&enc->bits);
277 gst_tag_list_free (enc->tags);
284 gst_speex_enc_get_latency (GstSpeexEnc * enc)
286 /* See the Speex manual section "Latency and algorithmic delay" */
287 if (enc->rate == 8000)
288 return 30 * GST_MSECOND;
290 return 34 * GST_MSECOND;
294 gst_speex_enc_set_format (GstAudioEncoder * benc, GstAudioInfo * info)
298 enc = GST_SPEEX_ENC (benc);
300 enc->channels = GST_AUDIO_INFO_CHANNELS (info);
301 enc->rate = GST_AUDIO_INFO_RATE (info);
303 /* handle reconfigure */
305 speex_encoder_destroy (enc->state);
309 if (!gst_speex_enc_setup (enc))
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);
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);
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);
335 gst_speex_enc_create_metadata_buffer (GstSpeexEnc * enc)
337 const GstTagList *user_tags;
338 GstTagList *merged_tags;
339 GstBuffer *comments = NULL;
341 user_tags = gst_tag_setter_get_tag_list (GST_TAG_SETTER (enc));
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);
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)));
350 if (merged_tags == NULL)
351 merged_tags = gst_tag_list_new ();
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_free (merged_tags);
358 GST_BUFFER_OFFSET (comments) = 0;
359 GST_BUFFER_OFFSET_END (comments) = 0;
365 gst_speex_enc_set_last_msg (GstSpeexEnc * enc, const gchar * msg)
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");
374 gst_speex_enc_setup (GstSpeexEnc * enc)
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);
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);
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);
389 case GST_SPEEX_ENC_MODE_AUTO:
391 GST_LOG_OBJECT (enc, "finding best mode");
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);
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");
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);
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");
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);
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");
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");
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;
438 /*Initialize Speex encoder */
439 enc->state = speex_encoder_init (enc->speex_mode);
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);
446 speex_encoder_ctl (enc->state, SPEEX_SET_VBR_QUALITY, &enc->quality);
448 gint tmp = floor (enc->quality);
450 speex_encoder_ctl (enc->state, SPEEX_SET_QUALITY, &tmp);
453 if (enc->quality >= 0.0 && enc->vbr) {
454 gst_speex_enc_set_last_msg (enc,
455 "Warning: bitrate option is overriding quality");
457 speex_encoder_ctl (enc->state, SPEEX_SET_BITRATE, &enc->bitrate);
462 speex_encoder_ctl (enc->state, SPEEX_SET_VBR, &tmp);
463 } else if (enc->vad) {
466 speex_encoder_ctl (enc->state, SPEEX_SET_VAD, &tmp);
472 speex_encoder_ctl (enc->state, SPEEX_SET_DTX, &tmp);
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");
484 speex_encoder_ctl (enc->state, SPEEX_SET_ABR, &enc->abr);
487 speex_encoder_ctl (enc->state, SPEEX_GET_LOOKAHEAD, &enc->lookahead);
489 GST_LOG_OBJECT (enc, "we have frame size %d, lookahead %d", enc->frame_size,
495 /* push out the buffer */
497 gst_speex_enc_push_buffer (GstSpeexEnc * enc, GstBuffer * buffer)
501 size = GST_BUFFER_SIZE (buffer);
502 GST_DEBUG_OBJECT (enc, "pushing output buffer of size %u", size);
504 return gst_pad_push (GST_AUDIO_ENCODER_SRC_PAD (enc), buffer);
508 gst_speex_enc_sink_event (GstAudioEncoder * benc, GstEvent * event)
512 enc = GST_SPEEX_ENC (benc);
514 switch (GST_EVENT_TYPE (event)) {
520 gst_event_parse_tag (event, &list);
521 gst_tag_list_insert (enc->tags, list,
522 gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (enc)));
524 g_assert_not_reached ();
532 /* we only peeked, let base class handle it */
537 gst_speex_enc_encode (GstSpeexEnc * enc, GstBuffer * buf)
539 gint frame_size = enc->frame_size;
540 gint bytes = frame_size * 2 * enc->channels, samples, size;
541 gint outsize, written, dtx_ret = 0;
544 GstFlowReturn ret = GST_FLOW_OK;
546 if (G_LIKELY (buf)) {
547 data = GST_BUFFER_DATA (buf);
548 size = GST_BUFFER_SIZE (buf);
550 if (G_UNLIKELY (size % bytes)) {
551 GST_DEBUG_OBJECT (enc, "draining; adding silence samples");
552 size = ((size / bytes) + 1) * bytes;
553 data = g_malloc0 (size);
554 memcpy (data, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
557 GST_DEBUG_OBJECT (enc, "nothing to drain");
561 samples = size / (2 * enc->channels);
562 speex_bits_reset (&enc->bits);
564 /* FIXME what about dropped samples if DTS enabled ?? */
567 GST_DEBUG_OBJECT (enc, "encoding %d samples (%d bytes)", frame_size, bytes);
569 if (enc->channels == 2) {
570 speex_encode_stereo_int ((gint16 *) data, frame_size, &enc->bits);
572 dtx_ret += speex_encode_int (enc->state, (gint16 *) data, &enc->bits);
578 speex_bits_insert_terminator (&enc->bits);
579 outsize = speex_bits_nbytes (&enc->bits);
581 ret = gst_pad_alloc_buffer_and_set_caps (GST_AUDIO_ENCODER_SRC_PAD (enc),
582 GST_BUFFER_OFFSET_NONE, outsize,
583 GST_PAD_CAPS (GST_AUDIO_ENCODER_SRC_PAD (enc)), &outbuf);
585 if ((GST_FLOW_OK != ret))
588 written = speex_bits_write (&enc->bits,
589 (gchar *) GST_BUFFER_DATA (outbuf), outsize);
591 if (G_UNLIKELY (written < outsize)) {
592 GST_ERROR_OBJECT (enc, "short write: %d < %d bytes", written, outsize);
593 GST_BUFFER_SIZE (outbuf) = written;
594 } else if (G_UNLIKELY (written > outsize)) {
595 GST_ERROR_OBJECT (enc, "overrun: %d > %d bytes", written, outsize);
599 GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_GAP);
601 ret = gst_audio_encoder_finish_frame (GST_AUDIO_ENCODER (enc),
609 * (really really) FIXME: move into core (dixit tpm)
612 * _gst_caps_set_buffer_array:
614 * @field: field in caps to set
615 * @buf: header buffers
617 * Adds given buffers to an array of buffers set as the given @field
618 * on the given @caps. List of buffer arguments must be NULL-terminated.
620 * Returns: input caps with a streamheader field added, or NULL if some error
623 _gst_caps_set_buffer_array (GstCaps * caps, const gchar * field,
624 GstBuffer * buf, ...)
626 GstStructure *structure = NULL;
628 GValue array = { 0 };
629 GValue value = { 0 };
631 g_return_val_if_fail (caps != NULL, NULL);
632 g_return_val_if_fail (gst_caps_is_fixed (caps), NULL);
633 g_return_val_if_fail (field != NULL, NULL);
635 caps = gst_caps_make_writable (caps);
636 structure = gst_caps_get_structure (caps, 0);
638 g_value_init (&array, GST_TYPE_ARRAY);
641 /* put buffers in a fixed list */
643 g_assert (gst_buffer_is_metadata_writable (buf));
646 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_IN_CAPS);
648 g_value_init (&value, GST_TYPE_BUFFER);
649 buf = gst_buffer_copy (buf);
650 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_IN_CAPS);
651 gst_value_set_buffer (&value, buf);
652 gst_buffer_unref (buf);
653 gst_value_array_append_value (&array, &value);
654 g_value_unset (&value);
656 buf = va_arg (va, GstBuffer *);
659 gst_structure_set_value (structure, field, &array);
660 g_value_unset (&array);
666 gst_speex_enc_handle_frame (GstAudioEncoder * benc, GstBuffer * buf)
669 GstFlowReturn ret = GST_FLOW_OK;
671 enc = GST_SPEEX_ENC (benc);
673 if (!enc->header_sent) {
674 /* Speex streams begin with two headers; the initial header (with
675 most of the codec setup parameters) which is mandated by the Ogg
676 bitstream spec. The second header holds any comment fields.
677 We merely need to make the headers, then pass them to libspeex
678 one at a time; libspeex handles the additional Ogg bitstream
680 GstBuffer *buf1, *buf2;
685 /* create header buffer */
686 data = (guint8 *) speex_header_to_packet (&enc->header, &data_len);
687 buf1 = gst_buffer_new ();
688 GST_BUFFER_DATA (buf1) = GST_BUFFER_MALLOCDATA (buf1) = data;
689 GST_BUFFER_SIZE (buf1) = data_len;
690 GST_BUFFER_OFFSET_END (buf1) = 0;
691 GST_BUFFER_OFFSET (buf1) = 0;
693 /* create comment buffer */
694 buf2 = gst_speex_enc_create_metadata_buffer (enc);
696 /* mark and put on caps */
697 caps = gst_caps_new_simple ("audio/x-speex", "rate", G_TYPE_INT, enc->rate,
698 "channels", G_TYPE_INT, enc->channels, NULL);
699 caps = _gst_caps_set_buffer_array (caps, "streamheader", buf1, buf2, NULL);
701 /* negotiate with these caps */
702 GST_DEBUG_OBJECT (enc, "here are the caps: %" GST_PTR_FORMAT, caps);
704 gst_buffer_set_caps (buf1, caps);
705 gst_buffer_set_caps (buf2, caps);
706 gst_caps_unref (caps);
708 /* push out buffers */
709 ret = gst_speex_enc_push_buffer (enc, buf1);
711 if (ret != GST_FLOW_OK) {
712 gst_buffer_unref (buf2);
716 ret = gst_speex_enc_push_buffer (enc, buf2);
718 if (ret != GST_FLOW_OK)
721 enc->header_sent = TRUE;
724 GST_DEBUG_OBJECT (enc, "received buffer %p of %u bytes", buf,
725 buf ? GST_BUFFER_SIZE (buf) : 0);
727 ret = gst_speex_enc_encode (enc, buf);
735 gst_speex_enc_get_property (GObject * object, guint prop_id, GValue * value,
740 enc = GST_SPEEX_ENC (object);
744 g_value_set_float (value, enc->quality);
747 g_value_set_int (value, enc->bitrate);
750 g_value_set_enum (value, enc->mode);
753 g_value_set_boolean (value, enc->vbr);
756 g_value_set_int (value, enc->abr);
759 g_value_set_boolean (value, enc->vad);
762 g_value_set_boolean (value, enc->dtx);
764 case PROP_COMPLEXITY:
765 g_value_set_int (value, enc->complexity);
768 g_value_set_int (value, enc->nframes);
770 case PROP_LAST_MESSAGE:
771 g_value_set_string (value, enc->last_message);
774 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
780 gst_speex_enc_set_property (GObject * object, guint prop_id,
781 const GValue * value, GParamSpec * pspec)
785 enc = GST_SPEEX_ENC (object);
789 enc->quality = g_value_get_float (value);
792 enc->bitrate = g_value_get_int (value);
795 enc->mode = g_value_get_enum (value);
798 enc->vbr = g_value_get_boolean (value);
801 enc->abr = g_value_get_int (value);
804 enc->vad = g_value_get_boolean (value);
807 enc->dtx = g_value_get_boolean (value);
809 case PROP_COMPLEXITY:
810 enc->complexity = g_value_get_int (value);
813 enc->nframes = g_value_get_int (value);
816 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);