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);
245 GST_PAD_SET_ACCEPT_TEMPLATE (GST_AUDIO_ENCODER_SINK_PAD (enc));
249 gst_speex_enc_start (GstAudioEncoder * benc)
251 GstSpeexEnc *enc = GST_SPEEX_ENC (benc);
253 GST_DEBUG_OBJECT (enc, "start");
254 speex_bits_init (&enc->bits);
255 enc->tags = gst_tag_list_new_empty ();
256 enc->header_sent = FALSE;
257 enc->encoded_samples = 0;
263 gst_speex_enc_stop (GstAudioEncoder * benc)
265 GstSpeexEnc *enc = GST_SPEEX_ENC (benc);
267 GST_DEBUG_OBJECT (enc, "stop");
268 enc->header_sent = FALSE;
270 speex_encoder_destroy (enc->state);
273 speex_bits_destroy (&enc->bits);
274 speex_bits_set_bit_buffer (&enc->bits, NULL, 0);
275 gst_tag_list_unref (enc->tags);
278 gst_tag_setter_reset_tags (GST_TAG_SETTER (enc));
284 gst_speex_enc_get_latency (GstSpeexEnc * enc)
286 /* See the Speex manual section "Latency and algorithmic delay" */
287 if (enc->rate == 8000)
288 return 30 * GST_MSECOND;
290 return 34 * GST_MSECOND;
294 gst_speex_enc_set_format (GstAudioEncoder * benc, GstAudioInfo * info)
298 enc = GST_SPEEX_ENC (benc);
300 enc->channels = GST_AUDIO_INFO_CHANNELS (info);
301 enc->rate = GST_AUDIO_INFO_RATE (info);
303 /* handle reconfigure */
305 speex_encoder_destroy (enc->state);
309 if (!gst_speex_enc_setup (enc))
312 /* feedback to base class */
313 gst_audio_encoder_set_latency (benc,
314 gst_speex_enc_get_latency (enc), gst_speex_enc_get_latency (enc));
315 gst_audio_encoder_set_lookahead (benc, enc->lookahead);
317 if (enc->nframes == 0) {
318 /* as many frames as available input allows */
319 gst_audio_encoder_set_frame_samples_min (benc, enc->frame_size);
320 gst_audio_encoder_set_frame_samples_max (benc, enc->frame_size);
321 gst_audio_encoder_set_frame_max (benc, 0);
323 /* exactly as many frames as configured */
324 gst_audio_encoder_set_frame_samples_min (benc,
325 enc->frame_size * enc->nframes);
326 gst_audio_encoder_set_frame_samples_max (benc,
327 enc->frame_size * enc->nframes);
328 gst_audio_encoder_set_frame_max (benc, 1);
335 gst_speex_enc_create_metadata_buffer (GstSpeexEnc * enc)
337 const GstTagList *user_tags;
338 GstTagList *merged_tags;
339 GstBuffer *comments = NULL;
341 user_tags = gst_tag_setter_get_tag_list (GST_TAG_SETTER (enc));
343 GST_DEBUG_OBJECT (enc, "upstream tags = %" GST_PTR_FORMAT, enc->tags);
344 GST_DEBUG_OBJECT (enc, "user-set tags = %" GST_PTR_FORMAT, user_tags);
346 /* gst_tag_list_merge() will handle NULL for either or both lists fine */
347 merged_tags = gst_tag_list_merge (user_tags, enc->tags,
348 gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (enc)));
350 if (merged_tags == NULL)
351 merged_tags = gst_tag_list_new_empty ();
353 GST_DEBUG_OBJECT (enc, "merged tags = %" GST_PTR_FORMAT, merged_tags);
354 comments = gst_tag_list_to_vorbiscomment_buffer (merged_tags, NULL,
355 0, "Encoded with GStreamer Speexenc");
356 gst_tag_list_unref (merged_tags);
358 GST_BUFFER_OFFSET (comments) = 0;
359 GST_BUFFER_OFFSET_END (comments) = 0;
365 gst_speex_enc_set_last_msg (GstSpeexEnc * enc, const gchar * msg)
367 g_free (enc->last_message);
368 enc->last_message = g_strdup (msg);
369 GST_WARNING_OBJECT (enc, "%s", msg);
370 g_object_notify (G_OBJECT (enc), "last-message");
374 gst_speex_enc_setup (GstSpeexEnc * enc)
377 case GST_SPEEX_ENC_MODE_UWB:
378 GST_LOG_OBJECT (enc, "configuring for requested UWB mode");
379 enc->speex_mode = speex_lib_get_mode (SPEEX_MODEID_UWB);
381 case GST_SPEEX_ENC_MODE_WB:
382 GST_LOG_OBJECT (enc, "configuring for requested WB mode");
383 enc->speex_mode = speex_lib_get_mode (SPEEX_MODEID_WB);
385 case GST_SPEEX_ENC_MODE_NB:
386 GST_LOG_OBJECT (enc, "configuring for requested NB mode");
387 enc->speex_mode = speex_lib_get_mode (SPEEX_MODEID_NB);
389 case GST_SPEEX_ENC_MODE_AUTO:
391 GST_LOG_OBJECT (enc, "finding best mode");
396 if (enc->rate > 25000) {
397 if (enc->mode == GST_SPEEX_ENC_MODE_AUTO) {
398 GST_LOG_OBJECT (enc, "selected UWB mode for samplerate %d", enc->rate);
399 enc->speex_mode = speex_lib_get_mode (SPEEX_MODEID_UWB);
401 if (enc->speex_mode != speex_lib_get_mode (SPEEX_MODEID_UWB)) {
402 gst_speex_enc_set_last_msg (enc,
403 "Warning: suggest to use ultra wide band mode for this rate");
406 } else if (enc->rate > 12500) {
407 if (enc->mode == GST_SPEEX_ENC_MODE_AUTO) {
408 GST_LOG_OBJECT (enc, "selected WB mode for samplerate %d", enc->rate);
409 enc->speex_mode = speex_lib_get_mode (SPEEX_MODEID_WB);
411 if (enc->speex_mode != speex_lib_get_mode (SPEEX_MODEID_WB)) {
412 gst_speex_enc_set_last_msg (enc,
413 "Warning: suggest to use wide band mode for this rate");
417 if (enc->mode == GST_SPEEX_ENC_MODE_AUTO) {
418 GST_LOG_OBJECT (enc, "selected NB mode for samplerate %d", enc->rate);
419 enc->speex_mode = speex_lib_get_mode (SPEEX_MODEID_NB);
421 if (enc->speex_mode != speex_lib_get_mode (SPEEX_MODEID_NB)) {
422 gst_speex_enc_set_last_msg (enc,
423 "Warning: suggest to use narrow band mode for this rate");
428 if (enc->rate != 8000 && enc->rate != 16000 && enc->rate != 32000) {
429 gst_speex_enc_set_last_msg (enc,
430 "Warning: speex is optimized for 8, 16 and 32 KHz");
433 speex_init_header (&enc->header, enc->rate, 1, enc->speex_mode);
434 enc->header.frames_per_packet = enc->nframes;
435 enc->header.vbr = enc->vbr;
436 enc->header.nb_channels = enc->channels;
438 /*Initialize Speex encoder */
439 enc->state = speex_encoder_init (enc->speex_mode);
441 speex_encoder_ctl (enc->state, SPEEX_GET_FRAME_SIZE, &enc->frame_size);
442 speex_encoder_ctl (enc->state, SPEEX_SET_COMPLEXITY, &enc->complexity);
443 speex_encoder_ctl (enc->state, SPEEX_SET_SAMPLING_RATE, &enc->rate);
446 speex_encoder_ctl (enc->state, SPEEX_SET_VBR_QUALITY, &enc->quality);
448 gint tmp = floor (enc->quality);
450 speex_encoder_ctl (enc->state, SPEEX_SET_QUALITY, &tmp);
453 if (enc->quality >= 0.0 && enc->vbr) {
454 gst_speex_enc_set_last_msg (enc,
455 "Warning: bitrate option is overriding quality");
457 speex_encoder_ctl (enc->state, SPEEX_SET_BITRATE, &enc->bitrate);
462 speex_encoder_ctl (enc->state, SPEEX_SET_VBR, &tmp);
463 } else if (enc->vad) {
466 speex_encoder_ctl (enc->state, SPEEX_SET_VAD, &tmp);
472 speex_encoder_ctl (enc->state, SPEEX_SET_DTX, &tmp);
475 if (enc->dtx && !(enc->vbr || enc->abr || enc->vad)) {
476 gst_speex_enc_set_last_msg (enc,
477 "Warning: dtx is useless without vad, vbr or abr");
478 } else if ((enc->vbr || enc->abr) && (enc->vad)) {
479 gst_speex_enc_set_last_msg (enc,
480 "Warning: vad is already implied by vbr or abr");
484 speex_encoder_ctl (enc->state, SPEEX_SET_ABR, &enc->abr);
487 speex_encoder_ctl (enc->state, SPEEX_GET_LOOKAHEAD, &enc->lookahead);
489 GST_LOG_OBJECT (enc, "we have frame size %d, lookahead %d", enc->frame_size,
496 gst_speex_enc_sink_event (GstAudioEncoder * benc, GstEvent * event)
500 enc = GST_SPEEX_ENC (benc);
502 switch (GST_EVENT_TYPE (event)) {
508 gst_event_parse_tag (event, &list);
509 gst_tag_list_insert (enc->tags, list,
510 gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (enc)));
512 g_assert_not_reached ();
516 case GST_EVENT_SEGMENT:
517 enc->encoded_samples = 0;
523 /* we only peeked, let base class handle it */
524 return GST_AUDIO_ENCODER_CLASS (parent_class)->sink_event (benc, event);
528 gst_speex_enc_encode (GstSpeexEnc * enc, GstBuffer * buf)
530 gint frame_size = enc->frame_size;
531 gint bytes = frame_size * 2 * enc->channels, samples;
532 gint outsize, written, dtx_ret = 0;
534 guint8 *data, *data0 = NULL, *bdata;
537 GstFlowReturn ret = GST_FLOW_OK;
539 GstClockTime duration;
541 if (G_LIKELY (buf)) {
542 gst_buffer_map (buf, &map, GST_MAP_READ);
546 if (G_UNLIKELY (bsize % bytes)) {
547 GST_DEBUG_OBJECT (enc, "draining; adding silence samples");
549 /* If encoding part of a frame, and we have no set stop time on
550 * the output segment, we update the segment stop time to reflect
551 * the last sample. This will let oggmux set the last page's
552 * granpos to tell a decoder the dummy samples should be clipped.
554 segment = &GST_AUDIO_ENCODER_OUTPUT_SEGMENT (enc);
555 GST_DEBUG_OBJECT (enc, "existing output segment %" GST_SEGMENT_FORMAT,
557 if (!GST_CLOCK_TIME_IS_VALID (segment->stop)) {
558 int input_samples = bsize / (enc->channels * 2);
559 GST_DEBUG_OBJECT (enc,
560 "No stop time and partial frame, updating segment");
562 gst_util_uint64_scale (enc->encoded_samples + input_samples,
563 GST_SECOND, enc->rate);
564 segment->stop = segment->start + duration;
565 GST_DEBUG_OBJECT (enc, "new output segment %" GST_SEGMENT_FORMAT,
567 gst_pad_push_event (GST_AUDIO_ENCODER_SRC_PAD (enc),
568 gst_event_new_segment (segment));
571 size = ((bsize / bytes) + 1) * bytes;
572 data0 = data = g_malloc0 (size);
573 memcpy (data, bdata, bsize);
574 gst_buffer_unmap (buf, &map);
581 GST_DEBUG_OBJECT (enc, "nothing to drain");
585 samples = size / (2 * enc->channels);
586 speex_bits_reset (&enc->bits);
588 /* FIXME what about dropped samples if DTS enabled ?? */
591 GST_DEBUG_OBJECT (enc, "encoding %d samples (%d bytes)", frame_size, bytes);
593 if (enc->channels == 2) {
594 speex_encode_stereo_int ((gint16 *) data, frame_size, &enc->bits);
596 dtx_ret += speex_encode_int (enc->state, (gint16 *) data, &enc->bits);
602 speex_bits_insert_terminator (&enc->bits);
603 outsize = speex_bits_nbytes (&enc->bits);
606 gst_buffer_unmap (buf, &map);
609 ret = gst_pad_alloc_buffer_and_set_caps (GST_AUDIO_ENCODER_SRC_PAD (enc),
610 GST_BUFFER_OFFSET_NONE, outsize,
611 GST_PAD_CAPS (GST_AUDIO_ENCODER_SRC_PAD (enc)), &outbuf);
613 if ((GST_FLOW_OK != ret))
616 outbuf = gst_buffer_new_allocate (NULL, outsize, NULL);
617 gst_buffer_map (outbuf, &map, GST_MAP_WRITE);
619 written = speex_bits_write (&enc->bits, (gchar *) map.data, outsize);
621 if (G_UNLIKELY (written < outsize)) {
622 GST_ERROR_OBJECT (enc, "short write: %d < %d bytes", written, outsize);
623 } else if (G_UNLIKELY (written > outsize)) {
624 GST_ERROR_OBJECT (enc, "overrun: %d > %d bytes", written, outsize);
627 gst_buffer_unmap (outbuf, &map);
628 gst_buffer_resize (outbuf, 0, written);
631 GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_GAP);
633 ret = gst_audio_encoder_finish_frame (GST_AUDIO_ENCODER (enc),
635 enc->encoded_samples += frame_size;
643 * (really really) FIXME: move into core (dixit tpm)
646 * _gst_caps_set_buffer_array:
647 * @caps: (transfer full): a #GstCaps
648 * @field: field in caps to set
649 * @buf: header buffers
651 * Adds given buffers to an array of buffers set as the given @field
652 * on the given @caps. List of buffer arguments must be NULL-terminated.
654 * Returns: (transfer full): input caps with a streamheader field added, or NULL
655 * if some error occurred
658 _gst_caps_set_buffer_array (GstCaps * caps, const gchar * field,
659 GstBuffer * buf, ...)
661 GstStructure *structure = NULL;
663 GValue array = { 0 };
664 GValue value = { 0 };
666 g_return_val_if_fail (caps != NULL, NULL);
667 g_return_val_if_fail (gst_caps_is_fixed (caps), NULL);
668 g_return_val_if_fail (field != NULL, NULL);
670 caps = gst_caps_make_writable (caps);
671 structure = gst_caps_get_structure (caps, 0);
673 g_value_init (&array, GST_TYPE_ARRAY);
676 /* put buffers in a fixed list */
678 g_assert (gst_buffer_is_writable (buf));
681 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_HEADER);
683 g_value_init (&value, GST_TYPE_BUFFER);
684 buf = gst_buffer_copy (buf);
685 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_HEADER);
686 gst_value_set_buffer (&value, buf);
687 gst_buffer_unref (buf);
688 gst_value_array_append_value (&array, &value);
689 g_value_unset (&value);
691 buf = va_arg (va, GstBuffer *);
695 gst_structure_set_value (structure, field, &array);
696 g_value_unset (&array);
702 gst_speex_enc_handle_frame (GstAudioEncoder * benc, GstBuffer * buf)
705 GstFlowReturn ret = GST_FLOW_OK;
707 enc = GST_SPEEX_ENC (benc);
709 if (!enc->header_sent) {
710 /* Speex streams begin with two headers; the initial header (with
711 most of the codec setup parameters) which is mandated by the Ogg
712 bitstream spec. The second header holds any comment fields.
713 We merely need to make the headers, then pass them to libspeex
714 one at a time; libspeex handles the additional Ogg bitstream
716 GstBuffer *buf1, *buf2;
722 /* create header buffer */
723 data = (guint8 *) speex_header_to_packet (&enc->header, &data_len);
724 buf1 = gst_buffer_new_wrapped (data, data_len);
725 GST_BUFFER_OFFSET_END (buf1) = 0;
726 GST_BUFFER_OFFSET (buf1) = 0;
728 /* create comment buffer */
729 buf2 = gst_speex_enc_create_metadata_buffer (enc);
731 /* mark and put on caps */
732 caps = gst_caps_new_simple ("audio/x-speex", "rate", G_TYPE_INT, enc->rate,
733 "channels", G_TYPE_INT, enc->channels, NULL);
734 caps = _gst_caps_set_buffer_array (caps, "streamheader", buf1, buf2, NULL);
736 /* negotiate with these caps */
737 GST_DEBUG_OBJECT (enc, "here are the caps: %" GST_PTR_FORMAT, caps);
739 gst_audio_encoder_set_output_format (GST_AUDIO_ENCODER (enc), caps);
740 gst_caps_unref (caps);
742 /* push out buffers */
743 /* store buffers for later pre_push sending */
745 GST_DEBUG_OBJECT (enc, "storing header buffers");
746 headers = g_list_prepend (headers, buf2);
747 headers = g_list_prepend (headers, buf1);
748 gst_audio_encoder_set_headers (benc, headers);
750 enc->header_sent = TRUE;
753 GST_DEBUG_OBJECT (enc, "received buffer %p of %" G_GSIZE_FORMAT " bytes", buf,
754 buf ? gst_buffer_get_size (buf) : 0);
756 ret = gst_speex_enc_encode (enc, buf);
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);