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);
248 gst_speex_enc_start (GstAudioEncoder * benc)
250 GstSpeexEnc *enc = GST_SPEEX_ENC (benc);
252 GST_DEBUG_OBJECT (enc, "start");
253 speex_bits_init (&enc->bits);
254 enc->tags = gst_tag_list_new_empty ();
255 enc->header_sent = FALSE;
256 enc->encoded_samples = 0;
262 gst_speex_enc_stop (GstAudioEncoder * benc)
264 GstSpeexEnc *enc = GST_SPEEX_ENC (benc);
266 GST_DEBUG_OBJECT (enc, "stop");
267 enc->header_sent = FALSE;
269 speex_encoder_destroy (enc->state);
272 speex_bits_destroy (&enc->bits);
273 speex_bits_set_bit_buffer (&enc->bits, NULL, 0);
274 gst_tag_list_unref (enc->tags);
277 gst_tag_setter_reset_tags (GST_TAG_SETTER (enc));
283 gst_speex_enc_get_latency (GstSpeexEnc * enc)
285 /* See the Speex manual section "Latency and algorithmic delay" */
286 if (enc->rate == 8000)
287 return 30 * GST_MSECOND;
289 return 34 * GST_MSECOND;
293 gst_speex_enc_set_format (GstAudioEncoder * benc, GstAudioInfo * info)
297 enc = GST_SPEEX_ENC (benc);
299 enc->channels = GST_AUDIO_INFO_CHANNELS (info);
300 enc->rate = GST_AUDIO_INFO_RATE (info);
302 /* handle reconfigure */
304 speex_encoder_destroy (enc->state);
308 if (!gst_speex_enc_setup (enc))
311 /* feedback to base class */
312 gst_audio_encoder_set_latency (benc,
313 gst_speex_enc_get_latency (enc), gst_speex_enc_get_latency (enc));
314 gst_audio_encoder_set_lookahead (benc, enc->lookahead);
316 if (enc->nframes == 0) {
317 /* as many frames as available input allows */
318 gst_audio_encoder_set_frame_samples_min (benc, enc->frame_size);
319 gst_audio_encoder_set_frame_samples_max (benc, enc->frame_size);
320 gst_audio_encoder_set_frame_max (benc, 0);
322 /* exactly as many frames as configured */
323 gst_audio_encoder_set_frame_samples_min (benc,
324 enc->frame_size * enc->nframes);
325 gst_audio_encoder_set_frame_samples_max (benc,
326 enc->frame_size * enc->nframes);
327 gst_audio_encoder_set_frame_max (benc, 1);
334 gst_speex_enc_create_metadata_buffer (GstSpeexEnc * enc)
336 const GstTagList *user_tags;
337 GstTagList *merged_tags;
338 GstBuffer *comments = NULL;
340 user_tags = gst_tag_setter_get_tag_list (GST_TAG_SETTER (enc));
342 GST_DEBUG_OBJECT (enc, "upstream tags = %" GST_PTR_FORMAT, enc->tags);
343 GST_DEBUG_OBJECT (enc, "user-set tags = %" GST_PTR_FORMAT, user_tags);
345 /* gst_tag_list_merge() will handle NULL for either or both lists fine */
346 merged_tags = gst_tag_list_merge (user_tags, enc->tags,
347 gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (enc)));
349 if (merged_tags == NULL)
350 merged_tags = gst_tag_list_new_empty ();
352 GST_DEBUG_OBJECT (enc, "merged tags = %" GST_PTR_FORMAT, merged_tags);
353 comments = gst_tag_list_to_vorbiscomment_buffer (merged_tags, NULL,
354 0, "Encoded with GStreamer Speexenc");
355 gst_tag_list_unref (merged_tags);
357 GST_BUFFER_OFFSET (comments) = 0;
358 GST_BUFFER_OFFSET_END (comments) = 0;
364 gst_speex_enc_set_last_msg (GstSpeexEnc * enc, const gchar * msg)
366 g_free (enc->last_message);
367 enc->last_message = g_strdup (msg);
368 GST_WARNING_OBJECT (enc, "%s", msg);
369 g_object_notify (G_OBJECT (enc), "last-message");
373 gst_speex_enc_setup (GstSpeexEnc * enc)
376 case GST_SPEEX_ENC_MODE_UWB:
377 GST_LOG_OBJECT (enc, "configuring for requested UWB mode");
378 enc->speex_mode = speex_lib_get_mode (SPEEX_MODEID_UWB);
380 case GST_SPEEX_ENC_MODE_WB:
381 GST_LOG_OBJECT (enc, "configuring for requested WB mode");
382 enc->speex_mode = speex_lib_get_mode (SPEEX_MODEID_WB);
384 case GST_SPEEX_ENC_MODE_NB:
385 GST_LOG_OBJECT (enc, "configuring for requested NB mode");
386 enc->speex_mode = speex_lib_get_mode (SPEEX_MODEID_NB);
388 case GST_SPEEX_ENC_MODE_AUTO:
390 GST_LOG_OBJECT (enc, "finding best mode");
395 if (enc->rate > 25000) {
396 if (enc->mode == GST_SPEEX_ENC_MODE_AUTO) {
397 GST_LOG_OBJECT (enc, "selected UWB mode for samplerate %d", enc->rate);
398 enc->speex_mode = speex_lib_get_mode (SPEEX_MODEID_UWB);
400 if (enc->speex_mode != speex_lib_get_mode (SPEEX_MODEID_UWB)) {
401 gst_speex_enc_set_last_msg (enc,
402 "Warning: suggest to use ultra wide band mode for this rate");
405 } else if (enc->rate > 12500) {
406 if (enc->mode == GST_SPEEX_ENC_MODE_AUTO) {
407 GST_LOG_OBJECT (enc, "selected WB mode for samplerate %d", enc->rate);
408 enc->speex_mode = speex_lib_get_mode (SPEEX_MODEID_WB);
410 if (enc->speex_mode != speex_lib_get_mode (SPEEX_MODEID_WB)) {
411 gst_speex_enc_set_last_msg (enc,
412 "Warning: suggest to use wide band mode for this rate");
416 if (enc->mode == GST_SPEEX_ENC_MODE_AUTO) {
417 GST_LOG_OBJECT (enc, "selected NB mode for samplerate %d", enc->rate);
418 enc->speex_mode = speex_lib_get_mode (SPEEX_MODEID_NB);
420 if (enc->speex_mode != speex_lib_get_mode (SPEEX_MODEID_NB)) {
421 gst_speex_enc_set_last_msg (enc,
422 "Warning: suggest to use narrow band mode for this rate");
427 if (enc->rate != 8000 && enc->rate != 16000 && enc->rate != 32000) {
428 gst_speex_enc_set_last_msg (enc,
429 "Warning: speex is optimized for 8, 16 and 32 KHz");
432 speex_init_header (&enc->header, enc->rate, 1, enc->speex_mode);
433 enc->header.frames_per_packet = enc->nframes;
434 enc->header.vbr = enc->vbr;
435 enc->header.nb_channels = enc->channels;
437 /*Initialize Speex encoder */
438 enc->state = speex_encoder_init (enc->speex_mode);
440 speex_encoder_ctl (enc->state, SPEEX_GET_FRAME_SIZE, &enc->frame_size);
441 speex_encoder_ctl (enc->state, SPEEX_SET_COMPLEXITY, &enc->complexity);
442 speex_encoder_ctl (enc->state, SPEEX_SET_SAMPLING_RATE, &enc->rate);
445 speex_encoder_ctl (enc->state, SPEEX_SET_VBR_QUALITY, &enc->quality);
447 gint tmp = floor (enc->quality);
449 speex_encoder_ctl (enc->state, SPEEX_SET_QUALITY, &tmp);
452 if (enc->quality >= 0.0 && enc->vbr) {
453 gst_speex_enc_set_last_msg (enc,
454 "Warning: bitrate option is overriding quality");
456 speex_encoder_ctl (enc->state, SPEEX_SET_BITRATE, &enc->bitrate);
461 speex_encoder_ctl (enc->state, SPEEX_SET_VBR, &tmp);
462 } else if (enc->vad) {
465 speex_encoder_ctl (enc->state, SPEEX_SET_VAD, &tmp);
471 speex_encoder_ctl (enc->state, SPEEX_SET_DTX, &tmp);
474 if (enc->dtx && !(enc->vbr || enc->abr || enc->vad)) {
475 gst_speex_enc_set_last_msg (enc,
476 "Warning: dtx is useless without vad, vbr or abr");
477 } else if ((enc->vbr || enc->abr) && (enc->vad)) {
478 gst_speex_enc_set_last_msg (enc,
479 "Warning: vad is already implied by vbr or abr");
483 speex_encoder_ctl (enc->state, SPEEX_SET_ABR, &enc->abr);
486 speex_encoder_ctl (enc->state, SPEEX_GET_LOOKAHEAD, &enc->lookahead);
488 GST_LOG_OBJECT (enc, "we have frame size %d, lookahead %d", enc->frame_size,
495 gst_speex_enc_sink_event (GstAudioEncoder * benc, GstEvent * event)
499 enc = GST_SPEEX_ENC (benc);
501 switch (GST_EVENT_TYPE (event)) {
507 gst_event_parse_tag (event, &list);
508 gst_tag_list_insert (enc->tags, list,
509 gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (enc)));
511 g_assert_not_reached ();
515 case GST_EVENT_SEGMENT:
516 enc->encoded_samples = 0;
522 /* we only peeked, let base class handle it */
523 return GST_AUDIO_ENCODER_CLASS (parent_class)->sink_event (benc, event);
527 gst_speex_enc_encode (GstSpeexEnc * enc, GstBuffer * buf)
529 gint frame_size = enc->frame_size;
530 gint bytes = frame_size * 2 * enc->channels, samples;
531 gint outsize, written, dtx_ret = 0;
533 guint8 *data, *data0 = NULL, *bdata;
536 GstFlowReturn ret = GST_FLOW_OK;
538 GstClockTime duration;
540 if (G_LIKELY (buf)) {
541 gst_buffer_map (buf, &map, GST_MAP_READ);
545 if (G_UNLIKELY (bsize % bytes)) {
546 GST_DEBUG_OBJECT (enc, "draining; adding silence samples");
548 /* If encoding part of a frame, and we have no set stop time on
549 * the output segment, we update the segment stop time to reflect
550 * the last sample. This will let oggmux set the last page's
551 * granpos to tell a decoder the dummy samples should be clipped.
553 segment = &GST_AUDIO_ENCODER_OUTPUT_SEGMENT (enc);
554 GST_DEBUG_OBJECT (enc, "existing output segment %" GST_SEGMENT_FORMAT,
556 if (!GST_CLOCK_TIME_IS_VALID (segment->stop)) {
557 int input_samples = bsize / (enc->channels * 2);
558 GST_DEBUG_OBJECT (enc,
559 "No stop time and partial frame, updating segment");
561 gst_util_uint64_scale (enc->encoded_samples + input_samples,
562 GST_SECOND, enc->rate);
563 segment->stop = segment->start + duration;
564 GST_DEBUG_OBJECT (enc, "new output segment %" GST_SEGMENT_FORMAT,
566 gst_pad_push_event (GST_AUDIO_ENCODER_SRC_PAD (enc),
567 gst_event_new_segment (segment));
570 size = ((bsize / bytes) + 1) * bytes;
571 data0 = data = g_malloc0 (size);
572 memcpy (data, bdata, bsize);
573 gst_buffer_unmap (buf, &map);
580 GST_DEBUG_OBJECT (enc, "nothing to drain");
584 samples = size / (2 * enc->channels);
585 speex_bits_reset (&enc->bits);
587 /* FIXME what about dropped samples if DTS enabled ?? */
590 GST_DEBUG_OBJECT (enc, "encoding %d samples (%d bytes)", frame_size, bytes);
592 if (enc->channels == 2) {
593 speex_encode_stereo_int ((gint16 *) data, frame_size, &enc->bits);
595 dtx_ret += speex_encode_int (enc->state, (gint16 *) data, &enc->bits);
601 speex_bits_insert_terminator (&enc->bits);
602 outsize = speex_bits_nbytes (&enc->bits);
605 gst_buffer_unmap (buf, &map);
608 ret = gst_pad_alloc_buffer_and_set_caps (GST_AUDIO_ENCODER_SRC_PAD (enc),
609 GST_BUFFER_OFFSET_NONE, outsize,
610 GST_PAD_CAPS (GST_AUDIO_ENCODER_SRC_PAD (enc)), &outbuf);
612 if ((GST_FLOW_OK != ret))
615 outbuf = gst_buffer_new_allocate (NULL, outsize, NULL);
616 gst_buffer_map (outbuf, &map, GST_MAP_WRITE);
618 written = speex_bits_write (&enc->bits, (gchar *) map.data, outsize);
620 if (G_UNLIKELY (written < outsize)) {
621 GST_ERROR_OBJECT (enc, "short write: %d < %d bytes", written, outsize);
622 } else if (G_UNLIKELY (written > outsize)) {
623 GST_ERROR_OBJECT (enc, "overrun: %d > %d bytes", written, outsize);
626 gst_buffer_unmap (outbuf, &map);
627 gst_buffer_resize (outbuf, 0, written);
630 GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_GAP);
632 ret = gst_audio_encoder_finish_frame (GST_AUDIO_ENCODER (enc),
634 enc->encoded_samples += frame_size;
642 * (really really) FIXME: move into core (dixit tpm)
645 * _gst_caps_set_buffer_array:
646 * @caps: (transfer full): a #GstCaps
647 * @field: field in caps to set
648 * @buf: header buffers
650 * Adds given buffers to an array of buffers set as the given @field
651 * on the given @caps. List of buffer arguments must be NULL-terminated.
653 * Returns: (transfer full): input caps with a streamheader field added, or NULL
654 * if some error occurred
657 _gst_caps_set_buffer_array (GstCaps * caps, const gchar * field,
658 GstBuffer * buf, ...)
660 GstStructure *structure = NULL;
662 GValue array = { 0 };
663 GValue value = { 0 };
665 g_return_val_if_fail (caps != NULL, NULL);
666 g_return_val_if_fail (gst_caps_is_fixed (caps), NULL);
667 g_return_val_if_fail (field != NULL, NULL);
669 caps = gst_caps_make_writable (caps);
670 structure = gst_caps_get_structure (caps, 0);
672 g_value_init (&array, GST_TYPE_ARRAY);
675 /* put buffers in a fixed list */
677 g_assert (gst_buffer_is_writable (buf));
680 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_HEADER);
682 g_value_init (&value, GST_TYPE_BUFFER);
683 buf = gst_buffer_copy (buf);
684 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_HEADER);
685 gst_value_set_buffer (&value, buf);
686 gst_buffer_unref (buf);
687 gst_value_array_append_value (&array, &value);
688 g_value_unset (&value);
690 buf = va_arg (va, GstBuffer *);
694 gst_structure_set_value (structure, field, &array);
695 g_value_unset (&array);
701 gst_speex_enc_handle_frame (GstAudioEncoder * benc, GstBuffer * buf)
704 GstFlowReturn ret = GST_FLOW_OK;
706 enc = GST_SPEEX_ENC (benc);
708 if (!enc->header_sent) {
709 /* Speex streams begin with two headers; the initial header (with
710 most of the codec setup parameters) which is mandated by the Ogg
711 bitstream spec. The second header holds any comment fields.
712 We merely need to make the headers, then pass them to libspeex
713 one at a time; libspeex handles the additional Ogg bitstream
715 GstBuffer *buf1, *buf2;
721 /* create header buffer */
722 data = (guint8 *) speex_header_to_packet (&enc->header, &data_len);
723 buf1 = gst_buffer_new_wrapped (data, data_len);
724 GST_BUFFER_OFFSET_END (buf1) = 0;
725 GST_BUFFER_OFFSET (buf1) = 0;
727 /* create comment buffer */
728 buf2 = gst_speex_enc_create_metadata_buffer (enc);
730 /* mark and put on caps */
731 caps = gst_caps_new_simple ("audio/x-speex", "rate", G_TYPE_INT, enc->rate,
732 "channels", G_TYPE_INT, enc->channels, NULL);
733 caps = _gst_caps_set_buffer_array (caps, "streamheader", buf1, buf2, NULL);
735 /* negotiate with these caps */
736 GST_DEBUG_OBJECT (enc, "here are the caps: %" GST_PTR_FORMAT, caps);
738 gst_audio_encoder_set_output_format (GST_AUDIO_ENCODER (enc), caps);
739 gst_caps_unref (caps);
741 /* push out buffers */
742 /* store buffers for later pre_push sending */
744 GST_DEBUG_OBJECT (enc, "storing header buffers");
745 headers = g_list_prepend (headers, buf2);
746 headers = g_list_prepend (headers, buf1);
747 gst_audio_encoder_set_headers (benc, headers);
749 enc->header_sent = TRUE;
752 GST_DEBUG_OBJECT (enc, "received buffer %p of %" G_GSIZE_FORMAT " bytes", buf,
753 buf ? gst_buffer_get_size (buf) : 0);
755 ret = gst_speex_enc_encode (enc, buf);
761 gst_speex_enc_get_property (GObject * object, guint prop_id, GValue * value,
766 enc = GST_SPEEX_ENC (object);
770 g_value_set_float (value, enc->quality);
773 g_value_set_int (value, enc->bitrate);
776 g_value_set_enum (value, enc->mode);
779 g_value_set_boolean (value, enc->vbr);
782 g_value_set_int (value, enc->abr);
785 g_value_set_boolean (value, enc->vad);
788 g_value_set_boolean (value, enc->dtx);
790 case PROP_COMPLEXITY:
791 g_value_set_int (value, enc->complexity);
794 g_value_set_int (value, enc->nframes);
796 case PROP_LAST_MESSAGE:
797 g_value_set_string (value, enc->last_message);
800 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
806 gst_speex_enc_set_property (GObject * object, guint prop_id,
807 const GValue * value, GParamSpec * pspec)
811 enc = GST_SPEEX_ENC (object);
815 enc->quality = g_value_get_float (value);
818 enc->bitrate = g_value_get_int (value);
821 enc->mode = g_value_get_enum (value);
824 enc->vbr = g_value_get_boolean (value);
827 enc->abr = g_value_get_int (value);
830 enc->vad = g_value_get_boolean (value);
833 enc->dtx = g_value_get_boolean (value);
835 case PROP_COMPLEXITY:
836 enc->complexity = g_value_get_int (value);
839 enc->nframes = g_value_get_int (value);
842 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);