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., 51 Franklin St, Fifth Floor,
17 * Boston, MA 02110-1301, 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-1.0 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 "layout = (string) interleaved, "
63 "rate = (int) [ 6000, 48000 ], "
64 "channels = (int) 1; "
66 "format = (string) " FORMAT_STR ", "
67 "layout = (string) interleaved, "
68 "rate = (int) [ 6000, 48000 ], "
69 "channels = (int) 2, " "channel-mask = (bitmask) 0x3")
72 static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
75 GST_STATIC_CAPS ("audio/x-speex, "
76 "rate = (int) [ 6000, 48000 ], " "channels = (int) [ 1, 2]")
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
84 #define DEFAULT_VAD FALSE
85 #define DEFAULT_DTX FALSE
86 #define DEFAULT_COMPLEXITY 3
87 #define DEFAULT_NFRAMES 1
104 #define GST_TYPE_SPEEX_ENC_MODE (gst_speex_enc_mode_get_type())
106 gst_speex_enc_mode_get_type (void)
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"},
116 if (G_UNLIKELY (speex_enc_mode_type == 0)) {
117 speex_enc_mode_type = g_enum_register_static ("GstSpeexEncMode",
120 return speex_enc_mode_type;
123 static void gst_speex_enc_finalize (GObject * object);
125 static gboolean gst_speex_enc_setup (GstSpeexEnc * enc);
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);
132 static GstFlowReturn gst_speex_enc_encode (GstSpeexEnc * enc, GstBuffer * buf);
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,
140 static gboolean gst_speex_enc_sink_event (GstAudioEncoder * enc,
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));
149 gst_speex_enc_class_init (GstSpeexEncClass * klass)
151 GObjectClass *gobject_class;
152 GstElementClass *gstelement_class;
153 GstAudioEncoderClass *base_class;
155 gobject_class = (GObjectClass *) klass;
156 gstelement_class = (GstElementClass *) klass;
157 base_class = (GstAudioEncoderClass *) klass;
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;
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);
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));
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>");
222 GST_DEBUG_CATEGORY_INIT (speexenc_debug, "speexenc", 0, "Speex encoder");
226 gst_speex_enc_finalize (GObject * object)
230 enc = GST_SPEEX_ENC (object);
232 g_free (enc->last_message);
234 G_OBJECT_CLASS (parent_class)->finalize (object);
238 gst_speex_enc_init (GstSpeexEnc * enc)
240 GstAudioEncoder *benc = GST_AUDIO_ENCODER (enc);
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);
248 gst_speex_enc_start (GstAudioEncoder * benc)
250 GstSpeexEnc *enc = GST_SPEEX_ENC (benc);
252 GST_DEBUG_OBJECT (enc, "start");
253 speex_bits_init (&enc->bits);
254 enc->tags = gst_tag_list_new_empty ();
255 enc->header_sent = FALSE;
261 gst_speex_enc_stop (GstAudioEncoder * benc)
263 GstSpeexEnc *enc = GST_SPEEX_ENC (benc);
265 GST_DEBUG_OBJECT (enc, "stop");
266 enc->header_sent = FALSE;
268 speex_encoder_destroy (enc->state);
271 speex_bits_destroy (&enc->bits);
272 gst_tag_list_unref (enc->tags);
275 gst_tag_setter_reset_tags (GST_TAG_SETTER (enc));
281 gst_speex_enc_get_latency (GstSpeexEnc * enc)
283 /* See the Speex manual section "Latency and algorithmic delay" */
284 if (enc->rate == 8000)
285 return 30 * GST_MSECOND;
287 return 34 * GST_MSECOND;
291 gst_speex_enc_set_format (GstAudioEncoder * benc, GstAudioInfo * info)
295 enc = GST_SPEEX_ENC (benc);
297 enc->channels = GST_AUDIO_INFO_CHANNELS (info);
298 enc->rate = GST_AUDIO_INFO_RATE (info);
300 /* handle reconfigure */
302 speex_encoder_destroy (enc->state);
306 if (!gst_speex_enc_setup (enc))
309 /* feedback to base class */
310 gst_audio_encoder_set_latency (benc,
311 gst_speex_enc_get_latency (enc), gst_speex_enc_get_latency (enc));
312 gst_audio_encoder_set_lookahead (benc, enc->lookahead);
314 if (enc->nframes == 0) {
315 /* as many frames as available input allows */
316 gst_audio_encoder_set_frame_samples_min (benc, enc->frame_size);
317 gst_audio_encoder_set_frame_samples_max (benc, enc->frame_size);
318 gst_audio_encoder_set_frame_max (benc, 0);
320 /* exactly as many frames as configured */
321 gst_audio_encoder_set_frame_samples_min (benc,
322 enc->frame_size * enc->nframes);
323 gst_audio_encoder_set_frame_samples_max (benc,
324 enc->frame_size * enc->nframes);
325 gst_audio_encoder_set_frame_max (benc, 1);
332 gst_speex_enc_create_metadata_buffer (GstSpeexEnc * enc)
334 const GstTagList *user_tags;
335 GstTagList *merged_tags;
336 GstBuffer *comments = NULL;
338 user_tags = gst_tag_setter_get_tag_list (GST_TAG_SETTER (enc));
340 GST_DEBUG_OBJECT (enc, "upstream tags = %" GST_PTR_FORMAT, enc->tags);
341 GST_DEBUG_OBJECT (enc, "user-set tags = %" GST_PTR_FORMAT, user_tags);
343 /* gst_tag_list_merge() will handle NULL for either or both lists fine */
344 merged_tags = gst_tag_list_merge (user_tags, enc->tags,
345 gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (enc)));
347 if (merged_tags == NULL)
348 merged_tags = gst_tag_list_new_empty ();
350 GST_DEBUG_OBJECT (enc, "merged tags = %" GST_PTR_FORMAT, merged_tags);
351 comments = gst_tag_list_to_vorbiscomment_buffer (merged_tags, NULL,
352 0, "Encoded with GStreamer Speexenc");
353 gst_tag_list_unref (merged_tags);
355 GST_BUFFER_OFFSET (comments) = 0;
356 GST_BUFFER_OFFSET_END (comments) = 0;
362 gst_speex_enc_set_last_msg (GstSpeexEnc * enc, const gchar * msg)
364 g_free (enc->last_message);
365 enc->last_message = g_strdup (msg);
366 GST_WARNING_OBJECT (enc, "%s", msg);
367 g_object_notify (G_OBJECT (enc), "last-message");
371 gst_speex_enc_setup (GstSpeexEnc * enc)
374 case GST_SPEEX_ENC_MODE_UWB:
375 GST_LOG_OBJECT (enc, "configuring for requested UWB mode");
376 enc->speex_mode = speex_lib_get_mode (SPEEX_MODEID_UWB);
378 case GST_SPEEX_ENC_MODE_WB:
379 GST_LOG_OBJECT (enc, "configuring for requested WB mode");
380 enc->speex_mode = speex_lib_get_mode (SPEEX_MODEID_WB);
382 case GST_SPEEX_ENC_MODE_NB:
383 GST_LOG_OBJECT (enc, "configuring for requested NB mode");
384 enc->speex_mode = speex_lib_get_mode (SPEEX_MODEID_NB);
386 case GST_SPEEX_ENC_MODE_AUTO:
388 GST_LOG_OBJECT (enc, "finding best mode");
393 if (enc->rate > 25000) {
394 if (enc->mode == GST_SPEEX_ENC_MODE_AUTO) {
395 GST_LOG_OBJECT (enc, "selected UWB mode for samplerate %d", enc->rate);
396 enc->speex_mode = speex_lib_get_mode (SPEEX_MODEID_UWB);
398 if (enc->speex_mode != speex_lib_get_mode (SPEEX_MODEID_UWB)) {
399 gst_speex_enc_set_last_msg (enc,
400 "Warning: suggest to use ultra wide band mode for this rate");
403 } else if (enc->rate > 12500) {
404 if (enc->mode == GST_SPEEX_ENC_MODE_AUTO) {
405 GST_LOG_OBJECT (enc, "selected WB mode for samplerate %d", enc->rate);
406 enc->speex_mode = speex_lib_get_mode (SPEEX_MODEID_WB);
408 if (enc->speex_mode != speex_lib_get_mode (SPEEX_MODEID_WB)) {
409 gst_speex_enc_set_last_msg (enc,
410 "Warning: suggest to use wide band mode for this rate");
414 if (enc->mode == GST_SPEEX_ENC_MODE_AUTO) {
415 GST_LOG_OBJECT (enc, "selected NB mode for samplerate %d", enc->rate);
416 enc->speex_mode = speex_lib_get_mode (SPEEX_MODEID_NB);
418 if (enc->speex_mode != speex_lib_get_mode (SPEEX_MODEID_NB)) {
419 gst_speex_enc_set_last_msg (enc,
420 "Warning: suggest to use narrow band mode for this rate");
425 if (enc->rate != 8000 && enc->rate != 16000 && enc->rate != 32000) {
426 gst_speex_enc_set_last_msg (enc,
427 "Warning: speex is optimized for 8, 16 and 32 KHz");
430 speex_init_header (&enc->header, enc->rate, 1, enc->speex_mode);
431 enc->header.frames_per_packet = enc->nframes;
432 enc->header.vbr = enc->vbr;
433 enc->header.nb_channels = enc->channels;
435 /*Initialize Speex encoder */
436 enc->state = speex_encoder_init (enc->speex_mode);
438 speex_encoder_ctl (enc->state, SPEEX_GET_FRAME_SIZE, &enc->frame_size);
439 speex_encoder_ctl (enc->state, SPEEX_SET_COMPLEXITY, &enc->complexity);
440 speex_encoder_ctl (enc->state, SPEEX_SET_SAMPLING_RATE, &enc->rate);
443 speex_encoder_ctl (enc->state, SPEEX_SET_VBR_QUALITY, &enc->quality);
445 gint tmp = floor (enc->quality);
447 speex_encoder_ctl (enc->state, SPEEX_SET_QUALITY, &tmp);
450 if (enc->quality >= 0.0 && enc->vbr) {
451 gst_speex_enc_set_last_msg (enc,
452 "Warning: bitrate option is overriding quality");
454 speex_encoder_ctl (enc->state, SPEEX_SET_BITRATE, &enc->bitrate);
459 speex_encoder_ctl (enc->state, SPEEX_SET_VBR, &tmp);
460 } else if (enc->vad) {
463 speex_encoder_ctl (enc->state, SPEEX_SET_VAD, &tmp);
469 speex_encoder_ctl (enc->state, SPEEX_SET_DTX, &tmp);
472 if (enc->dtx && !(enc->vbr || enc->abr || enc->vad)) {
473 gst_speex_enc_set_last_msg (enc,
474 "Warning: dtx is useless without vad, vbr or abr");
475 } else if ((enc->vbr || enc->abr) && (enc->vad)) {
476 gst_speex_enc_set_last_msg (enc,
477 "Warning: vad is already implied by vbr or abr");
481 speex_encoder_ctl (enc->state, SPEEX_SET_ABR, &enc->abr);
484 speex_encoder_ctl (enc->state, SPEEX_GET_LOOKAHEAD, &enc->lookahead);
486 GST_LOG_OBJECT (enc, "we have frame size %d, lookahead %d", enc->frame_size,
493 gst_speex_enc_sink_event (GstAudioEncoder * benc, GstEvent * event)
497 enc = GST_SPEEX_ENC (benc);
499 switch (GST_EVENT_TYPE (event)) {
505 gst_event_parse_tag (event, &list);
506 gst_tag_list_insert (enc->tags, list,
507 gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (enc)));
509 g_assert_not_reached ();
517 /* we only peeked, let base class handle it */
518 return GST_AUDIO_ENCODER_CLASS (parent_class)->sink_event (benc, event);
522 gst_speex_enc_encode (GstSpeexEnc * enc, GstBuffer * buf)
524 gint frame_size = enc->frame_size;
525 gint bytes = frame_size * 2 * enc->channels, samples;
526 gint outsize, written, dtx_ret = 0;
528 guint8 *data, *data0 = NULL, *bdata;
531 GstFlowReturn ret = GST_FLOW_OK;
533 if (G_LIKELY (buf)) {
534 gst_buffer_map (buf, &map, GST_MAP_READ);
538 if (G_UNLIKELY (bsize % bytes)) {
539 GST_DEBUG_OBJECT (enc, "draining; adding silence samples");
541 size = ((bsize / bytes) + 1) * bytes;
542 data0 = data = g_malloc0 (size);
543 memcpy (data, bdata, bsize);
544 gst_buffer_unmap (buf, &map);
551 GST_DEBUG_OBJECT (enc, "nothing to drain");
555 samples = size / (2 * enc->channels);
556 speex_bits_reset (&enc->bits);
558 /* FIXME what about dropped samples if DTS enabled ?? */
561 GST_DEBUG_OBJECT (enc, "encoding %d samples (%d bytes)", frame_size, bytes);
563 if (enc->channels == 2) {
564 speex_encode_stereo_int ((gint16 *) data, frame_size, &enc->bits);
566 dtx_ret += speex_encode_int (enc->state, (gint16 *) data, &enc->bits);
572 speex_bits_insert_terminator (&enc->bits);
573 outsize = speex_bits_nbytes (&enc->bits);
576 gst_buffer_unmap (buf, &map);
579 ret = gst_pad_alloc_buffer_and_set_caps (GST_AUDIO_ENCODER_SRC_PAD (enc),
580 GST_BUFFER_OFFSET_NONE, outsize,
581 GST_PAD_CAPS (GST_AUDIO_ENCODER_SRC_PAD (enc)), &outbuf);
583 if ((GST_FLOW_OK != ret))
586 outbuf = gst_buffer_new_allocate (NULL, outsize, NULL);
587 gst_buffer_map (outbuf, &map, GST_MAP_WRITE);
589 written = speex_bits_write (&enc->bits, (gchar *) map.data, outsize);
591 if (G_UNLIKELY (written < outsize)) {
592 GST_ERROR_OBJECT (enc, "short write: %d < %d bytes", written, outsize);
593 } else if (G_UNLIKELY (written > outsize)) {
594 GST_ERROR_OBJECT (enc, "overrun: %d > %d bytes", written, outsize);
597 gst_buffer_unmap (outbuf, &map);
598 gst_buffer_resize (outbuf, 0, written);
601 GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_GAP);
603 ret = gst_audio_encoder_finish_frame (GST_AUDIO_ENCODER (enc),
612 * (really really) FIXME: move into core (dixit tpm)
615 * _gst_caps_set_buffer_array:
617 * @field: field in caps to set
618 * @buf: header buffers
620 * Adds given buffers to an array of buffers set as the given @field
621 * on the given @caps. List of buffer arguments must be NULL-terminated.
623 * Returns: input caps with a streamheader field added, or NULL if some error
626 _gst_caps_set_buffer_array (GstCaps * caps, const gchar * field,
627 GstBuffer * buf, ...)
629 GstStructure *structure = NULL;
631 GValue array = { 0 };
632 GValue value = { 0 };
634 g_return_val_if_fail (caps != NULL, NULL);
635 g_return_val_if_fail (gst_caps_is_fixed (caps), NULL);
636 g_return_val_if_fail (field != NULL, NULL);
638 caps = gst_caps_make_writable (caps);
639 structure = gst_caps_get_structure (caps, 0);
641 g_value_init (&array, GST_TYPE_ARRAY);
644 /* put buffers in a fixed list */
646 g_assert (gst_buffer_is_writable (buf));
649 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_HEADER);
651 g_value_init (&value, GST_TYPE_BUFFER);
652 buf = gst_buffer_copy (buf);
653 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_HEADER);
654 gst_value_set_buffer (&value, buf);
655 gst_buffer_unref (buf);
656 gst_value_array_append_value (&array, &value);
657 g_value_unset (&value);
659 buf = va_arg (va, GstBuffer *);
662 gst_structure_set_value (structure, field, &array);
663 g_value_unset (&array);
669 gst_speex_enc_handle_frame (GstAudioEncoder * benc, GstBuffer * buf)
672 GstFlowReturn ret = GST_FLOW_OK;
674 enc = GST_SPEEX_ENC (benc);
676 if (!enc->header_sent) {
677 /* Speex streams begin with two headers; the initial header (with
678 most of the codec setup parameters) which is mandated by the Ogg
679 bitstream spec. The second header holds any comment fields.
680 We merely need to make the headers, then pass them to libspeex
681 one at a time; libspeex handles the additional Ogg bitstream
683 GstBuffer *buf1, *buf2;
689 /* create header buffer */
690 data = (guint8 *) speex_header_to_packet (&enc->header, &data_len);
691 buf1 = gst_buffer_new_wrapped (data, data_len);
692 GST_BUFFER_OFFSET_END (buf1) = 0;
693 GST_BUFFER_OFFSET (buf1) = 0;
695 /* create comment buffer */
696 buf2 = gst_speex_enc_create_metadata_buffer (enc);
698 /* mark and put on caps */
699 caps = gst_caps_new_simple ("audio/x-speex", "rate", G_TYPE_INT, enc->rate,
700 "channels", G_TYPE_INT, enc->channels, NULL);
701 caps = _gst_caps_set_buffer_array (caps, "streamheader", buf1, buf2, NULL);
703 /* negotiate with these caps */
704 GST_DEBUG_OBJECT (enc, "here are the caps: %" GST_PTR_FORMAT, caps);
706 gst_audio_encoder_set_output_format (GST_AUDIO_ENCODER (enc), caps);
707 gst_caps_unref (caps);
709 /* push out buffers */
710 /* store buffers for later pre_push sending */
712 GST_DEBUG_OBJECT (enc, "storing header buffers");
713 headers = g_list_prepend (headers, buf2);
714 headers = g_list_prepend (headers, buf1);
715 gst_audio_encoder_set_headers (benc, headers);
717 enc->header_sent = TRUE;
720 GST_DEBUG_OBJECT (enc, "received buffer %p of %" G_GSIZE_FORMAT " bytes", buf,
721 buf ? gst_buffer_get_size (buf) : 0);
723 ret = gst_speex_enc_encode (enc, buf);
729 gst_speex_enc_get_property (GObject * object, guint prop_id, GValue * value,
734 enc = GST_SPEEX_ENC (object);
738 g_value_set_float (value, enc->quality);
741 g_value_set_int (value, enc->bitrate);
744 g_value_set_enum (value, enc->mode);
747 g_value_set_boolean (value, enc->vbr);
750 g_value_set_int (value, enc->abr);
753 g_value_set_boolean (value, enc->vad);
756 g_value_set_boolean (value, enc->dtx);
758 case PROP_COMPLEXITY:
759 g_value_set_int (value, enc->complexity);
762 g_value_set_int (value, enc->nframes);
764 case PROP_LAST_MESSAGE:
765 g_value_set_string (value, enc->last_message);
768 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
774 gst_speex_enc_set_property (GObject * object, guint prop_id,
775 const GValue * value, GParamSpec * pspec)
779 enc = GST_SPEEX_ENC (object);
783 enc->quality = g_value_get_float (value);
786 enc->bitrate = g_value_get_int (value);
789 enc->mode = g_value_get_enum (value);
792 enc->vbr = g_value_get_boolean (value);
795 enc->abr = g_value_get_int (value);
798 enc->vad = g_value_get_boolean (value);
801 enc->dtx = g_value_get_boolean (value);
803 case PROP_COMPLEXITY:
804 enc->complexity = g_value_get_int (value);
807 enc->nframes = g_value_get_int (value);
810 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);