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 speex_bits_set_bit_buffer (&enc->bits, NULL, 0);
273 gst_tag_list_unref (enc->tags);
276 gst_tag_setter_reset_tags (GST_TAG_SETTER (enc));
282 gst_speex_enc_get_latency (GstSpeexEnc * enc)
284 /* See the Speex manual section "Latency and algorithmic delay" */
285 if (enc->rate == 8000)
286 return 30 * GST_MSECOND;
288 return 34 * GST_MSECOND;
292 gst_speex_enc_set_format (GstAudioEncoder * benc, GstAudioInfo * info)
296 enc = GST_SPEEX_ENC (benc);
298 enc->channels = GST_AUDIO_INFO_CHANNELS (info);
299 enc->rate = GST_AUDIO_INFO_RATE (info);
301 /* handle reconfigure */
303 speex_encoder_destroy (enc->state);
307 if (!gst_speex_enc_setup (enc))
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);
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);
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);
333 gst_speex_enc_create_metadata_buffer (GstSpeexEnc * enc)
335 const GstTagList *user_tags;
336 GstTagList *merged_tags;
337 GstBuffer *comments = NULL;
339 user_tags = gst_tag_setter_get_tag_list (GST_TAG_SETTER (enc));
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);
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)));
348 if (merged_tags == NULL)
349 merged_tags = gst_tag_list_new_empty ();
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);
356 GST_BUFFER_OFFSET (comments) = 0;
357 GST_BUFFER_OFFSET_END (comments) = 0;
363 gst_speex_enc_set_last_msg (GstSpeexEnc * enc, const gchar * msg)
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");
372 gst_speex_enc_setup (GstSpeexEnc * enc)
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);
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);
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);
387 case GST_SPEEX_ENC_MODE_AUTO:
389 GST_LOG_OBJECT (enc, "finding best mode");
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);
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");
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);
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");
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);
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");
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");
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;
436 /*Initialize Speex encoder */
437 enc->state = speex_encoder_init (enc->speex_mode);
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);
444 speex_encoder_ctl (enc->state, SPEEX_SET_VBR_QUALITY, &enc->quality);
446 gint tmp = floor (enc->quality);
448 speex_encoder_ctl (enc->state, SPEEX_SET_QUALITY, &tmp);
451 if (enc->quality >= 0.0 && enc->vbr) {
452 gst_speex_enc_set_last_msg (enc,
453 "Warning: bitrate option is overriding quality");
455 speex_encoder_ctl (enc->state, SPEEX_SET_BITRATE, &enc->bitrate);
460 speex_encoder_ctl (enc->state, SPEEX_SET_VBR, &tmp);
461 } else if (enc->vad) {
464 speex_encoder_ctl (enc->state, SPEEX_SET_VAD, &tmp);
470 speex_encoder_ctl (enc->state, SPEEX_SET_DTX, &tmp);
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");
482 speex_encoder_ctl (enc->state, SPEEX_SET_ABR, &enc->abr);
485 speex_encoder_ctl (enc->state, SPEEX_GET_LOOKAHEAD, &enc->lookahead);
487 GST_LOG_OBJECT (enc, "we have frame size %d, lookahead %d", enc->frame_size,
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 */
519 return GST_AUDIO_ENCODER_CLASS (parent_class)->sink_event (benc, event);
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;
529 guint8 *data, *data0 = NULL, *bdata;
532 GstFlowReturn ret = GST_FLOW_OK;
534 if (G_LIKELY (buf)) {
535 gst_buffer_map (buf, &map, GST_MAP_READ);
539 if (G_UNLIKELY (bsize % bytes)) {
540 GST_DEBUG_OBJECT (enc, "draining; adding silence samples");
542 size = ((bsize / bytes) + 1) * bytes;
543 data0 = data = g_malloc0 (size);
544 memcpy (data, bdata, bsize);
545 gst_buffer_unmap (buf, &map);
552 GST_DEBUG_OBJECT (enc, "nothing to drain");
556 samples = size / (2 * enc->channels);
557 speex_bits_reset (&enc->bits);
559 /* FIXME what about dropped samples if DTS enabled ?? */
562 GST_DEBUG_OBJECT (enc, "encoding %d samples (%d bytes)", frame_size, bytes);
564 if (enc->channels == 2) {
565 speex_encode_stereo_int ((gint16 *) data, frame_size, &enc->bits);
567 dtx_ret += speex_encode_int (enc->state, (gint16 *) data, &enc->bits);
573 speex_bits_insert_terminator (&enc->bits);
574 outsize = speex_bits_nbytes (&enc->bits);
577 gst_buffer_unmap (buf, &map);
580 ret = gst_pad_alloc_buffer_and_set_caps (GST_AUDIO_ENCODER_SRC_PAD (enc),
581 GST_BUFFER_OFFSET_NONE, outsize,
582 GST_PAD_CAPS (GST_AUDIO_ENCODER_SRC_PAD (enc)), &outbuf);
584 if ((GST_FLOW_OK != ret))
587 outbuf = gst_buffer_new_allocate (NULL, outsize, NULL);
588 gst_buffer_map (outbuf, &map, GST_MAP_WRITE);
590 written = speex_bits_write (&enc->bits, (gchar *) map.data, outsize);
592 if (G_UNLIKELY (written < outsize)) {
593 GST_ERROR_OBJECT (enc, "short write: %d < %d bytes", written, outsize);
594 } else if (G_UNLIKELY (written > outsize)) {
595 GST_ERROR_OBJECT (enc, "overrun: %d > %d bytes", written, outsize);
598 gst_buffer_unmap (outbuf, &map);
599 gst_buffer_resize (outbuf, 0, written);
602 GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_GAP);
604 ret = gst_audio_encoder_finish_frame (GST_AUDIO_ENCODER (enc),
613 * (really really) FIXME: move into core (dixit tpm)
616 * _gst_caps_set_buffer_array:
617 * @caps: (transfer full): a #GstCaps
618 * @field: field in caps to set
619 * @buf: header buffers
621 * Adds given buffers to an array of buffers set as the given @field
622 * on the given @caps. List of buffer arguments must be NULL-terminated.
624 * Returns: (transfer full): input caps with a streamheader field added, or NULL
625 * if some error occurred
628 _gst_caps_set_buffer_array (GstCaps * caps, const gchar * field,
629 GstBuffer * buf, ...)
631 GstStructure *structure = NULL;
633 GValue array = { 0 };
634 GValue value = { 0 };
636 g_return_val_if_fail (caps != NULL, NULL);
637 g_return_val_if_fail (gst_caps_is_fixed (caps), NULL);
638 g_return_val_if_fail (field != NULL, NULL);
640 caps = gst_caps_make_writable (caps);
641 structure = gst_caps_get_structure (caps, 0);
643 g_value_init (&array, GST_TYPE_ARRAY);
646 /* put buffers in a fixed list */
648 g_assert (gst_buffer_is_writable (buf));
651 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_HEADER);
653 g_value_init (&value, GST_TYPE_BUFFER);
654 buf = gst_buffer_copy (buf);
655 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_HEADER);
656 gst_value_set_buffer (&value, buf);
657 gst_buffer_unref (buf);
658 gst_value_array_append_value (&array, &value);
659 g_value_unset (&value);
661 buf = va_arg (va, GstBuffer *);
665 gst_structure_set_value (structure, field, &array);
666 g_value_unset (&array);
672 gst_speex_enc_handle_frame (GstAudioEncoder * benc, GstBuffer * buf)
675 GstFlowReturn ret = GST_FLOW_OK;
677 enc = GST_SPEEX_ENC (benc);
679 if (!enc->header_sent) {
680 /* Speex streams begin with two headers; the initial header (with
681 most of the codec setup parameters) which is mandated by the Ogg
682 bitstream spec. The second header holds any comment fields.
683 We merely need to make the headers, then pass them to libspeex
684 one at a time; libspeex handles the additional Ogg bitstream
686 GstBuffer *buf1, *buf2;
692 /* create header buffer */
693 data = (guint8 *) speex_header_to_packet (&enc->header, &data_len);
694 buf1 = gst_buffer_new_wrapped (data, data_len);
695 GST_BUFFER_OFFSET_END (buf1) = 0;
696 GST_BUFFER_OFFSET (buf1) = 0;
698 /* create comment buffer */
699 buf2 = gst_speex_enc_create_metadata_buffer (enc);
701 /* mark and put on caps */
702 caps = gst_caps_new_simple ("audio/x-speex", "rate", G_TYPE_INT, enc->rate,
703 "channels", G_TYPE_INT, enc->channels, NULL);
704 caps = _gst_caps_set_buffer_array (caps, "streamheader", buf1, buf2, NULL);
706 /* negotiate with these caps */
707 GST_DEBUG_OBJECT (enc, "here are the caps: %" GST_PTR_FORMAT, caps);
709 gst_audio_encoder_set_output_format (GST_AUDIO_ENCODER (enc), caps);
710 gst_caps_unref (caps);
712 /* push out buffers */
713 /* store buffers for later pre_push sending */
715 GST_DEBUG_OBJECT (enc, "storing header buffers");
716 headers = g_list_prepend (headers, buf2);
717 headers = g_list_prepend (headers, buf1);
718 gst_audio_encoder_set_headers (benc, headers);
720 enc->header_sent = TRUE;
723 GST_DEBUG_OBJECT (enc, "received buffer %p of %" G_GSIZE_FORMAT " bytes", buf,
724 buf ? gst_buffer_get_size (buf) : 0);
726 ret = gst_speex_enc_encode (enc, buf);
732 gst_speex_enc_get_property (GObject * object, guint prop_id, GValue * value,
737 enc = GST_SPEEX_ENC (object);
741 g_value_set_float (value, enc->quality);
744 g_value_set_int (value, enc->bitrate);
747 g_value_set_enum (value, enc->mode);
750 g_value_set_boolean (value, enc->vbr);
753 g_value_set_int (value, enc->abr);
756 g_value_set_boolean (value, enc->vad);
759 g_value_set_boolean (value, enc->dtx);
761 case PROP_COMPLEXITY:
762 g_value_set_int (value, enc->complexity);
765 g_value_set_int (value, enc->nframes);
767 case PROP_LAST_MESSAGE:
768 g_value_set_string (value, enc->last_message);
771 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
777 gst_speex_enc_set_property (GObject * object, guint prop_id,
778 const GValue * value, GParamSpec * pspec)
782 enc = GST_SPEEX_ENC (object);
786 enc->quality = g_value_get_float (value);
789 enc->bitrate = g_value_get_int (value);
792 enc->mode = g_value_get_enum (value);
795 enc->vbr = g_value_get_boolean (value);
798 enc->abr = g_value_get_int (value);
801 enc->vad = g_value_get_boolean (value);
804 enc->dtx = g_value_get_boolean (value);
806 case PROP_COMPLEXITY:
807 enc->complexity = g_value_get_int (value);
810 enc->nframes = g_value_get_int (value);
813 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);