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_static_pad_template (element_class, &src_factory);
158 gst_element_class_add_static_pad_template (element_class, &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);
181 base_class->pre_push = GST_DEBUG_FUNCPTR (gst_speex_enc_pre_push);
183 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_QUALITY,
184 g_param_spec_float ("quality", "Quality", "Encoding quality",
185 0.0, 10.0, DEFAULT_QUALITY,
186 G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
187 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_BITRATE,
188 g_param_spec_int ("bitrate", "Encoding Bit-rate",
189 "Specify an encoding bit-rate (in bps). (0 = automatic)",
190 0, G_MAXINT, DEFAULT_BITRATE,
191 G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
192 g_object_class_install_property (gobject_class, PROP_MODE,
193 g_param_spec_enum ("mode", "Mode", "The encoding mode",
194 GST_TYPE_SPEEX_ENC_MODE, GST_SPEEX_ENC_MODE_AUTO,
195 G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
196 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_VBR,
197 g_param_spec_boolean ("vbr", "VBR",
198 "Enable variable bit-rate", DEFAULT_VBR,
199 G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
200 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_ABR,
201 g_param_spec_int ("abr", "ABR",
202 "Enable average bit-rate (0 = disabled)",
203 0, G_MAXINT, DEFAULT_ABR,
204 G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
205 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_VAD,
206 g_param_spec_boolean ("vad", "VAD",
207 "Enable voice activity detection", DEFAULT_VAD,
208 G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
209 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_DTX,
210 g_param_spec_boolean ("dtx", "DTX",
211 "Enable discontinuous transmission", DEFAULT_DTX,
212 G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
213 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_COMPLEXITY,
214 g_param_spec_int ("complexity", "Complexity",
215 "Set encoding complexity",
216 0, G_MAXINT, DEFAULT_COMPLEXITY,
217 G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
218 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_NFRAMES,
219 g_param_spec_int ("nframes", "NFrames",
220 "Number of frames per buffer",
221 0, G_MAXINT, DEFAULT_NFRAMES,
222 G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
223 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_LAST_MESSAGE,
224 g_param_spec_string ("last-message", "last-message",
225 "The last status message", NULL,
226 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
228 gobject_class->finalize = gst_speex_enc_finalize;
232 gst_speex_enc_finalize (GObject * object)
236 enc = GST_SPEEX_ENC (object);
238 g_free (enc->last_message);
240 G_OBJECT_CLASS (parent_class)->finalize (object);
244 gst_speex_enc_init (GstSpeexEnc * enc, GstSpeexEncClass * klass)
246 GstAudioEncoder *benc = GST_AUDIO_ENCODER (enc);
248 /* arrange granulepos marking (and required perfect ts) */
249 gst_audio_encoder_set_mark_granule (benc, TRUE);
250 gst_audio_encoder_set_perfect_timestamp (benc, TRUE);
254 gst_speex_enc_start (GstAudioEncoder * benc)
256 GstSpeexEnc *enc = GST_SPEEX_ENC (benc);
258 GST_DEBUG_OBJECT (enc, "start");
259 speex_bits_init (&enc->bits);
260 enc->tags = gst_tag_list_new ();
261 enc->header_sent = FALSE;
267 gst_speex_enc_stop (GstAudioEncoder * benc)
269 GstSpeexEnc *enc = GST_SPEEX_ENC (benc);
271 GST_DEBUG_OBJECT (enc, "stop");
272 enc->header_sent = FALSE;
274 speex_encoder_destroy (enc->state);
277 speex_bits_destroy (&enc->bits);
278 gst_tag_list_free (enc->tags);
280 g_slist_foreach (enc->headers, (GFunc) gst_buffer_unref, NULL);
283 gst_tag_setter_reset_tags (GST_TAG_SETTER (enc));
289 gst_speex_enc_get_latency (GstSpeexEnc * enc)
291 /* See the Speex manual section "Latency and algorithmic delay" */
292 if (enc->rate == 8000)
293 return 30 * GST_MSECOND;
295 return 34 * GST_MSECOND;
299 gst_speex_enc_set_format (GstAudioEncoder * benc, GstAudioInfo * info)
303 enc = GST_SPEEX_ENC (benc);
305 enc->channels = GST_AUDIO_INFO_CHANNELS (info);
306 enc->rate = GST_AUDIO_INFO_RATE (info);
308 /* handle reconfigure */
310 speex_encoder_destroy (enc->state);
314 if (!gst_speex_enc_setup (enc))
317 /* feedback to base class */
318 gst_audio_encoder_set_latency (benc,
319 gst_speex_enc_get_latency (enc), gst_speex_enc_get_latency (enc));
320 gst_audio_encoder_set_lookahead (benc, enc->lookahead);
322 if (enc->nframes == 0) {
323 /* as many frames as available input allows */
324 gst_audio_encoder_set_frame_samples_min (benc, enc->frame_size);
325 gst_audio_encoder_set_frame_samples_max (benc, enc->frame_size);
326 gst_audio_encoder_set_frame_max (benc, 0);
328 /* exactly as many frames as configured */
329 gst_audio_encoder_set_frame_samples_min (benc,
330 enc->frame_size * enc->nframes);
331 gst_audio_encoder_set_frame_samples_max (benc,
332 enc->frame_size * enc->nframes);
333 gst_audio_encoder_set_frame_max (benc, 1);
340 gst_speex_enc_create_metadata_buffer (GstSpeexEnc * enc)
342 const GstTagList *user_tags;
343 GstTagList *merged_tags;
344 GstBuffer *comments = NULL;
346 user_tags = gst_tag_setter_get_tag_list (GST_TAG_SETTER (enc));
348 GST_DEBUG_OBJECT (enc, "upstream tags = %" GST_PTR_FORMAT, enc->tags);
349 GST_DEBUG_OBJECT (enc, "user-set tags = %" GST_PTR_FORMAT, user_tags);
351 /* gst_tag_list_merge() will handle NULL for either or both lists fine */
352 merged_tags = gst_tag_list_merge (user_tags, enc->tags,
353 gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (enc)));
355 if (merged_tags == NULL)
356 merged_tags = gst_tag_list_new ();
358 GST_DEBUG_OBJECT (enc, "merged tags = %" GST_PTR_FORMAT, merged_tags);
359 comments = gst_tag_list_to_vorbiscomment_buffer (merged_tags, NULL,
360 0, "Encoded with GStreamer Speexenc");
361 gst_tag_list_free (merged_tags);
363 GST_BUFFER_OFFSET (comments) = 0;
364 GST_BUFFER_OFFSET_END (comments) = 0;
370 gst_speex_enc_set_last_msg (GstSpeexEnc * enc, const gchar * msg)
372 g_free (enc->last_message);
373 enc->last_message = g_strdup (msg);
374 GST_WARNING_OBJECT (enc, "%s", msg);
375 g_object_notify (G_OBJECT (enc), "last-message");
379 gst_speex_enc_setup (GstSpeexEnc * enc)
382 case GST_SPEEX_ENC_MODE_UWB:
383 GST_LOG_OBJECT (enc, "configuring for requested UWB mode");
384 enc->speex_mode = speex_lib_get_mode (SPEEX_MODEID_UWB);
386 case GST_SPEEX_ENC_MODE_WB:
387 GST_LOG_OBJECT (enc, "configuring for requested WB mode");
388 enc->speex_mode = speex_lib_get_mode (SPEEX_MODEID_WB);
390 case GST_SPEEX_ENC_MODE_NB:
391 GST_LOG_OBJECT (enc, "configuring for requested NB mode");
392 enc->speex_mode = speex_lib_get_mode (SPEEX_MODEID_NB);
394 case GST_SPEEX_ENC_MODE_AUTO:
396 GST_LOG_OBJECT (enc, "finding best mode");
401 if (enc->rate > 25000) {
402 if (enc->mode == GST_SPEEX_ENC_MODE_AUTO) {
403 GST_LOG_OBJECT (enc, "selected UWB mode for samplerate %d", enc->rate);
404 enc->speex_mode = speex_lib_get_mode (SPEEX_MODEID_UWB);
406 if (enc->speex_mode != speex_lib_get_mode (SPEEX_MODEID_UWB)) {
407 gst_speex_enc_set_last_msg (enc,
408 "Warning: suggest to use ultra wide band mode for this rate");
411 } else if (enc->rate > 12500) {
412 if (enc->mode == GST_SPEEX_ENC_MODE_AUTO) {
413 GST_LOG_OBJECT (enc, "selected WB mode for samplerate %d", enc->rate);
414 enc->speex_mode = speex_lib_get_mode (SPEEX_MODEID_WB);
416 if (enc->speex_mode != speex_lib_get_mode (SPEEX_MODEID_WB)) {
417 gst_speex_enc_set_last_msg (enc,
418 "Warning: suggest to use wide band mode for this rate");
422 if (enc->mode == GST_SPEEX_ENC_MODE_AUTO) {
423 GST_LOG_OBJECT (enc, "selected NB mode for samplerate %d", enc->rate);
424 enc->speex_mode = speex_lib_get_mode (SPEEX_MODEID_NB);
426 if (enc->speex_mode != speex_lib_get_mode (SPEEX_MODEID_NB)) {
427 gst_speex_enc_set_last_msg (enc,
428 "Warning: suggest to use narrow band mode for this rate");
433 if (enc->rate != 8000 && enc->rate != 16000 && enc->rate != 32000) {
434 gst_speex_enc_set_last_msg (enc,
435 "Warning: speex is optimized for 8, 16 and 32 KHz");
438 speex_init_header (&enc->header, enc->rate, 1, enc->speex_mode);
439 enc->header.frames_per_packet = enc->nframes;
440 enc->header.vbr = enc->vbr;
441 enc->header.nb_channels = enc->channels;
443 /*Initialize Speex encoder */
444 enc->state = speex_encoder_init (enc->speex_mode);
446 speex_encoder_ctl (enc->state, SPEEX_GET_FRAME_SIZE, &enc->frame_size);
447 speex_encoder_ctl (enc->state, SPEEX_SET_COMPLEXITY, &enc->complexity);
448 speex_encoder_ctl (enc->state, SPEEX_SET_SAMPLING_RATE, &enc->rate);
451 speex_encoder_ctl (enc->state, SPEEX_SET_VBR_QUALITY, &enc->quality);
453 gint tmp = floor (enc->quality);
455 speex_encoder_ctl (enc->state, SPEEX_SET_QUALITY, &tmp);
458 if (enc->quality >= 0.0 && enc->vbr) {
459 gst_speex_enc_set_last_msg (enc,
460 "Warning: bitrate option is overriding quality");
462 speex_encoder_ctl (enc->state, SPEEX_SET_BITRATE, &enc->bitrate);
467 speex_encoder_ctl (enc->state, SPEEX_SET_VBR, &tmp);
468 } else if (enc->vad) {
471 speex_encoder_ctl (enc->state, SPEEX_SET_VAD, &tmp);
477 speex_encoder_ctl (enc->state, SPEEX_SET_DTX, &tmp);
480 if (enc->dtx && !(enc->vbr || enc->abr || enc->vad)) {
481 gst_speex_enc_set_last_msg (enc,
482 "Warning: dtx is useless without vad, vbr or abr");
483 } else if ((enc->vbr || enc->abr) && (enc->vad)) {
484 gst_speex_enc_set_last_msg (enc,
485 "Warning: vad is already implied by vbr or abr");
489 speex_encoder_ctl (enc->state, SPEEX_SET_ABR, &enc->abr);
492 speex_encoder_ctl (enc->state, SPEEX_GET_LOOKAHEAD, &enc->lookahead);
494 GST_LOG_OBJECT (enc, "we have frame size %d, lookahead %d", enc->frame_size,
500 /* push out the buffer */
502 gst_speex_enc_push_buffer (GstSpeexEnc * enc, GstBuffer * buffer)
506 size = GST_BUFFER_SIZE (buffer);
507 GST_DEBUG_OBJECT (enc, "pushing output buffer of size %u", size);
509 gst_buffer_set_caps (buffer, GST_PAD_CAPS (GST_AUDIO_ENCODER_SRC_PAD (enc)));
510 return gst_pad_push (GST_AUDIO_ENCODER_SRC_PAD (enc), buffer);
514 gst_speex_enc_sink_event (GstAudioEncoder * benc, GstEvent * event)
518 enc = GST_SPEEX_ENC (benc);
520 switch (GST_EVENT_TYPE (event)) {
526 gst_event_parse_tag (event, &list);
527 gst_tag_list_insert (enc->tags, list,
528 gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (enc)));
530 g_assert_not_reached ();
538 /* we only peeked, let base class handle it */
543 gst_speex_enc_encode (GstSpeexEnc * enc, GstBuffer * buf)
545 gint frame_size = enc->frame_size;
546 gint bytes = frame_size * 2 * enc->channels, samples, size;
547 gint outsize, written, dtx_ret = 0;
548 guint8 *data, *data0 = NULL;
550 GstFlowReturn ret = GST_FLOW_OK;
552 if (G_LIKELY (buf)) {
553 data = GST_BUFFER_DATA (buf);
554 size = GST_BUFFER_SIZE (buf);
556 if (G_UNLIKELY (size % bytes)) {
557 GST_DEBUG_OBJECT (enc, "draining; adding silence samples");
558 size = ((size / bytes) + 1) * bytes;
559 data0 = data = g_malloc0 (size);
560 memcpy (data, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
563 GST_DEBUG_OBJECT (enc, "nothing to drain");
567 samples = size / (2 * enc->channels);
568 speex_bits_reset (&enc->bits);
570 /* FIXME what about dropped samples if DTS enabled ?? */
573 GST_DEBUG_OBJECT (enc, "encoding %d samples (%d bytes)", frame_size, bytes);
575 if (enc->channels == 2) {
576 speex_encode_stereo_int ((gint16 *) data, frame_size, &enc->bits);
578 dtx_ret += speex_encode_int (enc->state, (gint16 *) data, &enc->bits);
584 speex_bits_insert_terminator (&enc->bits);
585 outsize = speex_bits_nbytes (&enc->bits);
587 ret = gst_pad_alloc_buffer_and_set_caps (GST_AUDIO_ENCODER_SRC_PAD (enc),
588 GST_BUFFER_OFFSET_NONE, outsize,
589 GST_PAD_CAPS (GST_AUDIO_ENCODER_SRC_PAD (enc)), &outbuf);
591 if ((GST_FLOW_OK != ret))
594 written = speex_bits_write (&enc->bits,
595 (gchar *) GST_BUFFER_DATA (outbuf), outsize);
597 if (G_UNLIKELY (written < outsize)) {
598 GST_ERROR_OBJECT (enc, "short write: %d < %d bytes", written, outsize);
599 GST_BUFFER_SIZE (outbuf) = written;
600 } else if (G_UNLIKELY (written > outsize)) {
601 GST_ERROR_OBJECT (enc, "overrun: %d > %d bytes", written, outsize);
605 GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_GAP);
607 ret = gst_audio_encoder_finish_frame (GST_AUDIO_ENCODER (enc),
616 * (really really) FIXME: move into core (dixit tpm)
619 * _gst_caps_set_buffer_array:
621 * @field: field in caps to set
622 * @buf: header buffers
624 * Adds given buffers to an array of buffers set as the given @field
625 * on the given @caps. List of buffer arguments must be NULL-terminated.
627 * Returns: input caps with a streamheader field added, or NULL if some error
630 _gst_caps_set_buffer_array (GstCaps * caps, const gchar * field,
631 GstBuffer * buf, ...)
633 GstStructure *structure = NULL;
635 GValue array = { 0 };
636 GValue value = { 0 };
638 g_return_val_if_fail (caps != NULL, NULL);
639 g_return_val_if_fail (gst_caps_is_fixed (caps), NULL);
640 g_return_val_if_fail (field != NULL, NULL);
642 caps = gst_caps_make_writable (caps);
643 structure = gst_caps_get_structure (caps, 0);
645 g_value_init (&array, GST_TYPE_ARRAY);
648 /* put buffers in a fixed list */
650 g_assert (gst_buffer_is_metadata_writable (buf));
653 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_IN_CAPS);
655 g_value_init (&value, GST_TYPE_BUFFER);
656 buf = gst_buffer_copy (buf);
657 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_IN_CAPS);
658 gst_value_set_buffer (&value, buf);
659 gst_buffer_unref (buf);
660 gst_value_array_append_value (&array, &value);
661 g_value_unset (&value);
663 buf = va_arg (va, GstBuffer *);
666 gst_structure_set_value (structure, field, &array);
667 g_value_unset (&array);
673 gst_speex_enc_handle_frame (GstAudioEncoder * benc, GstBuffer * buf)
676 GstFlowReturn ret = GST_FLOW_OK;
678 enc = GST_SPEEX_ENC (benc);
680 if (!enc->header_sent) {
681 /* Speex streams begin with two headers; the initial header (with
682 most of the codec setup parameters) which is mandated by the Ogg
683 bitstream spec. The second header holds any comment fields.
684 We merely need to make the headers, then pass them to libspeex
685 one at a time; libspeex handles the additional Ogg bitstream
687 GstBuffer *buf1, *buf2;
692 /* create header buffer */
693 data = (guint8 *) speex_header_to_packet (&enc->header, &data_len);
694 buf1 = gst_buffer_new ();
695 GST_BUFFER_DATA (buf1) = GST_BUFFER_MALLOCDATA (buf1) = data;
696 GST_BUFFER_SIZE (buf1) = data_len;
697 GST_BUFFER_OFFSET_END (buf1) = 0;
698 GST_BUFFER_OFFSET (buf1) = 0;
700 /* create comment buffer */
701 buf2 = gst_speex_enc_create_metadata_buffer (enc);
703 /* mark and put on caps */
704 caps = gst_caps_new_simple ("audio/x-speex", "rate", G_TYPE_INT, enc->rate,
705 "channels", G_TYPE_INT, enc->channels, NULL);
706 caps = _gst_caps_set_buffer_array (caps, "streamheader", buf1, buf2, NULL);
708 /* negotiate with these caps */
709 GST_DEBUG_OBJECT (enc, "here are the caps: %" GST_PTR_FORMAT, caps);
711 gst_buffer_set_caps (buf1, caps);
712 gst_buffer_set_caps (buf2, caps);
713 gst_pad_set_caps (GST_AUDIO_ENCODER_SRC_PAD (enc), caps);
714 gst_caps_unref (caps);
716 /* push out buffers */
717 /* store buffers for later pre_push sending */
718 g_slist_foreach (enc->headers, (GFunc) gst_buffer_unref, NULL);
720 GST_DEBUG_OBJECT (enc, "storing header buffers");
721 enc->headers = g_slist_prepend (enc->headers, buf2);
722 enc->headers = g_slist_prepend (enc->headers, buf1);
724 enc->header_sent = TRUE;
727 GST_DEBUG_OBJECT (enc, "received buffer %p of %u bytes", buf,
728 buf ? GST_BUFFER_SIZE (buf) : 0);
730 ret = gst_speex_enc_encode (enc, buf);
736 gst_speex_enc_pre_push (GstAudioEncoder * benc, GstBuffer ** buffer)
739 GstFlowReturn ret = GST_FLOW_OK;
741 enc = GST_SPEEX_ENC (benc);
743 /* FIXME 0.11 ? get rid of this special ogg stuff and have it
744 * put and use 'codec data' in caps like anything else,
745 * with all the usual out-of-band advantage etc */
746 if (G_UNLIKELY (enc->headers)) {
747 GSList *header = enc->headers;
749 /* try to push all of these, if we lose one, might as well lose all */
751 if (ret == GST_FLOW_OK)
752 ret = gst_speex_enc_push_buffer (enc, header->data);
754 gst_speex_enc_push_buffer (enc, header->data);
755 header = g_slist_next (header);
758 g_slist_free (enc->headers);
766 gst_speex_enc_get_property (GObject * object, guint prop_id, GValue * value,
771 enc = GST_SPEEX_ENC (object);
775 g_value_set_float (value, enc->quality);
778 g_value_set_int (value, enc->bitrate);
781 g_value_set_enum (value, enc->mode);
784 g_value_set_boolean (value, enc->vbr);
787 g_value_set_int (value, enc->abr);
790 g_value_set_boolean (value, enc->vad);
793 g_value_set_boolean (value, enc->dtx);
795 case PROP_COMPLEXITY:
796 g_value_set_int (value, enc->complexity);
799 g_value_set_int (value, enc->nframes);
801 case PROP_LAST_MESSAGE:
802 g_value_set_string (value, enc->last_message);
805 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
811 gst_speex_enc_set_property (GObject * object, guint prop_id,
812 const GValue * value, GParamSpec * pspec)
816 enc = GST_SPEEX_ENC (object);
820 enc->quality = g_value_get_float (value);
823 enc->bitrate = g_value_get_int (value);
826 enc->mode = g_value_get_enum (value);
829 enc->vbr = g_value_get_boolean (value);
832 enc->abr = g_value_get_int (value);
835 enc->vad = g_value_get_boolean (value);
838 enc->dtx = g_value_get_boolean (value);
840 case PROP_COMPLEXITY:
841 enc->complexity = g_value_get_int (value);
844 enc->nframes = g_value_get_int (value);
847 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);