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,
136 gst_speex_enc_pre_push (GstAudioEncoder * benc, GstBuffer ** buffer);
139 gst_speex_enc_setup_interfaces (GType speexenc_type)
141 static const GInterfaceInfo tag_setter_info = { NULL, NULL, NULL };
143 g_type_add_interface_static (speexenc_type, GST_TYPE_TAG_SETTER,
146 GST_DEBUG_CATEGORY_INIT (speexenc_debug, "speexenc", 0, "Speex encoder");
149 GST_BOILERPLATE_FULL (GstSpeexEnc, gst_speex_enc, GstAudioEncoder,
150 GST_TYPE_AUDIO_ENCODER, gst_speex_enc_setup_interfaces);
153 gst_speex_enc_base_init (gpointer g_class)
155 GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
157 gst_element_class_add_pad_template (element_class,
158 gst_static_pad_template_get (&src_factory));
159 gst_element_class_add_pad_template (element_class,
160 gst_static_pad_template_get (&sink_factory));
161 gst_element_class_set_details_simple (element_class, "Speex audio encoder",
162 "Codec/Encoder/Audio",
163 "Encodes audio in Speex format", "Wim Taymans <wim@fluendo.com>");
167 gst_speex_enc_class_init (GstSpeexEncClass * klass)
169 GObjectClass *gobject_class;
170 GstAudioEncoderClass *base_class;
172 gobject_class = (GObjectClass *) klass;
173 base_class = (GstAudioEncoderClass *) klass;
175 gobject_class->set_property = gst_speex_enc_set_property;
176 gobject_class->get_property = gst_speex_enc_get_property;
178 base_class->start = GST_DEBUG_FUNCPTR (gst_speex_enc_start);
179 base_class->stop = GST_DEBUG_FUNCPTR (gst_speex_enc_stop);
180 base_class->set_format = GST_DEBUG_FUNCPTR (gst_speex_enc_set_format);
181 base_class->handle_frame = GST_DEBUG_FUNCPTR (gst_speex_enc_handle_frame);
182 base_class->event = GST_DEBUG_FUNCPTR (gst_speex_enc_sink_event);
183 base_class->pre_push = GST_DEBUG_FUNCPTR (gst_speex_enc_pre_push);
185 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_QUALITY,
186 g_param_spec_float ("quality", "Quality", "Encoding quality",
187 0.0, 10.0, DEFAULT_QUALITY,
188 G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
189 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_BITRATE,
190 g_param_spec_int ("bitrate", "Encoding Bit-rate",
191 "Specify an encoding bit-rate (in bps). (0 = automatic)",
192 0, G_MAXINT, DEFAULT_BITRATE,
193 G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
194 g_object_class_install_property (gobject_class, PROP_MODE,
195 g_param_spec_enum ("mode", "Mode", "The encoding mode",
196 GST_TYPE_SPEEX_ENC_MODE, GST_SPEEX_ENC_MODE_AUTO,
197 G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
198 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_VBR,
199 g_param_spec_boolean ("vbr", "VBR",
200 "Enable variable bit-rate", DEFAULT_VBR,
201 G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
202 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_ABR,
203 g_param_spec_int ("abr", "ABR",
204 "Enable average bit-rate (0 = disabled)",
205 0, G_MAXINT, DEFAULT_ABR,
206 G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
207 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_VAD,
208 g_param_spec_boolean ("vad", "VAD",
209 "Enable voice activity detection", DEFAULT_VAD,
210 G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
211 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_DTX,
212 g_param_spec_boolean ("dtx", "DTX",
213 "Enable discontinuous transmission", DEFAULT_DTX,
214 G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
215 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_COMPLEXITY,
216 g_param_spec_int ("complexity", "Complexity",
217 "Set encoding complexity",
218 0, G_MAXINT, DEFAULT_COMPLEXITY,
219 G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
220 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_NFRAMES,
221 g_param_spec_int ("nframes", "NFrames",
222 "Number of frames per buffer",
223 0, G_MAXINT, DEFAULT_NFRAMES,
224 G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
225 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_LAST_MESSAGE,
226 g_param_spec_string ("last-message", "last-message",
227 "The last status message", NULL,
228 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
230 gobject_class->finalize = gst_speex_enc_finalize;
234 gst_speex_enc_finalize (GObject * object)
238 enc = GST_SPEEX_ENC (object);
240 g_free (enc->last_message);
242 G_OBJECT_CLASS (parent_class)->finalize (object);
246 gst_speex_enc_init (GstSpeexEnc * enc, GstSpeexEncClass * klass)
248 GstAudioEncoder *benc = GST_AUDIO_ENCODER (enc);
250 /* arrange granulepos marking (and required perfect ts) */
251 gst_audio_encoder_set_mark_granule (benc, TRUE);
252 gst_audio_encoder_set_perfect_timestamp (benc, TRUE);
256 gst_speex_enc_start (GstAudioEncoder * benc)
258 GstSpeexEnc *enc = GST_SPEEX_ENC (benc);
260 GST_DEBUG_OBJECT (enc, "start");
261 speex_bits_init (&enc->bits);
262 enc->tags = gst_tag_list_new ();
263 enc->header_sent = FALSE;
269 gst_speex_enc_stop (GstAudioEncoder * benc)
271 GstSpeexEnc *enc = GST_SPEEX_ENC (benc);
273 GST_DEBUG_OBJECT (enc, "stop");
274 enc->header_sent = FALSE;
276 speex_encoder_destroy (enc->state);
279 speex_bits_destroy (&enc->bits);
280 gst_tag_list_free (enc->tags);
282 g_slist_foreach (enc->headers, (GFunc) gst_buffer_unref, NULL);
285 gst_tag_setter_reset_tags (GST_TAG_SETTER (enc));
291 gst_speex_enc_get_latency (GstSpeexEnc * enc)
293 /* See the Speex manual section "Latency and algorithmic delay" */
294 if (enc->rate == 8000)
295 return 30 * GST_MSECOND;
297 return 34 * GST_MSECOND;
301 gst_speex_enc_set_format (GstAudioEncoder * benc, GstAudioInfo * info)
305 enc = GST_SPEEX_ENC (benc);
307 enc->channels = GST_AUDIO_INFO_CHANNELS (info);
308 enc->rate = GST_AUDIO_INFO_RATE (info);
310 /* handle reconfigure */
312 speex_encoder_destroy (enc->state);
316 if (!gst_speex_enc_setup (enc))
319 /* feedback to base class */
320 gst_audio_encoder_set_latency (benc,
321 gst_speex_enc_get_latency (enc), gst_speex_enc_get_latency (enc));
322 gst_audio_encoder_set_lookahead (benc, enc->lookahead);
324 if (enc->nframes == 0) {
325 /* as many frames as available input allows */
326 gst_audio_encoder_set_frame_samples_min (benc, enc->frame_size);
327 gst_audio_encoder_set_frame_samples_max (benc, enc->frame_size);
328 gst_audio_encoder_set_frame_max (benc, 0);
330 /* exactly as many frames as configured */
331 gst_audio_encoder_set_frame_samples_min (benc,
332 enc->frame_size * enc->nframes);
333 gst_audio_encoder_set_frame_samples_max (benc,
334 enc->frame_size * enc->nframes);
335 gst_audio_encoder_set_frame_max (benc, 1);
342 gst_speex_enc_create_metadata_buffer (GstSpeexEnc * enc)
344 const GstTagList *user_tags;
345 GstTagList *merged_tags;
346 GstBuffer *comments = NULL;
348 user_tags = gst_tag_setter_get_tag_list (GST_TAG_SETTER (enc));
350 GST_DEBUG_OBJECT (enc, "upstream tags = %" GST_PTR_FORMAT, enc->tags);
351 GST_DEBUG_OBJECT (enc, "user-set tags = %" GST_PTR_FORMAT, user_tags);
353 /* gst_tag_list_merge() will handle NULL for either or both lists fine */
354 merged_tags = gst_tag_list_merge (user_tags, enc->tags,
355 gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (enc)));
357 if (merged_tags == NULL)
358 merged_tags = gst_tag_list_new ();
360 GST_DEBUG_OBJECT (enc, "merged tags = %" GST_PTR_FORMAT, merged_tags);
361 comments = gst_tag_list_to_vorbiscomment_buffer (merged_tags, NULL,
362 0, "Encoded with GStreamer Speexenc");
363 gst_tag_list_free (merged_tags);
365 GST_BUFFER_OFFSET (comments) = 0;
366 GST_BUFFER_OFFSET_END (comments) = 0;
372 gst_speex_enc_set_last_msg (GstSpeexEnc * enc, const gchar * msg)
374 g_free (enc->last_message);
375 enc->last_message = g_strdup (msg);
376 GST_WARNING_OBJECT (enc, "%s", msg);
377 g_object_notify (G_OBJECT (enc), "last-message");
381 gst_speex_enc_setup (GstSpeexEnc * enc)
384 case GST_SPEEX_ENC_MODE_UWB:
385 GST_LOG_OBJECT (enc, "configuring for requested UWB mode");
386 enc->speex_mode = speex_lib_get_mode (SPEEX_MODEID_UWB);
388 case GST_SPEEX_ENC_MODE_WB:
389 GST_LOG_OBJECT (enc, "configuring for requested WB mode");
390 enc->speex_mode = speex_lib_get_mode (SPEEX_MODEID_WB);
392 case GST_SPEEX_ENC_MODE_NB:
393 GST_LOG_OBJECT (enc, "configuring for requested NB mode");
394 enc->speex_mode = speex_lib_get_mode (SPEEX_MODEID_NB);
396 case GST_SPEEX_ENC_MODE_AUTO:
398 GST_LOG_OBJECT (enc, "finding best mode");
403 if (enc->rate > 25000) {
404 if (enc->mode == GST_SPEEX_ENC_MODE_AUTO) {
405 GST_LOG_OBJECT (enc, "selected UWB mode for samplerate %d", enc->rate);
406 enc->speex_mode = speex_lib_get_mode (SPEEX_MODEID_UWB);
408 if (enc->speex_mode != speex_lib_get_mode (SPEEX_MODEID_UWB)) {
409 gst_speex_enc_set_last_msg (enc,
410 "Warning: suggest to use ultra wide band mode for this rate");
413 } else if (enc->rate > 12500) {
414 if (enc->mode == GST_SPEEX_ENC_MODE_AUTO) {
415 GST_LOG_OBJECT (enc, "selected WB mode for samplerate %d", enc->rate);
416 enc->speex_mode = speex_lib_get_mode (SPEEX_MODEID_WB);
418 if (enc->speex_mode != speex_lib_get_mode (SPEEX_MODEID_WB)) {
419 gst_speex_enc_set_last_msg (enc,
420 "Warning: suggest to use wide band mode for this rate");
424 if (enc->mode == GST_SPEEX_ENC_MODE_AUTO) {
425 GST_LOG_OBJECT (enc, "selected NB mode for samplerate %d", enc->rate);
426 enc->speex_mode = speex_lib_get_mode (SPEEX_MODEID_NB);
428 if (enc->speex_mode != speex_lib_get_mode (SPEEX_MODEID_NB)) {
429 gst_speex_enc_set_last_msg (enc,
430 "Warning: suggest to use narrow band mode for this rate");
435 if (enc->rate != 8000 && enc->rate != 16000 && enc->rate != 32000) {
436 gst_speex_enc_set_last_msg (enc,
437 "Warning: speex is optimized for 8, 16 and 32 KHz");
440 speex_init_header (&enc->header, enc->rate, 1, enc->speex_mode);
441 enc->header.frames_per_packet = enc->nframes;
442 enc->header.vbr = enc->vbr;
443 enc->header.nb_channels = enc->channels;
445 /*Initialize Speex encoder */
446 enc->state = speex_encoder_init (enc->speex_mode);
448 speex_encoder_ctl (enc->state, SPEEX_GET_FRAME_SIZE, &enc->frame_size);
449 speex_encoder_ctl (enc->state, SPEEX_SET_COMPLEXITY, &enc->complexity);
450 speex_encoder_ctl (enc->state, SPEEX_SET_SAMPLING_RATE, &enc->rate);
453 speex_encoder_ctl (enc->state, SPEEX_SET_VBR_QUALITY, &enc->quality);
455 gint tmp = floor (enc->quality);
457 speex_encoder_ctl (enc->state, SPEEX_SET_QUALITY, &tmp);
460 if (enc->quality >= 0.0 && enc->vbr) {
461 gst_speex_enc_set_last_msg (enc,
462 "Warning: bitrate option is overriding quality");
464 speex_encoder_ctl (enc->state, SPEEX_SET_BITRATE, &enc->bitrate);
469 speex_encoder_ctl (enc->state, SPEEX_SET_VBR, &tmp);
470 } else if (enc->vad) {
473 speex_encoder_ctl (enc->state, SPEEX_SET_VAD, &tmp);
479 speex_encoder_ctl (enc->state, SPEEX_SET_DTX, &tmp);
482 if (enc->dtx && !(enc->vbr || enc->abr || enc->vad)) {
483 gst_speex_enc_set_last_msg (enc,
484 "Warning: dtx is useless without vad, vbr or abr");
485 } else if ((enc->vbr || enc->abr) && (enc->vad)) {
486 gst_speex_enc_set_last_msg (enc,
487 "Warning: vad is already implied by vbr or abr");
491 speex_encoder_ctl (enc->state, SPEEX_SET_ABR, &enc->abr);
494 speex_encoder_ctl (enc->state, SPEEX_GET_LOOKAHEAD, &enc->lookahead);
496 GST_LOG_OBJECT (enc, "we have frame size %d, lookahead %d", enc->frame_size,
502 /* push out the buffer */
504 gst_speex_enc_push_buffer (GstSpeexEnc * enc, GstBuffer * buffer)
508 size = GST_BUFFER_SIZE (buffer);
509 GST_DEBUG_OBJECT (enc, "pushing output buffer of size %u", size);
511 gst_buffer_set_caps (buffer, GST_PAD_CAPS (GST_AUDIO_ENCODER_SRC_PAD (enc)));
512 return gst_pad_push (GST_AUDIO_ENCODER_SRC_PAD (enc), buffer);
516 gst_speex_enc_sink_event (GstAudioEncoder * benc, GstEvent * event)
520 enc = GST_SPEEX_ENC (benc);
522 switch (GST_EVENT_TYPE (event)) {
528 gst_event_parse_tag (event, &list);
529 gst_tag_list_insert (enc->tags, list,
530 gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (enc)));
532 g_assert_not_reached ();
540 /* we only peeked, let base class handle it */
545 gst_speex_enc_encode (GstSpeexEnc * enc, GstBuffer * buf)
547 gint frame_size = enc->frame_size;
548 gint bytes = frame_size * 2 * enc->channels, samples, size;
549 gint outsize, written, dtx_ret = 0;
550 guint8 *data, *data0 = NULL;
552 GstFlowReturn ret = GST_FLOW_OK;
554 if (G_LIKELY (buf)) {
555 data = GST_BUFFER_DATA (buf);
556 size = GST_BUFFER_SIZE (buf);
558 if (G_UNLIKELY (size % bytes)) {
559 GST_DEBUG_OBJECT (enc, "draining; adding silence samples");
560 size = ((size / bytes) + 1) * bytes;
561 data0 = data = g_malloc0 (size);
562 memcpy (data, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
565 GST_DEBUG_OBJECT (enc, "nothing to drain");
569 samples = size / (2 * enc->channels);
570 speex_bits_reset (&enc->bits);
572 /* FIXME what about dropped samples if DTS enabled ?? */
575 GST_DEBUG_OBJECT (enc, "encoding %d samples (%d bytes)", frame_size, bytes);
577 if (enc->channels == 2) {
578 speex_encode_stereo_int ((gint16 *) data, frame_size, &enc->bits);
580 dtx_ret += speex_encode_int (enc->state, (gint16 *) data, &enc->bits);
586 speex_bits_insert_terminator (&enc->bits);
587 outsize = speex_bits_nbytes (&enc->bits);
589 ret = gst_pad_alloc_buffer_and_set_caps (GST_AUDIO_ENCODER_SRC_PAD (enc),
590 GST_BUFFER_OFFSET_NONE, outsize,
591 GST_PAD_CAPS (GST_AUDIO_ENCODER_SRC_PAD (enc)), &outbuf);
593 if ((GST_FLOW_OK != ret))
596 written = speex_bits_write (&enc->bits,
597 (gchar *) GST_BUFFER_DATA (outbuf), outsize);
599 if (G_UNLIKELY (written < outsize)) {
600 GST_ERROR_OBJECT (enc, "short write: %d < %d bytes", written, outsize);
601 GST_BUFFER_SIZE (outbuf) = written;
602 } else if (G_UNLIKELY (written > outsize)) {
603 GST_ERROR_OBJECT (enc, "overrun: %d > %d bytes", written, outsize);
607 GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_GAP);
609 ret = gst_audio_encoder_finish_frame (GST_AUDIO_ENCODER (enc),
618 * (really really) FIXME: move into core (dixit tpm)
621 * _gst_caps_set_buffer_array:
623 * @field: field in caps to set
624 * @buf: header buffers
626 * Adds given buffers to an array of buffers set as the given @field
627 * on the given @caps. List of buffer arguments must be NULL-terminated.
629 * Returns: input caps with a streamheader field added, or NULL if some error
632 _gst_caps_set_buffer_array (GstCaps * caps, const gchar * field,
633 GstBuffer * buf, ...)
635 GstStructure *structure = NULL;
637 GValue array = { 0 };
638 GValue value = { 0 };
640 g_return_val_if_fail (caps != NULL, NULL);
641 g_return_val_if_fail (gst_caps_is_fixed (caps), NULL);
642 g_return_val_if_fail (field != NULL, NULL);
644 caps = gst_caps_make_writable (caps);
645 structure = gst_caps_get_structure (caps, 0);
647 g_value_init (&array, GST_TYPE_ARRAY);
650 /* put buffers in a fixed list */
652 g_assert (gst_buffer_is_metadata_writable (buf));
655 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_IN_CAPS);
657 g_value_init (&value, GST_TYPE_BUFFER);
658 buf = gst_buffer_copy (buf);
659 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_IN_CAPS);
660 gst_value_set_buffer (&value, buf);
661 gst_buffer_unref (buf);
662 gst_value_array_append_value (&array, &value);
663 g_value_unset (&value);
665 buf = va_arg (va, GstBuffer *);
668 gst_structure_set_value (structure, field, &array);
669 g_value_unset (&array);
675 gst_speex_enc_handle_frame (GstAudioEncoder * benc, GstBuffer * buf)
678 GstFlowReturn ret = GST_FLOW_OK;
680 enc = GST_SPEEX_ENC (benc);
682 if (!enc->header_sent) {
683 /* Speex streams begin with two headers; the initial header (with
684 most of the codec setup parameters) which is mandated by the Ogg
685 bitstream spec. The second header holds any comment fields.
686 We merely need to make the headers, then pass them to libspeex
687 one at a time; libspeex handles the additional Ogg bitstream
689 GstBuffer *buf1, *buf2;
694 /* create header buffer */
695 data = (guint8 *) speex_header_to_packet (&enc->header, &data_len);
696 buf1 = gst_buffer_new ();
697 GST_BUFFER_DATA (buf1) = GST_BUFFER_MALLOCDATA (buf1) = data;
698 GST_BUFFER_SIZE (buf1) = data_len;
699 GST_BUFFER_OFFSET_END (buf1) = 0;
700 GST_BUFFER_OFFSET (buf1) = 0;
702 /* create comment buffer */
703 buf2 = gst_speex_enc_create_metadata_buffer (enc);
705 /* mark and put on caps */
706 caps = gst_caps_new_simple ("audio/x-speex", "rate", G_TYPE_INT, enc->rate,
707 "channels", G_TYPE_INT, enc->channels, NULL);
708 caps = _gst_caps_set_buffer_array (caps, "streamheader", buf1, buf2, NULL);
710 /* negotiate with these caps */
711 GST_DEBUG_OBJECT (enc, "here are the caps: %" GST_PTR_FORMAT, caps);
713 gst_buffer_set_caps (buf1, caps);
714 gst_buffer_set_caps (buf2, caps);
715 gst_pad_set_caps (GST_AUDIO_ENCODER_SRC_PAD (enc), caps);
716 gst_caps_unref (caps);
718 /* push out buffers */
719 /* store buffers for later pre_push sending */
720 g_slist_foreach (enc->headers, (GFunc) gst_buffer_unref, NULL);
722 GST_DEBUG_OBJECT (enc, "storing header buffers");
723 enc->headers = g_slist_prepend (enc->headers, buf2);
724 enc->headers = g_slist_prepend (enc->headers, buf1);
726 enc->header_sent = TRUE;
729 GST_DEBUG_OBJECT (enc, "received buffer %p of %u bytes", buf,
730 buf ? GST_BUFFER_SIZE (buf) : 0);
732 ret = gst_speex_enc_encode (enc, buf);
738 gst_speex_enc_pre_push (GstAudioEncoder * benc, GstBuffer ** buffer)
741 GstFlowReturn ret = GST_FLOW_OK;
743 enc = GST_SPEEX_ENC (benc);
745 /* FIXME 0.11 ? get rid of this special ogg stuff and have it
746 * put and use 'codec data' in caps like anything else,
747 * with all the usual out-of-band advantage etc */
748 if (G_UNLIKELY (enc->headers)) {
749 GSList *header = enc->headers;
751 /* try to push all of these, if we lose one, might as well lose all */
753 if (ret == GST_FLOW_OK)
754 ret = gst_speex_enc_push_buffer (enc, header->data);
756 gst_speex_enc_push_buffer (enc, header->data);
757 header = g_slist_next (header);
760 g_slist_free (enc->headers);
768 gst_speex_enc_get_property (GObject * object, guint prop_id, GValue * value,
773 enc = GST_SPEEX_ENC (object);
777 g_value_set_float (value, enc->quality);
780 g_value_set_int (value, enc->bitrate);
783 g_value_set_enum (value, enc->mode);
786 g_value_set_boolean (value, enc->vbr);
789 g_value_set_int (value, enc->abr);
792 g_value_set_boolean (value, enc->vad);
795 g_value_set_boolean (value, enc->dtx);
797 case PROP_COMPLEXITY:
798 g_value_set_int (value, enc->complexity);
801 g_value_set_int (value, enc->nframes);
803 case PROP_LAST_MESSAGE:
804 g_value_set_string (value, enc->last_message);
807 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
813 gst_speex_enc_set_property (GObject * object, guint prop_id,
814 const GValue * value, GParamSpec * pspec)
818 enc = GST_SPEEX_ENC (object);
822 enc->quality = g_value_get_float (value);
825 enc->bitrate = g_value_get_int (value);
828 enc->mode = g_value_get_enum (value);
831 enc->vbr = g_value_get_boolean (value);
834 enc->abr = g_value_get_int (value);
837 enc->vad = g_value_get_boolean (value);
840 enc->dtx = g_value_get_boolean (value);
842 case PROP_COMPLEXITY:
843 enc->complexity = g_value_get_int (value);
846 enc->nframes = g_value_get_int (value);
849 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);