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.
29 #include <speex_stereo.h>
31 #include <gst/gsttaginterface.h>
32 #include <gst/tag/tag.h>
33 #include "gstspeexenc.h"
35 GST_DEBUG_CATEGORY (speexenc_debug);
36 #define GST_CAT_DEFAULT speexenc_debug
38 static GstPadTemplate *gst_speexenc_src_template, *gst_speexenc_sink_template;
40 /* elementfactory information */
41 GstElementDetails speexenc_details = {
43 "Codec/Encoder/Audio",
44 "Encodes audio in Speex format",
45 "Wim Taymans <wim@fluendo.com>",
48 /* GstSpeexEnc signals and args */
55 #define DEFAULT_QUALITY 8.0
56 #define DEFAULT_BITRATE 0
57 #define DEFAULT_VBR FALSE
59 #define DEFAULT_VAD FALSE
60 #define DEFAULT_DTX FALSE
61 #define DEFAULT_COMPLEXITY 3
62 #define DEFAULT_NFRAMES 1
78 static const GstFormat *
79 gst_speexenc_get_formats (GstPad * pad)
81 static const GstFormat src_formats[] = {
86 static const GstFormat sink_formats[] = {
93 return (GST_PAD_IS_SRC (pad) ? src_formats : sink_formats);
96 static void gst_speexenc_base_init (gpointer g_class);
97 static void gst_speexenc_class_init (GstSpeexEncClass * klass);
98 static void gst_speexenc_init (GstSpeexEnc * speexenc);
100 static void gst_speexenc_chain (GstPad * pad, GstData * _data);
101 static gboolean gst_speexenc_setup (GstSpeexEnc * speexenc);
103 static void gst_speexenc_get_property (GObject * object, guint prop_id,
104 GValue * value, GParamSpec * pspec);
105 static void gst_speexenc_set_property (GObject * object, guint prop_id,
106 const GValue * value, GParamSpec * pspec);
107 static GstElementStateReturn gst_speexenc_change_state (GstElement * element);
109 static GstElementClass *parent_class = NULL;
111 /*static guint gst_speexenc_signals[LAST_SIGNAL] = { 0 }; */
114 gst_speexenc_get_type (void)
116 static GType speexenc_type = 0;
118 if (!speexenc_type) {
119 static const GTypeInfo speexenc_info = {
120 sizeof (GstSpeexEncClass),
121 gst_speexenc_base_init,
123 (GClassInitFunc) gst_speexenc_class_init,
126 sizeof (GstSpeexEnc),
128 (GInstanceInitFunc) gst_speexenc_init,
130 static const GInterfaceInfo tag_setter_info = {
137 g_type_register_static (GST_TYPE_ELEMENT, "GstSpeexEnc", &speexenc_info,
140 g_type_add_interface_static (speexenc_type, GST_TYPE_TAG_SETTER,
143 GST_DEBUG_CATEGORY_INIT (speexenc_debug, "speexenc", 0, "Speex encoder");
145 return speexenc_type;
149 speex_caps_factory (void)
151 return gst_caps_new_simple ("audio/x-speex", NULL);
155 raw_caps_factory (void)
158 gst_caps_new_simple ("audio/x-raw-int",
159 "rate", GST_TYPE_INT_RANGE, 6000, 48000,
160 "channels", GST_TYPE_INT_RANGE, 1, 2,
161 "endianness", G_TYPE_INT, G_BYTE_ORDER,
162 "signed", G_TYPE_BOOLEAN, TRUE,
163 "width", G_TYPE_INT, 16, "depth", G_TYPE_INT, 16, NULL);
167 gst_speexenc_base_init (gpointer g_class)
169 GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
170 GstCaps *raw_caps, *speex_caps;
172 raw_caps = raw_caps_factory ();
173 speex_caps = speex_caps_factory ();
175 gst_speexenc_sink_template = gst_pad_template_new ("sink", GST_PAD_SINK,
176 GST_PAD_ALWAYS, raw_caps);
177 gst_speexenc_src_template = gst_pad_template_new ("src", GST_PAD_SRC,
178 GST_PAD_ALWAYS, speex_caps);
179 gst_element_class_add_pad_template (element_class,
180 gst_speexenc_sink_template);
181 gst_element_class_add_pad_template (element_class, gst_speexenc_src_template);
182 gst_element_class_set_details (element_class, &speexenc_details);
186 gst_speexenc_class_init (GstSpeexEncClass * klass)
188 GObjectClass *gobject_class;
189 GstElementClass *gstelement_class;
191 gobject_class = (GObjectClass *) klass;
192 gstelement_class = (GstElementClass *) klass;
194 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_QUALITY,
195 g_param_spec_float ("quality", "Quality", "Encoding quality",
196 0.0, 10.0, DEFAULT_QUALITY, G_PARAM_READWRITE));
197 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_BITRATE,
198 g_param_spec_int ("bitrate", "Encoding Bit-rate",
199 "Specify an encoding bit-rate (in bps). ",
200 0, G_MAXINT, DEFAULT_BITRATE, G_PARAM_READWRITE));
201 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_VBR,
202 g_param_spec_boolean ("vbr", "VBR",
203 "Enable variable bit-rate", DEFAULT_VBR, G_PARAM_READWRITE));
204 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_ABR,
205 g_param_spec_int ("abr", "ABR",
206 "Enable average bit-rate (0 = disabled)",
207 0, G_MAXINT, DEFAULT_ABR, G_PARAM_READWRITE));
208 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_VAD,
209 g_param_spec_boolean ("vad", "VAD",
210 "Enable voice activity detection", DEFAULT_VAD, G_PARAM_READWRITE));
211 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_DTX,
212 g_param_spec_boolean ("dtx", "DTX",
213 "Enable discontinuous transmission", DEFAULT_DTX, G_PARAM_READWRITE));
214 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_COMPLEXITY,
215 g_param_spec_int ("complexity", "Complexity",
216 "Set encoding complexity",
217 0, G_MAXINT, DEFAULT_COMPLEXITY, G_PARAM_READWRITE));
218 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_NFRAMES,
219 g_param_spec_int ("nframes", "NFrames",
220 "Number of frames per buffer",
221 0, G_MAXINT, DEFAULT_NFRAMES, G_PARAM_READWRITE));
222 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_LAST_MESSAGE,
223 g_param_spec_string ("last-message", "last-message",
224 "The last status message", NULL, G_PARAM_READABLE));
226 parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
228 gobject_class->set_property = gst_speexenc_set_property;
229 gobject_class->get_property = gst_speexenc_get_property;
231 gstelement_class->change_state = gst_speexenc_change_state;
234 static GstPadLinkReturn
235 gst_speexenc_sinkconnect (GstPad * pad, const GstCaps * caps)
237 GstSpeexEnc *speexenc;
238 GstStructure *structure;
240 speexenc = GST_SPEEXENC (gst_pad_get_parent (pad));
241 speexenc->setup = FALSE;
243 structure = gst_caps_get_structure (caps, 0);
244 gst_structure_get_int (structure, "channels", &speexenc->channels);
245 gst_structure_get_int (structure, "rate", &speexenc->rate);
247 gst_speexenc_setup (speexenc);
250 return GST_PAD_LINK_OK;
252 return GST_PAD_LINK_REFUSED;
256 gst_speexenc_convert_src (GstPad * pad, GstFormat src_format, gint64 src_value,
257 GstFormat * dest_format, gint64 * dest_value)
260 GstSpeexEnc *speexenc;
263 speexenc = GST_SPEEXENC (gst_pad_get_parent (pad));
265 if (speexenc->samples_in == 0 ||
266 speexenc->bytes_out == 0 || speexenc->rate == 0)
269 avg = (speexenc->bytes_out * speexenc->rate) / (speexenc->samples_in);
271 switch (src_format) {
272 case GST_FORMAT_BYTES:
273 switch (*dest_format) {
274 case GST_FORMAT_TIME:
275 *dest_value = src_value * GST_SECOND / avg;
281 case GST_FORMAT_TIME:
282 switch (*dest_format) {
283 case GST_FORMAT_BYTES:
284 *dest_value = src_value * avg / GST_SECOND;
297 gst_speexenc_convert_sink (GstPad * pad, GstFormat src_format,
298 gint64 src_value, GstFormat * dest_format, gint64 * dest_value)
302 gint bytes_per_sample;
303 GstSpeexEnc *speexenc;
305 speexenc = GST_SPEEXENC (gst_pad_get_parent (pad));
307 bytes_per_sample = speexenc->channels * 2;
309 switch (src_format) {
310 case GST_FORMAT_BYTES:
311 switch (*dest_format) {
312 case GST_FORMAT_DEFAULT:
313 if (bytes_per_sample == 0)
315 *dest_value = src_value / bytes_per_sample;
317 case GST_FORMAT_TIME:
319 gint byterate = bytes_per_sample * speexenc->rate;
323 *dest_value = src_value * GST_SECOND / byterate;
330 case GST_FORMAT_DEFAULT:
331 switch (*dest_format) {
332 case GST_FORMAT_BYTES:
333 *dest_value = src_value * bytes_per_sample;
335 case GST_FORMAT_TIME:
336 if (speexenc->rate == 0)
338 *dest_value = src_value * GST_SECOND / speexenc->rate;
344 case GST_FORMAT_TIME:
345 switch (*dest_format) {
346 case GST_FORMAT_BYTES:
347 scale = bytes_per_sample;
349 case GST_FORMAT_DEFAULT:
350 *dest_value = src_value * scale * speexenc->rate / GST_SECOND;
362 static const GstQueryType *
363 gst_speexenc_get_query_types (GstPad * pad)
365 static const GstQueryType gst_speexenc_src_query_types[] = {
371 return gst_speexenc_src_query_types;
375 gst_speexenc_src_query (GstPad * pad, GstQueryType type,
376 GstFormat * format, gint64 * value)
379 GstSpeexEnc *speexenc;
381 speexenc = GST_SPEEXENC (gst_pad_get_parent (pad));
384 case GST_QUERY_TOTAL:
387 case GST_FORMAT_BYTES:
388 case GST_FORMAT_TIME:
391 const GstFormat *peer_formats;
395 peer_formats = gst_pad_get_formats (GST_PAD_PEER (speexenc->sinkpad));
397 while (peer_formats && *peer_formats && !res) {
399 GstFormat peer_format = *peer_formats;
402 if (gst_pad_query (GST_PAD_PEER (speexenc->sinkpad),
403 GST_QUERY_TOTAL, &peer_format, &peer_value)) {
404 GstFormat conv_format;
406 /* convert to TIME */
407 conv_format = GST_FORMAT_TIME;
408 res = gst_pad_convert (speexenc->sinkpad,
409 peer_format, peer_value, &conv_format, value);
410 /* and to final format */
411 res &= gst_pad_convert (pad,
412 GST_FORMAT_TIME, *value, format, value);
424 case GST_QUERY_POSITION:
428 /* we only know about our samples, convert to requested format */
429 res = gst_pad_convert (pad,
430 GST_FORMAT_BYTES, speexenc->bytes_out, format, value);
443 gst_speexenc_init (GstSpeexEnc * speexenc)
446 gst_pad_new_from_template (gst_speexenc_sink_template, "sink");
447 gst_element_add_pad (GST_ELEMENT (speexenc), speexenc->sinkpad);
448 gst_pad_set_chain_function (speexenc->sinkpad, gst_speexenc_chain);
449 gst_pad_set_link_function (speexenc->sinkpad, gst_speexenc_sinkconnect);
450 gst_pad_set_convert_function (speexenc->sinkpad,
451 GST_DEBUG_FUNCPTR (gst_speexenc_convert_sink));
452 gst_pad_set_formats_function (speexenc->sinkpad,
453 GST_DEBUG_FUNCPTR (gst_speexenc_get_formats));
456 gst_pad_new_from_template (gst_speexenc_src_template, "src");
457 gst_pad_set_query_function (speexenc->srcpad,
458 GST_DEBUG_FUNCPTR (gst_speexenc_src_query));
459 gst_pad_set_query_type_function (speexenc->srcpad,
460 GST_DEBUG_FUNCPTR (gst_speexenc_get_query_types));
461 gst_pad_set_convert_function (speexenc->srcpad,
462 GST_DEBUG_FUNCPTR (gst_speexenc_convert_src));
463 gst_pad_set_formats_function (speexenc->srcpad,
464 GST_DEBUG_FUNCPTR (gst_speexenc_get_formats));
465 gst_element_add_pad (GST_ELEMENT (speexenc), speexenc->srcpad);
467 speexenc->channels = -1;
470 speexenc->quality = DEFAULT_QUALITY;
471 speexenc->bitrate = DEFAULT_BITRATE;
472 speexenc->vbr = DEFAULT_VBR;
473 speexenc->abr = DEFAULT_ABR;
474 speexenc->vad = DEFAULT_VAD;
475 speexenc->dtx = DEFAULT_DTX;
476 speexenc->complexity = DEFAULT_COMPLEXITY;
477 speexenc->nframes = DEFAULT_NFRAMES;
479 speexenc->setup = FALSE;
480 speexenc->eos = FALSE;
481 speexenc->header_sent = FALSE;
483 speexenc->tags = gst_tag_list_new ();
484 speexenc->adapter = gst_adapter_new ();
486 /* we're chained and we can deal with events */
487 GST_FLAG_SET (speexenc, GST_ELEMENT_EVENT_AWARE);
492 gst_speexenc_get_tag_value (const GstTagList * list, const gchar * tag,
495 gchar *speexvalue = NULL;
501 /* get tag name right */
502 if ((strcmp (tag, GST_TAG_TRACK_NUMBER) == 0)
503 || (strcmp (tag, GST_TAG_ALBUM_VOLUME_NUMBER) == 0)
504 || (strcmp (tag, GST_TAG_TRACK_COUNT) == 0)
505 || (strcmp (tag, GST_TAG_ALBUM_VOLUME_COUNT) == 0)) {
508 if (!gst_tag_list_get_uint_index (list, tag, index, &track_no))
509 g_assert_not_reached ();
510 speexvalue = g_strdup_printf ("%u", track_no);
511 } else if (strcmp (tag, GST_TAG_DATE) == 0) {
512 /* FIXME: how are dates represented in speex files? */
516 if (!gst_tag_list_get_uint_index (list, tag, index, &u))
517 g_assert_not_reached ();
518 date = g_date_new_julian (u);
520 g_strdup_printf ("%04d-%02d-%02d", (gint) g_date_get_year (date),
521 (gint) g_date_get_month (date), (gint) g_date_get_day (date));
523 } else if (gst_tag_get_type (tag) == G_TYPE_STRING) {
524 if (!gst_tag_list_get_string_index (list, tag, index, &speexvalue))
525 g_assert_not_reached ();
532 * Comments will be stored in the Vorbis style.
533 * It is describled in the "Structure" section of
534 * http://www.xiph.org/ogg/vorbis/doc/v-comment.html
536 * The comment header is decoded as follows:
537 * 1) [vendor_length] = read an unsigned integer of 32 bits
538 * 2) [vendor_string] = read a UTF-8 vector as [vendor_length] octets
539 * 3) [user_comment_list_length] = read an unsigned integer of 32 bits
540 * 4) iterate [user_comment_list_length] times {
541 * 5) [length] = read an unsigned integer of 32 bits
542 * 6) this iteration's user comment = read a UTF-8 vector as [length] octets
544 * 7) [framing_bit] = read a single bit as boolean
545 * 8) if ( [framing_bit] unset or end of packet ) then ERROR
548 * If you have troubles, please write to ymnk@jcraft.com.
550 #define readint(buf, base) (((buf[base+3]<<24) & 0xff000000)| \
551 ((buf[base+2]<<16) & 0xff0000)| \
552 ((buf[base+1]<< 8) & 0xff00)| \
554 #define writeint(buf, base, val) do{ buf[base+3] = ((val)>>24) & 0xff; \
555 buf[base+2] = ((val)>>16) & 0xff; \
556 buf[base+1] = ((val)>> 8) & 0xff; \
557 buf[base ] = (val) & 0xff; \
561 comment_init (char **comments, int *length, char *vendor_string)
563 int vendor_length = strlen (vendor_string);
564 int user_comment_list_length = 0;
565 int len = 4 + vendor_length + 4;
566 char *p = (char *) malloc (len);
570 writeint (p, 0, vendor_length);
571 memcpy (p + 4, vendor_string, vendor_length);
572 writeint (p, 4 + vendor_length, user_comment_list_length);
577 comment_add (char **comments, int *length, const char *tag, char *val)
580 int vendor_length = readint (p, 0);
581 int user_comment_list_length = readint (p, 4 + vendor_length);
582 int tag_len = (tag ? strlen (tag) : 0);
583 int val_len = strlen (val);
584 int len = (*length) + 4 + tag_len + val_len;
586 p = (char *) realloc (p, len);
588 writeint (p, *length, tag_len + val_len); /* length of comment */
590 memcpy (p + *length + 4, tag, tag_len); /* comment */
591 memcpy (p + *length + 4 + tag_len, val, val_len); /* comment */
592 writeint (p, 4 + vendor_length, user_comment_list_length + 1);
602 gst_speexenc_metadata_set1 (const GstTagList * list, const gchar * tag,
605 const gchar *speextag = NULL;
606 gchar *speexvalue = NULL;
608 GstSpeexEnc *enc = GST_SPEEXENC (speexenc);
610 speextag = gst_tag_to_vorbis_tag (tag);
611 if (speextag == NULL) {
615 count = gst_tag_list_get_tag_size (list, tag);
616 for (i = 0; i < count; i++) {
617 speexvalue = gst_speexenc_get_tag_value (list, tag, i);
619 if (speexvalue != NULL) {
620 comment_add (&enc->comments, &enc->comment_len, speextag, speexvalue);
626 gst_speexenc_set_metadata (GstSpeexEnc * speexenc)
629 const GstTagList *user_tags;
631 user_tags = gst_tag_setter_get_list (GST_TAG_SETTER (speexenc));
632 if (!(speexenc->tags || user_tags))
635 comment_init (&speexenc->comments, &speexenc->comment_len,
636 "Encoded with GStreamer Speexenc");
638 gst_tag_list_merge (user_tags, speexenc->tags,
639 gst_tag_setter_get_merge_mode (GST_TAG_SETTER (speexenc)));
640 gst_tag_list_foreach (copy, gst_speexenc_metadata_set1, speexenc);
641 gst_tag_list_free (copy);
645 gst_speexenc_setup (GstSpeexEnc * speexenc)
647 speexenc->setup = FALSE;
649 switch (speexenc->mode) {
650 case GST_SPEEXENC_MODE_UWB:
651 speexenc->speex_mode = (SpeexMode *) & speex_uwb_mode;
653 case GST_SPEEXENC_MODE_WB:
654 speexenc->speex_mode = (SpeexMode *) & speex_wb_mode;
656 case GST_SPEEXENC_MODE_NB:
657 speexenc->speex_mode = (SpeexMode *) & speex_nb_mode;
659 case GST_SPEEXENC_MODE_AUTO:
664 if (speexenc->rate > 25000) {
665 if (speexenc->mode == GST_SPEEXENC_MODE_AUTO) {
666 speexenc->speex_mode = (SpeexMode *) & speex_uwb_mode;
668 if (speexenc->speex_mode != &speex_uwb_mode) {
669 speexenc->last_message =
671 ("Warning: suggest to use ultra wide band mode for this rate");
672 g_object_notify (G_OBJECT (speexenc), "last_message");
675 } else if (speexenc->rate > 12500) {
676 if (speexenc->mode == GST_SPEEXENC_MODE_AUTO) {
677 speexenc->speex_mode = (SpeexMode *) & speex_wb_mode;
679 if (speexenc->speex_mode != &speex_wb_mode) {
680 speexenc->last_message =
682 ("Warning: suggest to use wide band mode for this rate");
683 g_object_notify (G_OBJECT (speexenc), "last_message");
687 if (speexenc->mode == GST_SPEEXENC_MODE_AUTO) {
688 speexenc->speex_mode = (SpeexMode *) & speex_nb_mode;
690 if (speexenc->speex_mode != &speex_nb_mode) {
691 speexenc->last_message =
693 ("Warning: suggest to use narrow band mode for this rate");
694 g_object_notify (G_OBJECT (speexenc), "last_message");
699 if (speexenc->rate != 8000 && speexenc->rate != 16000
700 && speexenc->rate != 32000) {
701 speexenc->last_message =
702 g_strdup_printf ("Warning: speex is optimized for 8, 16 and 32 KHz");
703 g_object_notify (G_OBJECT (speexenc), "last_message");
706 speex_init_header (&speexenc->header, speexenc->rate, 1,
707 speexenc->speex_mode);
708 speexenc->header.frames_per_packet = speexenc->nframes;
709 speexenc->header.vbr = speexenc->vbr;
710 speexenc->header.nb_channels = speexenc->channels;
712 /*Initialize Speex encoder */
713 speexenc->state = speex_encoder_init (speexenc->speex_mode);
715 speex_encoder_ctl (speexenc->state, SPEEX_GET_FRAME_SIZE,
716 &speexenc->frame_size);
717 speex_encoder_ctl (speexenc->state, SPEEX_SET_COMPLEXITY,
718 &speexenc->complexity);
719 speex_encoder_ctl (speexenc->state, SPEEX_SET_SAMPLING_RATE, &speexenc->rate);
722 speex_encoder_ctl (speexenc->state, SPEEX_SET_VBR_QUALITY,
725 gint tmp = floor (speexenc->quality);
727 speex_encoder_ctl (speexenc->state, SPEEX_SET_QUALITY, &tmp);
729 if (speexenc->bitrate) {
730 if (speexenc->quality >= 0.0 && speexenc->vbr) {
731 speexenc->last_message =
732 g_strdup_printf ("Warning: bitrate option is overriding quality");
733 g_object_notify (G_OBJECT (speexenc), "last_message");
735 speex_encoder_ctl (speexenc->state, SPEEX_SET_BITRATE, &speexenc->bitrate);
740 speex_encoder_ctl (speexenc->state, SPEEX_SET_VBR, &tmp);
741 } else if (speexenc->vad) {
744 speex_encoder_ctl (speexenc->state, SPEEX_SET_VAD, &tmp);
750 speex_encoder_ctl (speexenc->state, SPEEX_SET_DTX, &tmp);
753 if (speexenc->dtx && !(speexenc->vbr || speexenc->abr || speexenc->vad)) {
754 speexenc->last_message =
755 g_strdup_printf ("Warning: dtx is useless without vad, vbr or abr");
756 g_object_notify (G_OBJECT (speexenc), "last_message");
757 } else if ((speexenc->vbr || speexenc->abr) && (speexenc->vad)) {
758 speexenc->last_message =
759 g_strdup_printf ("Warning: vad is already implied by vbr or abr");
760 g_object_notify (G_OBJECT (speexenc), "last_message");
764 speex_encoder_ctl (speexenc->state, SPEEX_SET_ABR, &speexenc->abr);
767 speex_encoder_ctl (speexenc->state, SPEEX_GET_LOOKAHEAD,
768 &speexenc->lookahead);
770 speexenc->setup = TRUE;
775 /* prepare a buffer for transmission */
777 gst_speexenc_buffer_from_data (GstSpeexEnc * speexenc, guchar * data,
778 gint data_len, guint64 granulepos)
782 outbuf = gst_buffer_new_and_alloc (data_len);
783 memcpy (GST_BUFFER_DATA (outbuf), data, data_len);
784 GST_BUFFER_OFFSET (outbuf) = speexenc->bytes_out;
785 GST_BUFFER_OFFSET_END (outbuf) = granulepos;
787 GST_DEBUG ("encoded buffer of %d bytes", GST_BUFFER_SIZE (outbuf));
791 /* push out the buffer and do internal bookkeeping */
793 gst_speexenc_push_buffer (GstSpeexEnc * speexenc, GstBuffer * buffer)
795 speexenc->bytes_out += GST_BUFFER_SIZE (buffer);
797 if (GST_PAD_IS_USABLE (speexenc->srcpad)) {
798 gst_pad_push (speexenc->srcpad, GST_DATA (buffer));
800 gst_buffer_unref (buffer);
805 gst_speexenc_set_header_on_caps (GstCaps * caps, GstBuffer * buf1,
808 GstStructure *structure = gst_caps_get_structure (caps, 0);
810 GValue value = { 0 };
813 GST_BUFFER_FLAG_SET (buf1, GST_BUFFER_IN_CAPS);
814 GST_BUFFER_FLAG_SET (buf2, GST_BUFFER_IN_CAPS);
816 /* put buffers in a fixed list */
817 g_value_init (&list, GST_TYPE_FIXED_LIST);
818 g_value_init (&value, GST_TYPE_BUFFER);
819 g_value_set_boxed (&value, buf1);
820 gst_value_list_append_value (&list, &value);
821 g_value_unset (&value);
822 g_value_init (&value, GST_TYPE_BUFFER);
823 g_value_set_boxed (&value, buf2);
824 gst_value_list_append_value (&list, &value);
825 gst_structure_set_value (structure, "streamheader", &list);
826 g_value_unset (&value);
827 g_value_unset (&list);
831 gst_speexenc_chain (GstPad * pad, GstData * _data)
833 GstBuffer *buf = GST_BUFFER (_data);
834 GstSpeexEnc *speexenc;
836 g_return_if_fail (pad != NULL);
837 g_return_if_fail (GST_IS_PAD (pad));
838 g_return_if_fail (buf != NULL);
840 speexenc = GST_SPEEXENC (gst_pad_get_parent (pad));
842 if (GST_IS_EVENT (buf)) {
843 GstEvent *event = GST_EVENT (buf);
845 switch (GST_EVENT_TYPE (event)) {
847 speexenc->eos = TRUE;
848 gst_event_unref (event);
851 if (speexenc->tags) {
852 gst_tag_list_insert (speexenc->tags, gst_event_tag_get_list (event),
853 gst_tag_setter_get_merge_mode (GST_TAG_SETTER (speexenc)));
855 g_assert_not_reached ();
857 gst_pad_event_default (pad, event);
860 gst_pad_event_default (pad, event);
864 if (!speexenc->setup) {
865 gst_buffer_unref (buf);
866 GST_ELEMENT_ERROR (speexenc, CORE, NEGOTIATION, (NULL),
867 ("encoder not initialized (input is not audio?)"));
871 if (!speexenc->header_sent) {
872 /* Speex streams begin with two headers; the initial header (with
873 most of the codec setup parameters) which is mandated by the Ogg
874 bitstream spec. The second header holds any comment fields.
875 We merely need to make the headers, then pass them to libspeex
876 one at a time; libspeex handles the additional Ogg bitstream
878 GstBuffer *buf1, *buf2;
883 gst_speexenc_set_metadata (speexenc);
885 /* create header buffer */
886 data = speex_header_to_packet (&speexenc->header, &data_len);
887 buf1 = gst_speexenc_buffer_from_data (speexenc, data, data_len, 0);
889 /* create comment buffer */
891 gst_speexenc_buffer_from_data (speexenc, speexenc->comments,
892 speexenc->comment_len, 0);
894 /* mark and put on caps */
895 caps = gst_pad_get_caps (speexenc->srcpad);
896 gst_speexenc_set_header_on_caps (caps, buf1, buf2);
898 /* negotiate with these caps */
899 GST_DEBUG ("here are the caps: %" GST_PTR_FORMAT, caps);
900 gst_pad_try_set_caps (speexenc->srcpad, caps);
902 /* push out buffers */
903 gst_speexenc_push_buffer (speexenc, buf1);
904 gst_speexenc_push_buffer (speexenc, buf2);
906 speex_bits_init (&speexenc->bits);
907 speex_bits_reset (&speexenc->bits);
909 speexenc->header_sent = TRUE;
913 gint frame_size = speexenc->frame_size;
914 gint bytes = frame_size * 2 * speexenc->channels;
916 /* push buffer to adapter */
917 gst_adapter_push (speexenc->adapter, buf);
919 while (gst_adapter_available (speexenc->adapter) >= bytes) {
922 gint outsize, written;
925 data = (gint16 *) gst_adapter_peek (speexenc->adapter, bytes);
927 for (i = 0; i < frame_size * speexenc->channels; i++) {
928 speexenc->input[i] = (gfloat) data[i];
930 gst_adapter_flush (speexenc->adapter, bytes);
932 speexenc->samples_in += frame_size;
934 if (speexenc->channels == 2) {
935 speex_encode_stereo (speexenc->input, frame_size, &speexenc->bits);
937 speex_encode (speexenc->state, speexenc->input, &speexenc->bits);
941 if ((speexenc->frameno % speexenc->nframes) != 0)
944 speex_bits_insert_terminator (&speexenc->bits);
945 outsize = speex_bits_nbytes (&speexenc->bits);
947 gst_pad_alloc_buffer (speexenc->srcpad, GST_BUFFER_OFFSET_NONE,
950 speex_bits_write (&speexenc->bits, GST_BUFFER_DATA (outbuf),
952 g_assert (written == outsize);
953 speex_bits_reset (&speexenc->bits);
955 GST_BUFFER_OFFSET (outbuf) = speexenc->bytes_out;
956 GST_BUFFER_OFFSET_END (outbuf) =
957 speexenc->frameno * frame_size - speexenc->lookahead;
959 gst_speexenc_push_buffer (speexenc, outbuf);
965 /* clean up and exit. */
966 gst_pad_push (speexenc->srcpad, GST_DATA (gst_event_new (GST_EVENT_EOS)));
967 gst_element_set_eos (GST_ELEMENT (speexenc));
972 gst_speexenc_get_property (GObject * object, guint prop_id, GValue * value,
975 GstSpeexEnc *speexenc;
977 /* it's not null if we got it, but it might not be ours */
978 g_return_if_fail (GST_IS_SPEEXENC (object));
980 speexenc = GST_SPEEXENC (object);
984 g_value_set_float (value, speexenc->quality);
987 g_value_set_int (value, speexenc->bitrate);
990 g_value_set_boolean (value, speexenc->vbr);
993 g_value_set_int (value, speexenc->abr);
996 g_value_set_boolean (value, speexenc->vad);
999 g_value_set_boolean (value, speexenc->dtx);
1001 case ARG_COMPLEXITY:
1002 g_value_set_int (value, speexenc->complexity);
1005 g_value_set_int (value, speexenc->nframes);
1007 case ARG_LAST_MESSAGE:
1008 g_value_set_string (value, speexenc->last_message);
1011 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1017 gst_speexenc_set_property (GObject * object, guint prop_id,
1018 const GValue * value, GParamSpec * pspec)
1020 GstSpeexEnc *speexenc;
1022 /* it's not null if we got it, but it might not be ours */
1023 g_return_if_fail (GST_IS_SPEEXENC (object));
1025 speexenc = GST_SPEEXENC (object);
1029 speexenc->quality = g_value_get_float (value);
1032 speexenc->bitrate = g_value_get_int (value);
1035 speexenc->vbr = g_value_get_boolean (value);
1038 speexenc->abr = g_value_get_int (value);
1041 speexenc->vad = g_value_get_boolean (value);
1044 speexenc->dtx = g_value_get_boolean (value);
1046 case ARG_COMPLEXITY:
1047 speexenc->complexity = g_value_get_int (value);
1050 speexenc->nframes = g_value_get_int (value);
1053 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1058 static GstElementStateReturn
1059 gst_speexenc_change_state (GstElement * element)
1061 GstSpeexEnc *speexenc = GST_SPEEXENC (element);
1063 switch (GST_STATE_TRANSITION (element)) {
1064 case GST_STATE_NULL_TO_READY:
1066 case GST_STATE_READY_TO_PAUSED:
1067 speexenc->eos = FALSE;
1068 speexenc->frameno = 0;
1069 speexenc->samples_in = 0;
1071 case GST_STATE_PAUSED_TO_PLAYING:
1072 case GST_STATE_PLAYING_TO_PAUSED:
1074 case GST_STATE_PAUSED_TO_READY:
1075 speexenc->setup = FALSE;
1076 speexenc->header_sent = FALSE;
1077 gst_tag_list_free (speexenc->tags);
1078 speexenc->tags = gst_tag_list_new ();
1080 case GST_STATE_READY_TO_NULL:
1085 if (GST_ELEMENT_CLASS (parent_class)->change_state)
1086 return GST_ELEMENT_CLASS (parent_class)->change_state (element);
1088 return GST_STATE_SUCCESS;