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 "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 gst_speex_enc_pre_push (GstAudioEncoder * benc, GstBuffer ** buffer);
145 #define gst_speex_enc_parent_class parent_class
146 G_DEFINE_TYPE_WITH_CODE (GstSpeexEnc, gst_speex_enc, GST_TYPE_AUDIO_ENCODER,
147 G_IMPLEMENT_INTERFACE (GST_TYPE_TAG_SETTER, NULL);
148 G_IMPLEMENT_INTERFACE (GST_TYPE_PRESET, NULL));
151 gst_speex_enc_class_init (GstSpeexEncClass * klass)
153 GObjectClass *gobject_class;
154 GstElementClass *gstelement_class;
155 GstAudioEncoderClass *base_class;
157 gobject_class = (GObjectClass *) klass;
158 gstelement_class = (GstElementClass *) klass;
159 base_class = (GstAudioEncoderClass *) klass;
161 gobject_class->finalize = gst_speex_enc_finalize;
162 gobject_class->set_property = gst_speex_enc_set_property;
163 gobject_class->get_property = gst_speex_enc_get_property;
165 base_class->start = GST_DEBUG_FUNCPTR (gst_speex_enc_start);
166 base_class->stop = GST_DEBUG_FUNCPTR (gst_speex_enc_stop);
167 base_class->set_format = GST_DEBUG_FUNCPTR (gst_speex_enc_set_format);
168 base_class->handle_frame = GST_DEBUG_FUNCPTR (gst_speex_enc_handle_frame);
169 base_class->event = GST_DEBUG_FUNCPTR (gst_speex_enc_sink_event);
170 base_class->pre_push = GST_DEBUG_FUNCPTR (gst_speex_enc_pre_push);
172 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_QUALITY,
173 g_param_spec_float ("quality", "Quality", "Encoding quality",
174 0.0, 10.0, DEFAULT_QUALITY,
175 G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
176 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_BITRATE,
177 g_param_spec_int ("bitrate", "Encoding Bit-rate",
178 "Specify an encoding bit-rate (in bps). (0 = automatic)",
179 0, G_MAXINT, DEFAULT_BITRATE,
180 G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
181 g_object_class_install_property (gobject_class, PROP_MODE,
182 g_param_spec_enum ("mode", "Mode", "The encoding mode",
183 GST_TYPE_SPEEX_ENC_MODE, GST_SPEEX_ENC_MODE_AUTO,
184 G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
185 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_VBR,
186 g_param_spec_boolean ("vbr", "VBR",
187 "Enable variable bit-rate", DEFAULT_VBR,
188 G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
189 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_ABR,
190 g_param_spec_int ("abr", "ABR",
191 "Enable average bit-rate (0 = disabled)",
192 0, G_MAXINT, DEFAULT_ABR,
193 G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
194 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_VAD,
195 g_param_spec_boolean ("vad", "VAD",
196 "Enable voice activity detection", DEFAULT_VAD,
197 G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
198 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_DTX,
199 g_param_spec_boolean ("dtx", "DTX",
200 "Enable discontinuous transmission", DEFAULT_DTX,
201 G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
202 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_COMPLEXITY,
203 g_param_spec_int ("complexity", "Complexity",
204 "Set encoding complexity",
205 0, G_MAXINT, DEFAULT_COMPLEXITY,
206 G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
207 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_NFRAMES,
208 g_param_spec_int ("nframes", "NFrames",
209 "Number of frames per buffer",
210 0, G_MAXINT, DEFAULT_NFRAMES,
211 G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
212 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_LAST_MESSAGE,
213 g_param_spec_string ("last-message", "last-message",
214 "The last status message", NULL,
215 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
217 gst_element_class_add_pad_template (gstelement_class,
218 gst_static_pad_template_get (&src_factory));
219 gst_element_class_add_pad_template (gstelement_class,
220 gst_static_pad_template_get (&sink_factory));
221 gst_element_class_set_details_simple (gstelement_class, "Speex audio encoder",
222 "Codec/Encoder/Audio",
223 "Encodes audio in Speex format", "Wim Taymans <wim@fluendo.com>");
225 GST_DEBUG_CATEGORY_INIT (speexenc_debug, "speexenc", 0, "Speex encoder");
229 gst_speex_enc_finalize (GObject * object)
233 enc = GST_SPEEX_ENC (object);
235 g_free (enc->last_message);
237 G_OBJECT_CLASS (parent_class)->finalize (object);
241 gst_speex_enc_init (GstSpeexEnc * enc)
243 GstAudioEncoder *benc = GST_AUDIO_ENCODER (enc);
245 /* arrange granulepos marking (and required perfect ts) */
246 gst_audio_encoder_set_mark_granule (benc, TRUE);
247 gst_audio_encoder_set_perfect_timestamp (benc, TRUE);
251 gst_speex_enc_start (GstAudioEncoder * benc)
253 GstSpeexEnc *enc = GST_SPEEX_ENC (benc);
255 GST_DEBUG_OBJECT (enc, "start");
256 speex_bits_init (&enc->bits);
257 enc->tags = gst_tag_list_new_empty ();
258 enc->header_sent = FALSE;
264 gst_speex_enc_stop (GstAudioEncoder * benc)
266 GstSpeexEnc *enc = GST_SPEEX_ENC (benc);
268 GST_DEBUG_OBJECT (enc, "stop");
269 enc->header_sent = FALSE;
271 speex_encoder_destroy (enc->state);
274 speex_bits_destroy (&enc->bits);
275 gst_tag_list_free (enc->tags);
277 g_slist_foreach (enc->headers, (GFunc) gst_buffer_unref, NULL);
280 gst_tag_setter_reset_tags (GST_TAG_SETTER (enc));
286 gst_speex_enc_get_latency (GstSpeexEnc * enc)
288 /* See the Speex manual section "Latency and algorithmic delay" */
289 if (enc->rate == 8000)
290 return 30 * GST_MSECOND;
292 return 34 * GST_MSECOND;
296 gst_speex_enc_set_format (GstAudioEncoder * benc, GstAudioInfo * info)
300 enc = GST_SPEEX_ENC (benc);
302 enc->channels = GST_AUDIO_INFO_CHANNELS (info);
303 enc->rate = GST_AUDIO_INFO_RATE (info);
305 /* handle reconfigure */
307 speex_encoder_destroy (enc->state);
311 if (!gst_speex_enc_setup (enc))
314 /* feedback to base class */
315 gst_audio_encoder_set_latency (benc,
316 gst_speex_enc_get_latency (enc), gst_speex_enc_get_latency (enc));
317 gst_audio_encoder_set_lookahead (benc, enc->lookahead);
319 if (enc->nframes == 0) {
320 /* as many frames as available input allows */
321 gst_audio_encoder_set_frame_samples_min (benc, enc->frame_size);
322 gst_audio_encoder_set_frame_samples_max (benc, enc->frame_size);
323 gst_audio_encoder_set_frame_max (benc, 0);
325 /* exactly as many frames as configured */
326 gst_audio_encoder_set_frame_samples_min (benc,
327 enc->frame_size * enc->nframes);
328 gst_audio_encoder_set_frame_samples_max (benc,
329 enc->frame_size * enc->nframes);
330 gst_audio_encoder_set_frame_max (benc, 1);
337 gst_speex_enc_create_metadata_buffer (GstSpeexEnc * enc)
339 const GstTagList *user_tags;
340 GstTagList *merged_tags;
341 GstBuffer *comments = NULL;
343 user_tags = gst_tag_setter_get_tag_list (GST_TAG_SETTER (enc));
345 GST_DEBUG_OBJECT (enc, "upstream tags = %" GST_PTR_FORMAT, enc->tags);
346 GST_DEBUG_OBJECT (enc, "user-set tags = %" GST_PTR_FORMAT, user_tags);
348 /* gst_tag_list_merge() will handle NULL for either or both lists fine */
349 merged_tags = gst_tag_list_merge (user_tags, enc->tags,
350 gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (enc)));
352 if (merged_tags == NULL)
353 merged_tags = gst_tag_list_new_empty ();
355 GST_DEBUG_OBJECT (enc, "merged tags = %" GST_PTR_FORMAT, merged_tags);
356 comments = gst_tag_list_to_vorbiscomment_buffer (merged_tags, NULL,
357 0, "Encoded with GStreamer Speexenc");
358 gst_tag_list_free (merged_tags);
360 GST_BUFFER_OFFSET (comments) = 0;
361 GST_BUFFER_OFFSET_END (comments) = 0;
367 gst_speex_enc_set_last_msg (GstSpeexEnc * enc, const gchar * msg)
369 g_free (enc->last_message);
370 enc->last_message = g_strdup (msg);
371 GST_WARNING_OBJECT (enc, "%s", msg);
372 g_object_notify (G_OBJECT (enc), "last-message");
376 gst_speex_enc_setup (GstSpeexEnc * enc)
379 case GST_SPEEX_ENC_MODE_UWB:
380 GST_LOG_OBJECT (enc, "configuring for requested UWB mode");
381 enc->speex_mode = speex_lib_get_mode (SPEEX_MODEID_UWB);
383 case GST_SPEEX_ENC_MODE_WB:
384 GST_LOG_OBJECT (enc, "configuring for requested WB mode");
385 enc->speex_mode = speex_lib_get_mode (SPEEX_MODEID_WB);
387 case GST_SPEEX_ENC_MODE_NB:
388 GST_LOG_OBJECT (enc, "configuring for requested NB mode");
389 enc->speex_mode = speex_lib_get_mode (SPEEX_MODEID_NB);
391 case GST_SPEEX_ENC_MODE_AUTO:
393 GST_LOG_OBJECT (enc, "finding best mode");
398 if (enc->rate > 25000) {
399 if (enc->mode == GST_SPEEX_ENC_MODE_AUTO) {
400 GST_LOG_OBJECT (enc, "selected UWB mode for samplerate %d", enc->rate);
401 enc->speex_mode = speex_lib_get_mode (SPEEX_MODEID_UWB);
403 if (enc->speex_mode != speex_lib_get_mode (SPEEX_MODEID_UWB)) {
404 gst_speex_enc_set_last_msg (enc,
405 "Warning: suggest to use ultra wide band mode for this rate");
408 } else if (enc->rate > 12500) {
409 if (enc->mode == GST_SPEEX_ENC_MODE_AUTO) {
410 GST_LOG_OBJECT (enc, "selected WB mode for samplerate %d", enc->rate);
411 enc->speex_mode = speex_lib_get_mode (SPEEX_MODEID_WB);
413 if (enc->speex_mode != speex_lib_get_mode (SPEEX_MODEID_WB)) {
414 gst_speex_enc_set_last_msg (enc,
415 "Warning: suggest to use wide band mode for this rate");
419 if (enc->mode == GST_SPEEX_ENC_MODE_AUTO) {
420 GST_LOG_OBJECT (enc, "selected NB mode for samplerate %d", enc->rate);
421 enc->speex_mode = speex_lib_get_mode (SPEEX_MODEID_NB);
423 if (enc->speex_mode != speex_lib_get_mode (SPEEX_MODEID_NB)) {
424 gst_speex_enc_set_last_msg (enc,
425 "Warning: suggest to use narrow band mode for this rate");
430 if (enc->rate != 8000 && enc->rate != 16000 && enc->rate != 32000) {
431 gst_speex_enc_set_last_msg (enc,
432 "Warning: speex is optimized for 8, 16 and 32 KHz");
435 speex_init_header (&enc->header, enc->rate, 1, enc->speex_mode);
436 enc->header.frames_per_packet = enc->nframes;
437 enc->header.vbr = enc->vbr;
438 enc->header.nb_channels = enc->channels;
440 /*Initialize Speex encoder */
441 enc->state = speex_encoder_init (enc->speex_mode);
443 speex_encoder_ctl (enc->state, SPEEX_GET_FRAME_SIZE, &enc->frame_size);
444 speex_encoder_ctl (enc->state, SPEEX_SET_COMPLEXITY, &enc->complexity);
445 speex_encoder_ctl (enc->state, SPEEX_SET_SAMPLING_RATE, &enc->rate);
448 speex_encoder_ctl (enc->state, SPEEX_SET_VBR_QUALITY, &enc->quality);
450 gint tmp = floor (enc->quality);
452 speex_encoder_ctl (enc->state, SPEEX_SET_QUALITY, &tmp);
455 if (enc->quality >= 0.0 && enc->vbr) {
456 gst_speex_enc_set_last_msg (enc,
457 "Warning: bitrate option is overriding quality");
459 speex_encoder_ctl (enc->state, SPEEX_SET_BITRATE, &enc->bitrate);
464 speex_encoder_ctl (enc->state, SPEEX_SET_VBR, &tmp);
465 } else if (enc->vad) {
468 speex_encoder_ctl (enc->state, SPEEX_SET_VAD, &tmp);
474 speex_encoder_ctl (enc->state, SPEEX_SET_DTX, &tmp);
477 if (enc->dtx && !(enc->vbr || enc->abr || enc->vad)) {
478 gst_speex_enc_set_last_msg (enc,
479 "Warning: dtx is useless without vad, vbr or abr");
480 } else if ((enc->vbr || enc->abr) && (enc->vad)) {
481 gst_speex_enc_set_last_msg (enc,
482 "Warning: vad is already implied by vbr or abr");
486 speex_encoder_ctl (enc->state, SPEEX_SET_ABR, &enc->abr);
489 speex_encoder_ctl (enc->state, SPEEX_GET_LOOKAHEAD, &enc->lookahead);
491 GST_LOG_OBJECT (enc, "we have frame size %d, lookahead %d", enc->frame_size,
497 /* push out the buffer */
499 gst_speex_enc_push_buffer (GstSpeexEnc * enc, GstBuffer * buffer)
501 GST_DEBUG_OBJECT (enc, "pushing output buffer of size %" G_GSIZE_FORMAT,
502 gst_buffer_get_size (buffer));
504 return gst_pad_push (GST_AUDIO_ENCODER_SRC_PAD (enc), buffer);
508 gst_speex_enc_sink_event (GstAudioEncoder * benc, GstEvent * event)
512 enc = GST_SPEEX_ENC (benc);
514 switch (GST_EVENT_TYPE (event)) {
520 gst_event_parse_tag (event, &list);
521 gst_tag_list_insert (enc->tags, list,
522 gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (enc)));
524 g_assert_not_reached ();
532 /* we only peeked, let base class handle it */
533 return GST_AUDIO_ENCODER_CLASS (parent_class)->event (benc, event);
537 gst_speex_enc_encode (GstSpeexEnc * enc, GstBuffer * buf)
539 gint frame_size = enc->frame_size;
540 gint bytes = frame_size * 2 * enc->channels, samples;
541 gint outsize, written, dtx_ret = 0;
543 guint8 *data, *data0 = NULL, *bdata;
546 GstFlowReturn ret = GST_FLOW_OK;
548 if (G_LIKELY (buf)) {
549 gst_buffer_map (buf, &map, GST_MAP_READ);
553 if (G_UNLIKELY (bsize % bytes)) {
554 GST_DEBUG_OBJECT (enc, "draining; adding silence samples");
556 size = ((bsize / bytes) + 1) * bytes;
557 data0 = data = g_malloc0 (size);
558 memcpy (data, bdata, bsize);
559 gst_buffer_unmap (buf, &map);
566 GST_DEBUG_OBJECT (enc, "nothing to drain");
570 samples = size / (2 * enc->channels);
571 speex_bits_reset (&enc->bits);
573 /* FIXME what about dropped samples if DTS enabled ?? */
576 GST_DEBUG_OBJECT (enc, "encoding %d samples (%d bytes)", frame_size, bytes);
578 if (enc->channels == 2) {
579 speex_encode_stereo_int ((gint16 *) data, frame_size, &enc->bits);
581 dtx_ret += speex_encode_int (enc->state, (gint16 *) data, &enc->bits);
587 speex_bits_insert_terminator (&enc->bits);
588 outsize = speex_bits_nbytes (&enc->bits);
591 gst_buffer_unmap (buf, &map);
594 ret = gst_pad_alloc_buffer_and_set_caps (GST_AUDIO_ENCODER_SRC_PAD (enc),
595 GST_BUFFER_OFFSET_NONE, outsize,
596 GST_PAD_CAPS (GST_AUDIO_ENCODER_SRC_PAD (enc)), &outbuf);
598 if ((GST_FLOW_OK != ret))
601 outbuf = gst_buffer_new_allocate (NULL, outsize, 0);
602 gst_buffer_map (outbuf, &map, GST_MAP_WRITE);
604 written = speex_bits_write (&enc->bits, (gchar *) map.data, outsize);
606 if (G_UNLIKELY (written < outsize)) {
607 GST_ERROR_OBJECT (enc, "short write: %d < %d bytes", written, outsize);
608 } else if (G_UNLIKELY (written > outsize)) {
609 GST_ERROR_OBJECT (enc, "overrun: %d > %d bytes", written, outsize);
612 gst_buffer_unmap (outbuf, &map);
613 gst_buffer_resize (outbuf, 0, written);
616 GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_GAP);
618 ret = gst_audio_encoder_finish_frame (GST_AUDIO_ENCODER (enc),
627 * (really really) FIXME: move into core (dixit tpm)
630 * _gst_caps_set_buffer_array:
632 * @field: field in caps to set
633 * @buf: header buffers
635 * Adds given buffers to an array of buffers set as the given @field
636 * on the given @caps. List of buffer arguments must be NULL-terminated.
638 * Returns: input caps with a streamheader field added, or NULL if some error
641 _gst_caps_set_buffer_array (GstCaps * caps, const gchar * field,
642 GstBuffer * buf, ...)
644 GstStructure *structure = NULL;
646 GValue array = { 0 };
647 GValue value = { 0 };
649 g_return_val_if_fail (caps != NULL, NULL);
650 g_return_val_if_fail (gst_caps_is_fixed (caps), NULL);
651 g_return_val_if_fail (field != NULL, NULL);
653 caps = gst_caps_make_writable (caps);
654 structure = gst_caps_get_structure (caps, 0);
656 g_value_init (&array, GST_TYPE_ARRAY);
659 /* put buffers in a fixed list */
661 g_assert (gst_buffer_is_writable (buf));
664 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_HEADER);
666 g_value_init (&value, GST_TYPE_BUFFER);
667 buf = gst_buffer_copy (buf);
668 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_HEADER);
669 gst_value_set_buffer (&value, buf);
670 gst_buffer_unref (buf);
671 gst_value_array_append_value (&array, &value);
672 g_value_unset (&value);
674 buf = va_arg (va, GstBuffer *);
677 gst_structure_set_value (structure, field, &array);
678 g_value_unset (&array);
684 gst_speex_enc_handle_frame (GstAudioEncoder * benc, GstBuffer * buf)
687 GstFlowReturn ret = GST_FLOW_OK;
689 enc = GST_SPEEX_ENC (benc);
691 if (!enc->header_sent) {
692 /* Speex streams begin with two headers; the initial header (with
693 most of the codec setup parameters) which is mandated by the Ogg
694 bitstream spec. The second header holds any comment fields.
695 We merely need to make the headers, then pass them to libspeex
696 one at a time; libspeex handles the additional Ogg bitstream
698 GstBuffer *buf1, *buf2;
703 /* create header buffer */
704 data = (guint8 *) speex_header_to_packet (&enc->header, &data_len);
705 buf1 = gst_buffer_new_wrapped (data, data_len);
706 GST_BUFFER_OFFSET_END (buf1) = 0;
707 GST_BUFFER_OFFSET (buf1) = 0;
709 /* create comment buffer */
710 buf2 = gst_speex_enc_create_metadata_buffer (enc);
712 /* mark and put on caps */
713 caps = gst_caps_new_simple ("audio/x-speex", "rate", G_TYPE_INT, enc->rate,
714 "channels", G_TYPE_INT, enc->channels, NULL);
715 caps = _gst_caps_set_buffer_array (caps, "streamheader", buf1, buf2, NULL);
717 /* negotiate with these caps */
718 GST_DEBUG_OBJECT (enc, "here are the caps: %" GST_PTR_FORMAT, caps);
720 gst_audio_encoder_set_output_format (GST_AUDIO_ENCODER (enc), caps);
721 gst_caps_unref (caps);
723 /* push out buffers */
724 /* store buffers for later pre_push sending */
725 g_slist_foreach (enc->headers, (GFunc) gst_buffer_unref, NULL);
727 GST_DEBUG_OBJECT (enc, "storing header buffers");
728 enc->headers = g_slist_prepend (enc->headers, buf2);
729 enc->headers = g_slist_prepend (enc->headers, buf1);
731 enc->header_sent = TRUE;
734 GST_DEBUG_OBJECT (enc, "received buffer %p of %" G_GSIZE_FORMAT " bytes", buf,
735 buf ? gst_buffer_get_size (buf) : 0);
737 ret = gst_speex_enc_encode (enc, buf);
743 gst_speex_enc_pre_push (GstAudioEncoder * benc, GstBuffer ** buffer)
746 GstFlowReturn ret = GST_FLOW_OK;
748 enc = GST_SPEEX_ENC (benc);
750 /* FIXME 0.11 ? get rid of this special ogg stuff and have it
751 * put and use 'codec data' in caps like anything else,
752 * with all the usual out-of-band advantage etc */
753 if (G_UNLIKELY (enc->headers)) {
754 GSList *header = enc->headers;
756 /* try to push all of these, if we lose one, might as well lose all */
758 if (ret == GST_FLOW_OK)
759 ret = gst_speex_enc_push_buffer (enc, header->data);
761 gst_speex_enc_push_buffer (enc, header->data);
762 header = g_slist_next (header);
765 g_slist_free (enc->headers);
773 gst_speex_enc_get_property (GObject * object, guint prop_id, GValue * value,
778 enc = GST_SPEEX_ENC (object);
782 g_value_set_float (value, enc->quality);
785 g_value_set_int (value, enc->bitrate);
788 g_value_set_enum (value, enc->mode);
791 g_value_set_boolean (value, enc->vbr);
794 g_value_set_int (value, enc->abr);
797 g_value_set_boolean (value, enc->vad);
800 g_value_set_boolean (value, enc->dtx);
802 case PROP_COMPLEXITY:
803 g_value_set_int (value, enc->complexity);
806 g_value_set_int (value, enc->nframes);
808 case PROP_LAST_MESSAGE:
809 g_value_set_string (value, enc->last_message);
812 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
818 gst_speex_enc_set_property (GObject * object, guint prop_id,
819 const GValue * value, GParamSpec * pspec)
823 enc = GST_SPEEX_ENC (object);
827 enc->quality = g_value_get_float (value);
830 enc->bitrate = g_value_get_int (value);
833 enc->mode = g_value_get_enum (value);
836 enc->vbr = g_value_get_boolean (value);
839 enc->abr = g_value_get_int (value);
842 enc->vad = g_value_get_boolean (value);
845 enc->dtx = g_value_get_boolean (value);
847 case PROP_COMPLEXITY:
848 enc->complexity = g_value_get_int (value);
851 enc->nframes = g_value_get_int (value);
854 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);