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 #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 "rate = (int) [ 6000, 48000 ], " "channels = (int) [ 1, 2 ]")
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);
138 #define gst_speex_enc_parent_class parent_class
139 G_DEFINE_TYPE_WITH_CODE (GstSpeexEnc, gst_speex_enc, GST_TYPE_AUDIO_ENCODER,
140 G_IMPLEMENT_INTERFACE (GST_TYPE_TAG_SETTER, NULL);
141 G_IMPLEMENT_INTERFACE (GST_TYPE_PRESET, NULL));
144 gst_speex_enc_class_init (GstSpeexEncClass * klass)
146 GObjectClass *gobject_class;
147 GstElementClass *gstelement_class;
148 GstAudioEncoderClass *base_class;
150 gobject_class = (GObjectClass *) klass;
151 gstelement_class = (GstElementClass *) klass;
152 base_class = (GstAudioEncoderClass *) klass;
154 gobject_class->finalize = gst_speex_enc_finalize;
155 gobject_class->set_property = gst_speex_enc_set_property;
156 gobject_class->get_property = gst_speex_enc_get_property;
158 base_class->start = GST_DEBUG_FUNCPTR (gst_speex_enc_start);
159 base_class->stop = GST_DEBUG_FUNCPTR (gst_speex_enc_stop);
160 base_class->set_format = GST_DEBUG_FUNCPTR (gst_speex_enc_set_format);
161 base_class->handle_frame = GST_DEBUG_FUNCPTR (gst_speex_enc_handle_frame);
162 base_class->event = GST_DEBUG_FUNCPTR (gst_speex_enc_sink_event);
163 base_class->pre_push = GST_DEBUG_FUNCPTR (gst_speex_enc_pre_push);
165 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_QUALITY,
166 g_param_spec_float ("quality", "Quality", "Encoding quality",
167 0.0, 10.0, DEFAULT_QUALITY,
168 G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
169 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_BITRATE,
170 g_param_spec_int ("bitrate", "Encoding Bit-rate",
171 "Specify an encoding bit-rate (in bps). (0 = automatic)",
172 0, G_MAXINT, DEFAULT_BITRATE,
173 G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
174 g_object_class_install_property (gobject_class, PROP_MODE,
175 g_param_spec_enum ("mode", "Mode", "The encoding mode",
176 GST_TYPE_SPEEX_ENC_MODE, GST_SPEEX_ENC_MODE_AUTO,
177 G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
178 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_VBR,
179 g_param_spec_boolean ("vbr", "VBR",
180 "Enable variable bit-rate", DEFAULT_VBR,
181 G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
182 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_ABR,
183 g_param_spec_int ("abr", "ABR",
184 "Enable average bit-rate (0 = disabled)",
185 0, G_MAXINT, DEFAULT_ABR,
186 G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
187 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_VAD,
188 g_param_spec_boolean ("vad", "VAD",
189 "Enable voice activity detection", DEFAULT_VAD,
190 G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
191 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_DTX,
192 g_param_spec_boolean ("dtx", "DTX",
193 "Enable discontinuous transmission", DEFAULT_DTX,
194 G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
195 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_COMPLEXITY,
196 g_param_spec_int ("complexity", "Complexity",
197 "Set encoding complexity",
198 0, G_MAXINT, DEFAULT_COMPLEXITY,
199 G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
200 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_NFRAMES,
201 g_param_spec_int ("nframes", "NFrames",
202 "Number of frames per buffer",
203 0, G_MAXINT, DEFAULT_NFRAMES,
204 G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
205 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_LAST_MESSAGE,
206 g_param_spec_string ("last-message", "last-message",
207 "The last status message", NULL,
208 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
210 gst_element_class_add_pad_template (gstelement_class,
211 gst_static_pad_template_get (&src_factory));
212 gst_element_class_add_pad_template (gstelement_class,
213 gst_static_pad_template_get (&sink_factory));
214 gst_element_class_set_details_simple (gstelement_class, "Speex audio encoder",
215 "Codec/Encoder/Audio",
216 "Encodes audio in Speex format", "Wim Taymans <wim@fluendo.com>");
218 GST_DEBUG_CATEGORY_INIT (speexenc_debug, "speexenc", 0, "Speex encoder");
222 gst_speex_enc_finalize (GObject * object)
226 enc = GST_SPEEX_ENC (object);
228 g_free (enc->last_message);
230 G_OBJECT_CLASS (parent_class)->finalize (object);
234 gst_speex_enc_init (GstSpeexEnc * enc)
236 GstAudioEncoder *benc = GST_AUDIO_ENCODER (enc);
238 /* arrange granulepos marking (and required perfect ts) */
239 gst_audio_encoder_set_mark_granule (benc, TRUE);
240 gst_audio_encoder_set_perfect_timestamp (benc, TRUE);
244 gst_speex_enc_start (GstAudioEncoder * benc)
246 GstSpeexEnc *enc = GST_SPEEX_ENC (benc);
248 GST_DEBUG_OBJECT (enc, "start");
249 speex_bits_init (&enc->bits);
250 enc->tags = gst_tag_list_new_empty ();
251 enc->header_sent = FALSE;
257 gst_speex_enc_stop (GstAudioEncoder * benc)
259 GstSpeexEnc *enc = GST_SPEEX_ENC (benc);
261 GST_DEBUG_OBJECT (enc, "stop");
262 enc->header_sent = FALSE;
264 speex_encoder_destroy (enc->state);
267 speex_bits_destroy (&enc->bits);
268 gst_tag_list_free (enc->tags);
270 g_slist_foreach (enc->headers, (GFunc) gst_buffer_unref, NULL);
273 gst_tag_setter_reset_tags (GST_TAG_SETTER (enc));
279 gst_speex_enc_get_latency (GstSpeexEnc * enc)
281 /* See the Speex manual section "Latency and algorithmic delay" */
282 if (enc->rate == 8000)
283 return 30 * GST_MSECOND;
285 return 34 * GST_MSECOND;
289 gst_speex_enc_set_format (GstAudioEncoder * benc, GstAudioInfo * info)
293 enc = GST_SPEEX_ENC (benc);
295 enc->channels = GST_AUDIO_INFO_CHANNELS (info);
296 enc->rate = GST_AUDIO_INFO_RATE (info);
298 /* handle reconfigure */
300 speex_encoder_destroy (enc->state);
304 if (!gst_speex_enc_setup (enc))
307 /* feedback to base class */
308 gst_audio_encoder_set_latency (benc,
309 gst_speex_enc_get_latency (enc), gst_speex_enc_get_latency (enc));
310 gst_audio_encoder_set_lookahead (benc, enc->lookahead);
312 if (enc->nframes == 0) {
313 /* as many frames as available input allows */
314 gst_audio_encoder_set_frame_samples_min (benc, enc->frame_size);
315 gst_audio_encoder_set_frame_samples_max (benc, enc->frame_size);
316 gst_audio_encoder_set_frame_max (benc, 0);
318 /* exactly as many frames as configured */
319 gst_audio_encoder_set_frame_samples_min (benc,
320 enc->frame_size * enc->nframes);
321 gst_audio_encoder_set_frame_samples_max (benc,
322 enc->frame_size * enc->nframes);
323 gst_audio_encoder_set_frame_max (benc, 1);
330 gst_speex_enc_create_metadata_buffer (GstSpeexEnc * enc)
332 const GstTagList *user_tags;
333 GstTagList *merged_tags;
334 GstBuffer *comments = NULL;
336 user_tags = gst_tag_setter_get_tag_list (GST_TAG_SETTER (enc));
338 GST_DEBUG_OBJECT (enc, "upstream tags = %" GST_PTR_FORMAT, enc->tags);
339 GST_DEBUG_OBJECT (enc, "user-set tags = %" GST_PTR_FORMAT, user_tags);
341 /* gst_tag_list_merge() will handle NULL for either or both lists fine */
342 merged_tags = gst_tag_list_merge (user_tags, enc->tags,
343 gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (enc)));
345 if (merged_tags == NULL)
346 merged_tags = gst_tag_list_new_empty ();
348 GST_DEBUG_OBJECT (enc, "merged tags = %" GST_PTR_FORMAT, merged_tags);
349 comments = gst_tag_list_to_vorbiscomment_buffer (merged_tags, NULL,
350 0, "Encoded with GStreamer Speexenc");
351 gst_tag_list_free (merged_tags);
353 GST_BUFFER_OFFSET (comments) = 0;
354 GST_BUFFER_OFFSET_END (comments) = 0;
360 gst_speex_enc_set_last_msg (GstSpeexEnc * enc, const gchar * msg)
362 g_free (enc->last_message);
363 enc->last_message = g_strdup (msg);
364 GST_WARNING_OBJECT (enc, "%s", msg);
365 g_object_notify (G_OBJECT (enc), "last-message");
369 gst_speex_enc_setup (GstSpeexEnc * enc)
372 case GST_SPEEX_ENC_MODE_UWB:
373 GST_LOG_OBJECT (enc, "configuring for requested UWB mode");
374 enc->speex_mode = speex_lib_get_mode (SPEEX_MODEID_UWB);
376 case GST_SPEEX_ENC_MODE_WB:
377 GST_LOG_OBJECT (enc, "configuring for requested WB mode");
378 enc->speex_mode = speex_lib_get_mode (SPEEX_MODEID_WB);
380 case GST_SPEEX_ENC_MODE_NB:
381 GST_LOG_OBJECT (enc, "configuring for requested NB mode");
382 enc->speex_mode = speex_lib_get_mode (SPEEX_MODEID_NB);
384 case GST_SPEEX_ENC_MODE_AUTO:
386 GST_LOG_OBJECT (enc, "finding best mode");
391 if (enc->rate > 25000) {
392 if (enc->mode == GST_SPEEX_ENC_MODE_AUTO) {
393 GST_LOG_OBJECT (enc, "selected UWB mode for samplerate %d", enc->rate);
394 enc->speex_mode = speex_lib_get_mode (SPEEX_MODEID_UWB);
396 if (enc->speex_mode != speex_lib_get_mode (SPEEX_MODEID_UWB)) {
397 gst_speex_enc_set_last_msg (enc,
398 "Warning: suggest to use ultra wide band mode for this rate");
401 } else if (enc->rate > 12500) {
402 if (enc->mode == GST_SPEEX_ENC_MODE_AUTO) {
403 GST_LOG_OBJECT (enc, "selected WB mode for samplerate %d", enc->rate);
404 enc->speex_mode = speex_lib_get_mode (SPEEX_MODEID_WB);
406 if (enc->speex_mode != speex_lib_get_mode (SPEEX_MODEID_WB)) {
407 gst_speex_enc_set_last_msg (enc,
408 "Warning: suggest to use wide band mode for this rate");
412 if (enc->mode == GST_SPEEX_ENC_MODE_AUTO) {
413 GST_LOG_OBJECT (enc, "selected NB mode for samplerate %d", enc->rate);
414 enc->speex_mode = speex_lib_get_mode (SPEEX_MODEID_NB);
416 if (enc->speex_mode != speex_lib_get_mode (SPEEX_MODEID_NB)) {
417 gst_speex_enc_set_last_msg (enc,
418 "Warning: suggest to use narrow band mode for this rate");
423 if (enc->rate != 8000 && enc->rate != 16000 && enc->rate != 32000) {
424 gst_speex_enc_set_last_msg (enc,
425 "Warning: speex is optimized for 8, 16 and 32 KHz");
428 speex_init_header (&enc->header, enc->rate, 1, enc->speex_mode);
429 enc->header.frames_per_packet = enc->nframes;
430 enc->header.vbr = enc->vbr;
431 enc->header.nb_channels = enc->channels;
433 /*Initialize Speex encoder */
434 enc->state = speex_encoder_init (enc->speex_mode);
436 speex_encoder_ctl (enc->state, SPEEX_GET_FRAME_SIZE, &enc->frame_size);
437 speex_encoder_ctl (enc->state, SPEEX_SET_COMPLEXITY, &enc->complexity);
438 speex_encoder_ctl (enc->state, SPEEX_SET_SAMPLING_RATE, &enc->rate);
441 speex_encoder_ctl (enc->state, SPEEX_SET_VBR_QUALITY, &enc->quality);
443 gint tmp = floor (enc->quality);
445 speex_encoder_ctl (enc->state, SPEEX_SET_QUALITY, &tmp);
448 if (enc->quality >= 0.0 && enc->vbr) {
449 gst_speex_enc_set_last_msg (enc,
450 "Warning: bitrate option is overriding quality");
452 speex_encoder_ctl (enc->state, SPEEX_SET_BITRATE, &enc->bitrate);
457 speex_encoder_ctl (enc->state, SPEEX_SET_VBR, &tmp);
458 } else if (enc->vad) {
461 speex_encoder_ctl (enc->state, SPEEX_SET_VAD, &tmp);
467 speex_encoder_ctl (enc->state, SPEEX_SET_DTX, &tmp);
470 if (enc->dtx && !(enc->vbr || enc->abr || enc->vad)) {
471 gst_speex_enc_set_last_msg (enc,
472 "Warning: dtx is useless without vad, vbr or abr");
473 } else if ((enc->vbr || enc->abr) && (enc->vad)) {
474 gst_speex_enc_set_last_msg (enc,
475 "Warning: vad is already implied by vbr or abr");
479 speex_encoder_ctl (enc->state, SPEEX_SET_ABR, &enc->abr);
482 speex_encoder_ctl (enc->state, SPEEX_GET_LOOKAHEAD, &enc->lookahead);
484 GST_LOG_OBJECT (enc, "we have frame size %d, lookahead %d", enc->frame_size,
490 /* push out the buffer */
492 gst_speex_enc_push_buffer (GstSpeexEnc * enc, GstBuffer * buffer)
494 GST_DEBUG_OBJECT (enc, "pushing output buffer of size %" G_GSIZE_FORMAT,
495 gst_buffer_get_size (buffer));
497 return gst_pad_push (GST_AUDIO_ENCODER_SRC_PAD (enc), buffer);
501 gst_speex_enc_sink_event (GstAudioEncoder * benc, GstEvent * event)
505 enc = GST_SPEEX_ENC (benc);
507 switch (GST_EVENT_TYPE (event)) {
513 gst_event_parse_tag (event, &list);
514 gst_tag_list_insert (enc->tags, list,
515 gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (enc)));
517 g_assert_not_reached ();
525 /* we only peeked, let base class handle it */
530 gst_speex_enc_encode (GstSpeexEnc * enc, GstBuffer * buf)
532 gint frame_size = enc->frame_size;
533 gint bytes = frame_size * 2 * enc->channels, samples;
534 gint outsize, written, dtx_ret = 0;
535 guint8 *data, *data0 = NULL, *bdata, *outdata;
538 GstFlowReturn ret = GST_FLOW_OK;
540 if (G_LIKELY (buf)) {
541 bdata = gst_buffer_map (buf, &bsize, NULL, GST_MAP_READ);
543 if (G_UNLIKELY (bsize % bytes)) {
544 GST_DEBUG_OBJECT (enc, "draining; adding silence samples");
546 size = ((bsize / bytes) + 1) * bytes;
547 data0 = data = g_malloc0 (size);
548 memcpy (data, bdata, bsize);
549 gst_buffer_unmap (buf, bdata, bsize);
556 GST_DEBUG_OBJECT (enc, "nothing to drain");
560 samples = size / (2 * enc->channels);
561 speex_bits_reset (&enc->bits);
563 /* FIXME what about dropped samples if DTS enabled ?? */
566 GST_DEBUG_OBJECT (enc, "encoding %d samples (%d bytes)", frame_size, bytes);
568 if (enc->channels == 2) {
569 speex_encode_stereo_int ((gint16 *) data, frame_size, &enc->bits);
571 dtx_ret += speex_encode_int (enc->state, (gint16 *) data, &enc->bits);
577 speex_bits_insert_terminator (&enc->bits);
578 outsize = speex_bits_nbytes (&enc->bits);
581 gst_buffer_unmap (buf, bdata, bsize);
584 ret = gst_pad_alloc_buffer_and_set_caps (GST_AUDIO_ENCODER_SRC_PAD (enc),
585 GST_BUFFER_OFFSET_NONE, outsize,
586 GST_PAD_CAPS (GST_AUDIO_ENCODER_SRC_PAD (enc)), &outbuf);
588 if ((GST_FLOW_OK != ret))
591 outbuf = gst_buffer_new_allocate (NULL, outsize, 0);
592 outdata = gst_buffer_map (outbuf, NULL, NULL, GST_MAP_WRITE);
594 written = speex_bits_write (&enc->bits, (gchar *) outdata, outsize);
596 if (G_UNLIKELY (written < outsize)) {
597 GST_ERROR_OBJECT (enc, "short write: %d < %d bytes", written, outsize);
598 } else if (G_UNLIKELY (written > outsize)) {
599 GST_ERROR_OBJECT (enc, "overrun: %d > %d bytes", written, outsize);
602 gst_buffer_unmap (outbuf, outdata, written);
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_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_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_pad_set_caps (GST_AUDIO_ENCODER_SRC_PAD (enc), caps);
710 gst_caps_unref (caps);
712 /* push out buffers */
713 /* store buffers for later pre_push sending */
714 g_slist_foreach (enc->headers, (GFunc) gst_buffer_unref, NULL);
716 GST_DEBUG_OBJECT (enc, "storing header buffers");
717 enc->headers = g_slist_prepend (enc->headers, buf2);
718 enc->headers = g_slist_prepend (enc->headers, buf1);
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_pre_push (GstAudioEncoder * benc, GstBuffer ** buffer)
735 GstFlowReturn ret = GST_FLOW_OK;
737 enc = GST_SPEEX_ENC (benc);
739 /* FIXME 0.11 ? get rid of this special ogg stuff and have it
740 * put and use 'codec data' in caps like anything else,
741 * with all the usual out-of-band advantage etc */
742 if (G_UNLIKELY (enc->headers)) {
743 GSList *header = enc->headers;
745 /* try to push all of these, if we lose one, might as well lose all */
747 if (ret == GST_FLOW_OK)
748 ret = gst_speex_enc_push_buffer (enc, header->data);
750 gst_speex_enc_push_buffer (enc, header->data);
751 header = g_slist_next (header);
754 g_slist_free (enc->headers);
762 gst_speex_enc_get_property (GObject * object, guint prop_id, GValue * value,
767 enc = GST_SPEEX_ENC (object);
771 g_value_set_float (value, enc->quality);
774 g_value_set_int (value, enc->bitrate);
777 g_value_set_enum (value, enc->mode);
780 g_value_set_boolean (value, enc->vbr);
783 g_value_set_int (value, enc->abr);
786 g_value_set_boolean (value, enc->vad);
789 g_value_set_boolean (value, enc->dtx);
791 case PROP_COMPLEXITY:
792 g_value_set_int (value, enc->complexity);
795 g_value_set_int (value, enc->nframes);
797 case PROP_LAST_MESSAGE:
798 g_value_set_string (value, enc->last_message);
801 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
807 gst_speex_enc_set_property (GObject * object, guint prop_id,
808 const GValue * value, GParamSpec * pspec)
812 enc = GST_SPEEX_ENC (object);
816 enc->quality = g_value_get_float (value);
819 enc->bitrate = g_value_get_int (value);
822 enc->mode = g_value_get_enum (value);
825 enc->vbr = g_value_get_boolean (value);
828 enc->abr = g_value_get_int (value);
831 enc->vad = g_value_get_boolean (value);
834 enc->dtx = g_value_get_boolean (value);
836 case PROP_COMPLEXITY:
837 enc->complexity = g_value_get_int (value);
840 enc->nframes = g_value_get_int (value);
843 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);