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.
28 #include <speex/speex.h>
29 #include <speex/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 GstStateChangeReturn gst_speexenc_change_state (GstElement * element,
108 GstStateChange transition);
110 static GstElementClass *parent_class = NULL;
112 /*static guint gst_speexenc_signals[LAST_SIGNAL] = { 0 }; */
115 gst_speexenc_get_type (void)
117 static GType speexenc_type = 0;
119 if (!speexenc_type) {
120 static const GTypeInfo speexenc_info = {
121 sizeof (GstSpeexEncClass),
122 gst_speexenc_base_init,
124 (GClassInitFunc) gst_speexenc_class_init,
127 sizeof (GstSpeexEnc),
129 (GInstanceInitFunc) gst_speexenc_init,
131 static const GInterfaceInfo tag_setter_info = {
138 g_type_register_static (GST_TYPE_ELEMENT, "GstSpeexEnc", &speexenc_info,
141 g_type_add_interface_static (speexenc_type, GST_TYPE_TAG_SETTER,
144 GST_DEBUG_CATEGORY_INIT (speexenc_debug, "speexenc", 0, "Speex encoder");
146 return speexenc_type;
150 speex_caps_factory (void)
152 return gst_caps_new_simple ("audio/x-speex", NULL);
156 raw_caps_factory (void)
159 gst_caps_new_simple ("audio/x-raw-int",
160 "rate", GST_TYPE_INT_RANGE, 6000, 48000,
161 "channels", GST_TYPE_INT_RANGE, 1, 2,
162 "endianness", G_TYPE_INT, G_BYTE_ORDER,
163 "signed", G_TYPE_BOOLEAN, TRUE,
164 "width", G_TYPE_INT, 16, "depth", G_TYPE_INT, 16, NULL);
168 gst_speexenc_base_init (gpointer g_class)
170 GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
171 GstCaps *raw_caps, *speex_caps;
173 raw_caps = raw_caps_factory ();
174 speex_caps = speex_caps_factory ();
176 gst_speexenc_sink_template = gst_pad_template_new ("sink", GST_PAD_SINK,
177 GST_PAD_ALWAYS, raw_caps);
178 gst_speexenc_src_template = gst_pad_template_new ("src", GST_PAD_SRC,
179 GST_PAD_ALWAYS, speex_caps);
180 gst_element_class_add_pad_template (element_class,
181 gst_speexenc_sink_template);
182 gst_element_class_add_pad_template (element_class, gst_speexenc_src_template);
183 gst_element_class_set_details (element_class, &speexenc_details);
187 gst_speexenc_class_init (GstSpeexEncClass * klass)
189 GObjectClass *gobject_class;
190 GstElementClass *gstelement_class;
192 gobject_class = (GObjectClass *) klass;
193 gstelement_class = (GstElementClass *) klass;
195 gobject_class->set_property = gst_speexenc_set_property;
196 gobject_class->get_property = gst_speexenc_get_property;
198 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_QUALITY,
199 g_param_spec_float ("quality", "Quality", "Encoding quality",
200 0.0, 10.0, DEFAULT_QUALITY, G_PARAM_READWRITE));
201 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_BITRATE,
202 g_param_spec_int ("bitrate", "Encoding Bit-rate",
203 "Specify an encoding bit-rate (in bps). (0 = automatic)",
204 0, G_MAXINT, DEFAULT_BITRATE, G_PARAM_READWRITE));
205 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_VBR,
206 g_param_spec_boolean ("vbr", "VBR",
207 "Enable variable bit-rate", DEFAULT_VBR, G_PARAM_READWRITE));
208 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_ABR,
209 g_param_spec_int ("abr", "ABR",
210 "Enable average bit-rate (0 = disabled)",
211 0, G_MAXINT, DEFAULT_ABR, G_PARAM_READWRITE));
212 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_VAD,
213 g_param_spec_boolean ("vad", "VAD",
214 "Enable voice activity detection", DEFAULT_VAD, G_PARAM_READWRITE));
215 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_DTX,
216 g_param_spec_boolean ("dtx", "DTX",
217 "Enable discontinuous transmission", DEFAULT_DTX, G_PARAM_READWRITE));
218 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_COMPLEXITY,
219 g_param_spec_int ("complexity", "Complexity",
220 "Set encoding complexity",
221 0, G_MAXINT, DEFAULT_COMPLEXITY, G_PARAM_READWRITE));
222 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_NFRAMES,
223 g_param_spec_int ("nframes", "NFrames",
224 "Number of frames per buffer",
225 0, G_MAXINT, DEFAULT_NFRAMES, G_PARAM_READWRITE));
226 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_LAST_MESSAGE,
227 g_param_spec_string ("last-message", "last-message",
228 "The last status message", NULL, G_PARAM_READABLE));
230 parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
232 gstelement_class->change_state = gst_speexenc_change_state;
235 static GstPadLinkReturn
236 gst_speexenc_sinkconnect (GstPad * pad, const GstCaps * caps)
238 GstSpeexEnc *speexenc;
239 GstStructure *structure;
241 speexenc = GST_SPEEXENC (gst_pad_get_parent (pad));
242 speexenc->setup = FALSE;
244 structure = gst_caps_get_structure (caps, 0);
245 gst_structure_get_int (structure, "channels", &speexenc->channels);
246 gst_structure_get_int (structure, "rate", &speexenc->rate);
248 gst_speexenc_setup (speexenc);
251 return GST_PAD_LINK_OK;
253 return GST_PAD_LINK_REFUSED;
257 gst_speexenc_convert_src (GstPad * pad, GstFormat src_format, gint64 src_value,
258 GstFormat * dest_format, gint64 * dest_value)
261 GstSpeexEnc *speexenc;
264 speexenc = GST_SPEEXENC (gst_pad_get_parent (pad));
266 if (speexenc->samples_in == 0 ||
267 speexenc->bytes_out == 0 || speexenc->rate == 0)
270 avg = (speexenc->bytes_out * speexenc->rate) / (speexenc->samples_in);
272 switch (src_format) {
273 case GST_FORMAT_BYTES:
274 switch (*dest_format) {
275 case GST_FORMAT_TIME:
276 *dest_value = src_value * GST_SECOND / avg;
282 case GST_FORMAT_TIME:
283 switch (*dest_format) {
284 case GST_FORMAT_BYTES:
285 *dest_value = src_value * avg / GST_SECOND;
298 gst_speexenc_convert_sink (GstPad * pad, GstFormat src_format,
299 gint64 src_value, GstFormat * dest_format, gint64 * dest_value)
303 gint bytes_per_sample;
304 GstSpeexEnc *speexenc;
306 speexenc = GST_SPEEXENC (gst_pad_get_parent (pad));
308 bytes_per_sample = speexenc->channels * 2;
310 switch (src_format) {
311 case GST_FORMAT_BYTES:
312 switch (*dest_format) {
313 case GST_FORMAT_DEFAULT:
314 if (bytes_per_sample == 0)
316 *dest_value = src_value / bytes_per_sample;
318 case GST_FORMAT_TIME:
320 gint byterate = bytes_per_sample * speexenc->rate;
324 *dest_value = src_value * GST_SECOND / byterate;
331 case GST_FORMAT_DEFAULT:
332 switch (*dest_format) {
333 case GST_FORMAT_BYTES:
334 *dest_value = src_value * bytes_per_sample;
336 case GST_FORMAT_TIME:
337 if (speexenc->rate == 0)
339 *dest_value = src_value * GST_SECOND / speexenc->rate;
345 case GST_FORMAT_TIME:
346 switch (*dest_format) {
347 case GST_FORMAT_BYTES:
348 scale = bytes_per_sample;
350 case GST_FORMAT_DEFAULT:
351 *dest_value = src_value * scale * speexenc->rate / GST_SECOND;
363 static const GstQueryType *
364 gst_speexenc_get_query_types (GstPad * pad)
366 static const GstQueryType gst_speexenc_src_query_types[] = {
372 return gst_speexenc_src_query_types;
376 gst_speexenc_src_query (GstPad * pad, GstQueryType type,
377 GstFormat * format, gint64 * value)
380 GstSpeexEnc *speexenc;
382 speexenc = GST_SPEEXENC (gst_pad_get_parent (pad));
385 case GST_QUERY_TOTAL:
388 case GST_FORMAT_BYTES:
389 case GST_FORMAT_TIME:
392 const GstFormat *peer_formats;
396 peer_formats = gst_pad_get_formats (GST_PAD_PEER (speexenc->sinkpad));
398 while (peer_formats && *peer_formats && !res) {
400 GstFormat peer_format = *peer_formats;
403 if (gst_pad_query (GST_PAD_PEER (speexenc->sinkpad),
404 GST_QUERY_TOTAL, &peer_format, &peer_value)) {
405 GstFormat conv_format;
407 /* convert to TIME */
408 conv_format = GST_FORMAT_TIME;
409 res = gst_pad_convert (speexenc->sinkpad,
410 peer_format, peer_value, &conv_format, value);
411 /* and to final format */
412 res &= gst_pad_convert (pad,
413 GST_FORMAT_TIME, *value, format, value);
425 case GST_QUERY_POSITION:
429 /* we only know about our samples, convert to requested format */
430 res = gst_pad_convert (pad,
431 GST_FORMAT_BYTES, speexenc->bytes_out, format, value);
444 gst_speexenc_init (GstSpeexEnc * speexenc)
447 gst_pad_new_from_template (gst_speexenc_sink_template, "sink");
448 gst_element_add_pad (GST_ELEMENT (speexenc), speexenc->sinkpad);
449 gst_pad_set_chain_function (speexenc->sinkpad, gst_speexenc_chain);
450 gst_pad_set_link_function (speexenc->sinkpad, gst_speexenc_sinkconnect);
451 gst_pad_set_convert_function (speexenc->sinkpad,
452 GST_DEBUG_FUNCPTR (gst_speexenc_convert_sink));
453 gst_pad_set_formats_function (speexenc->sinkpad,
454 GST_DEBUG_FUNCPTR (gst_speexenc_get_formats));
457 gst_pad_new_from_template (gst_speexenc_src_template, "src");
458 gst_pad_set_query_function (speexenc->srcpad,
459 GST_DEBUG_FUNCPTR (gst_speexenc_src_query));
460 gst_pad_set_query_type_function (speexenc->srcpad,
461 GST_DEBUG_FUNCPTR (gst_speexenc_get_query_types));
462 gst_pad_set_convert_function (speexenc->srcpad,
463 GST_DEBUG_FUNCPTR (gst_speexenc_convert_src));
464 gst_pad_set_formats_function (speexenc->srcpad,
465 GST_DEBUG_FUNCPTR (gst_speexenc_get_formats));
466 gst_element_add_pad (GST_ELEMENT (speexenc), speexenc->srcpad);
468 speexenc->channels = -1;
471 speexenc->quality = DEFAULT_QUALITY;
472 speexenc->bitrate = DEFAULT_BITRATE;
473 speexenc->vbr = DEFAULT_VBR;
474 speexenc->abr = DEFAULT_ABR;
475 speexenc->vad = DEFAULT_VAD;
476 speexenc->dtx = DEFAULT_DTX;
477 speexenc->complexity = DEFAULT_COMPLEXITY;
478 speexenc->nframes = DEFAULT_NFRAMES;
480 speexenc->setup = FALSE;
481 speexenc->eos = FALSE;
482 speexenc->header_sent = FALSE;
484 speexenc->tags = gst_tag_list_new ();
485 speexenc->adapter = gst_adapter_new ();
487 /* we're chained and we can deal with events */
488 GST_FLAG_SET (speexenc, GST_ELEMENT_EVENT_AWARE);
493 gst_speexenc_get_tag_value (const GstTagList * list, const gchar * tag,
496 gchar *speexvalue = NULL;
502 /* get tag name right */
503 if ((strcmp (tag, GST_TAG_TRACK_NUMBER) == 0)
504 || (strcmp (tag, GST_TAG_ALBUM_VOLUME_NUMBER) == 0)
505 || (strcmp (tag, GST_TAG_TRACK_COUNT) == 0)
506 || (strcmp (tag, GST_TAG_ALBUM_VOLUME_COUNT) == 0)) {
509 if (!gst_tag_list_get_uint_index (list, tag, index, &track_no))
510 g_assert_not_reached ();
511 speexvalue = g_strdup_printf ("%u", track_no);
512 } else if (strcmp (tag, GST_TAG_DATE) == 0) {
513 /* FIXME: how are dates represented in speex files? */
517 if (!gst_tag_list_get_uint_index (list, tag, index, &u))
518 g_assert_not_reached ();
519 date = g_date_new_julian (u);
521 g_strdup_printf ("%04d-%02d-%02d", (gint) g_date_get_year (date),
522 (gint) g_date_get_month (date), (gint) g_date_get_day (date));
524 } else if (gst_tag_get_type (tag) == G_TYPE_STRING) {
525 if (!gst_tag_list_get_string_index (list, tag, index, &speexvalue))
526 g_assert_not_reached ();
533 * Comments will be stored in the Vorbis style.
534 * It is describled in the "Structure" section of
535 * http://www.xiph.org/ogg/vorbis/doc/v-comment.html
537 * The comment header is decoded as follows:
538 * 1) [vendor_length] = read an unsigned integer of 32 bits
539 * 2) [vendor_string] = read a UTF-8 vector as [vendor_length] octets
540 * 3) [user_comment_list_length] = read an unsigned integer of 32 bits
541 * 4) iterate [user_comment_list_length] times {
542 * 5) [length] = read an unsigned integer of 32 bits
543 * 6) this iteration's user comment = read a UTF-8 vector as [length] octets
545 * 7) [framing_bit] = read a single bit as boolean
546 * 8) if ( [framing_bit] unset or end of packet ) then ERROR
549 * If you have troubles, please write to ymnk@jcraft.com.
551 #define readint(buf, base) (((buf[base+3]<<24) & 0xff000000)| \
552 ((buf[base+2]<<16) & 0xff0000)| \
553 ((buf[base+1]<< 8) & 0xff00)| \
555 #define writeint(buf, base, val) do{ buf[base+3] = ((val)>>24) & 0xff; \
556 buf[base+2] = ((val)>>16) & 0xff; \
557 buf[base+1] = ((val)>> 8) & 0xff; \
558 buf[base ] = (val) & 0xff; \
562 comment_init (char **comments, int *length, char *vendor_string)
564 int vendor_length = strlen (vendor_string);
565 int user_comment_list_length = 0;
566 int len = 4 + vendor_length + 4;
567 char *p = (char *) malloc (len);
571 writeint (p, 0, vendor_length);
572 memcpy (p + 4, vendor_string, vendor_length);
573 writeint (p, 4 + vendor_length, user_comment_list_length);
578 comment_add (char **comments, int *length, const char *tag, char *val)
581 int vendor_length = readint (p, 0);
582 int user_comment_list_length = readint (p, 4 + vendor_length);
583 int tag_len = (tag ? strlen (tag) : 0);
584 int val_len = strlen (val);
585 int len = (*length) + 4 + tag_len + val_len;
587 p = (char *) realloc (p, len);
589 writeint (p, *length, tag_len + val_len); /* length of comment */
591 memcpy (p + *length + 4, tag, tag_len); /* comment */
592 memcpy (p + *length + 4 + tag_len, val, val_len); /* comment */
593 writeint (p, 4 + vendor_length, user_comment_list_length + 1);
603 gst_speexenc_metadata_set1 (const GstTagList * list, const gchar * tag,
606 const gchar *speextag = NULL;
607 gchar *speexvalue = NULL;
609 GstSpeexEnc *enc = GST_SPEEXENC (speexenc);
611 speextag = gst_tag_to_vorbis_tag (tag);
612 if (speextag == NULL) {
616 count = gst_tag_list_get_tag_size (list, tag);
617 for (i = 0; i < count; i++) {
618 speexvalue = gst_speexenc_get_tag_value (list, tag, i);
620 if (speexvalue != NULL) {
621 comment_add (&enc->comments, &enc->comment_len, speextag, speexvalue);
627 gst_speexenc_set_metadata (GstSpeexEnc * speexenc)
630 const GstTagList *user_tags;
632 user_tags = gst_tag_setter_get_list (GST_TAG_SETTER (speexenc));
633 if (!(speexenc->tags || user_tags))
636 comment_init (&speexenc->comments, &speexenc->comment_len,
637 "Encoded with GStreamer Speexenc");
639 gst_tag_list_merge (user_tags, speexenc->tags,
640 gst_tag_setter_get_merge_mode (GST_TAG_SETTER (speexenc)));
641 gst_tag_list_foreach (copy, gst_speexenc_metadata_set1, speexenc);
642 gst_tag_list_free (copy);
646 gst_speexenc_setup (GstSpeexEnc * speexenc)
648 speexenc->setup = FALSE;
650 switch (speexenc->mode) {
651 case GST_SPEEXENC_MODE_UWB:
652 speexenc->speex_mode = (SpeexMode *) & speex_uwb_mode;
654 case GST_SPEEXENC_MODE_WB:
655 speexenc->speex_mode = (SpeexMode *) & speex_wb_mode;
657 case GST_SPEEXENC_MODE_NB:
658 speexenc->speex_mode = (SpeexMode *) & speex_nb_mode;
660 case GST_SPEEXENC_MODE_AUTO:
665 if (speexenc->rate > 25000) {
666 if (speexenc->mode == GST_SPEEXENC_MODE_AUTO) {
667 speexenc->speex_mode = (SpeexMode *) & speex_uwb_mode;
669 if (speexenc->speex_mode != &speex_uwb_mode) {
670 speexenc->last_message =
672 ("Warning: suggest to use ultra wide band mode for this rate");
673 g_object_notify (G_OBJECT (speexenc), "last_message");
676 } else if (speexenc->rate > 12500) {
677 if (speexenc->mode == GST_SPEEXENC_MODE_AUTO) {
678 speexenc->speex_mode = (SpeexMode *) & speex_wb_mode;
680 if (speexenc->speex_mode != &speex_wb_mode) {
681 speexenc->last_message =
683 ("Warning: suggest to use wide band mode for this rate");
684 g_object_notify (G_OBJECT (speexenc), "last_message");
688 if (speexenc->mode == GST_SPEEXENC_MODE_AUTO) {
689 speexenc->speex_mode = (SpeexMode *) & speex_nb_mode;
691 if (speexenc->speex_mode != &speex_nb_mode) {
692 speexenc->last_message =
694 ("Warning: suggest to use narrow band mode for this rate");
695 g_object_notify (G_OBJECT (speexenc), "last_message");
700 if (speexenc->rate != 8000 && speexenc->rate != 16000
701 && speexenc->rate != 32000) {
702 speexenc->last_message =
703 g_strdup_printf ("Warning: speex is optimized for 8, 16 and 32 KHz");
704 g_object_notify (G_OBJECT (speexenc), "last_message");
707 speex_init_header (&speexenc->header, speexenc->rate, 1,
708 speexenc->speex_mode);
709 speexenc->header.frames_per_packet = speexenc->nframes;
710 speexenc->header.vbr = speexenc->vbr;
711 speexenc->header.nb_channels = speexenc->channels;
713 /*Initialize Speex encoder */
714 speexenc->state = speex_encoder_init (speexenc->speex_mode);
716 speex_encoder_ctl (speexenc->state, SPEEX_GET_FRAME_SIZE,
717 &speexenc->frame_size);
718 speex_encoder_ctl (speexenc->state, SPEEX_SET_COMPLEXITY,
719 &speexenc->complexity);
720 speex_encoder_ctl (speexenc->state, SPEEX_SET_SAMPLING_RATE, &speexenc->rate);
723 speex_encoder_ctl (speexenc->state, SPEEX_SET_VBR_QUALITY,
726 gint tmp = floor (speexenc->quality);
728 speex_encoder_ctl (speexenc->state, SPEEX_SET_QUALITY, &tmp);
730 if (speexenc->bitrate) {
731 if (speexenc->quality >= 0.0 && speexenc->vbr) {
732 speexenc->last_message =
733 g_strdup_printf ("Warning: bitrate option is overriding quality");
734 g_object_notify (G_OBJECT (speexenc), "last_message");
736 speex_encoder_ctl (speexenc->state, SPEEX_SET_BITRATE, &speexenc->bitrate);
741 speex_encoder_ctl (speexenc->state, SPEEX_SET_VBR, &tmp);
742 } else if (speexenc->vad) {
745 speex_encoder_ctl (speexenc->state, SPEEX_SET_VAD, &tmp);
751 speex_encoder_ctl (speexenc->state, SPEEX_SET_DTX, &tmp);
754 if (speexenc->dtx && !(speexenc->vbr || speexenc->abr || speexenc->vad)) {
755 speexenc->last_message =
756 g_strdup_printf ("Warning: dtx is useless without vad, vbr or abr");
757 g_object_notify (G_OBJECT (speexenc), "last_message");
758 } else if ((speexenc->vbr || speexenc->abr) && (speexenc->vad)) {
759 speexenc->last_message =
760 g_strdup_printf ("Warning: vad is already implied by vbr or abr");
761 g_object_notify (G_OBJECT (speexenc), "last_message");
765 speex_encoder_ctl (speexenc->state, SPEEX_SET_ABR, &speexenc->abr);
768 speex_encoder_ctl (speexenc->state, SPEEX_GET_LOOKAHEAD,
769 &speexenc->lookahead);
771 speexenc->setup = TRUE;
776 /* prepare a buffer for transmission */
778 gst_speexenc_buffer_from_data (GstSpeexEnc * speexenc, guchar * data,
779 gint data_len, guint64 granulepos)
783 outbuf = gst_buffer_new_and_alloc (data_len);
784 memcpy (GST_BUFFER_DATA (outbuf), data, data_len);
785 GST_BUFFER_OFFSET (outbuf) = speexenc->bytes_out;
786 GST_BUFFER_OFFSET_END (outbuf) = granulepos;
788 GST_DEBUG ("encoded buffer of %d bytes", GST_BUFFER_SIZE (outbuf));
792 /* push out the buffer and do internal bookkeeping */
794 gst_speexenc_push_buffer (GstSpeexEnc * speexenc, GstBuffer * buffer)
796 speexenc->bytes_out += GST_BUFFER_SIZE (buffer);
798 if (GST_PAD_IS_USABLE (speexenc->srcpad)) {
799 gst_pad_push (speexenc->srcpad, GST_DATA (buffer));
801 gst_buffer_unref (buffer);
806 gst_speexenc_set_header_on_caps (GstCaps * caps, GstBuffer * buf1,
809 GstStructure *structure = gst_caps_get_structure (caps, 0);
811 GValue value = { 0 };
814 GST_BUFFER_FLAG_SET (buf1, GST_BUFFER_IN_CAPS);
815 GST_BUFFER_FLAG_SET (buf2, GST_BUFFER_IN_CAPS);
817 /* put buffers in a fixed list */
818 g_value_init (&list, GST_TYPE_FIXED_LIST);
819 g_value_init (&value, GST_TYPE_BUFFER);
820 g_value_set_boxed (&value, buf1);
821 gst_value_list_append_value (&list, &value);
822 g_value_unset (&value);
823 g_value_init (&value, GST_TYPE_BUFFER);
824 g_value_set_boxed (&value, buf2);
825 gst_value_list_append_value (&list, &value);
826 gst_structure_set_value (structure, "streamheader", &list);
827 g_value_unset (&value);
828 g_value_unset (&list);
832 gst_speexenc_chain (GstPad * pad, GstData * _data)
834 GstBuffer *buf = GST_BUFFER (_data);
835 GstSpeexEnc *speexenc;
837 g_return_if_fail (pad != NULL);
838 g_return_if_fail (GST_IS_PAD (pad));
839 g_return_if_fail (buf != NULL);
841 speexenc = GST_SPEEXENC (gst_pad_get_parent (pad));
843 if (GST_IS_EVENT (buf)) {
844 GstEvent *event = GST_EVENT (buf);
846 switch (GST_EVENT_TYPE (event)) {
848 speexenc->eos = TRUE;
849 gst_event_unref (event);
852 if (speexenc->tags) {
853 gst_tag_list_insert (speexenc->tags, gst_event_tag_get_list (event),
854 gst_tag_setter_get_merge_mode (GST_TAG_SETTER (speexenc)));
856 g_assert_not_reached ();
858 gst_pad_event_default (pad, event);
861 gst_pad_event_default (pad, event);
865 if (!speexenc->setup) {
866 gst_buffer_unref (buf);
867 GST_ELEMENT_ERROR (speexenc, CORE, NEGOTIATION, (NULL),
868 ("encoder not initialized (input is not audio?)"));
872 if (!speexenc->header_sent) {
873 /* Speex streams begin with two headers; the initial header (with
874 most of the codec setup parameters) which is mandated by the Ogg
875 bitstream spec. The second header holds any comment fields.
876 We merely need to make the headers, then pass them to libspeex
877 one at a time; libspeex handles the additional Ogg bitstream
879 GstBuffer *buf1, *buf2;
884 gst_speexenc_set_metadata (speexenc);
886 /* create header buffer */
887 data = speex_header_to_packet (&speexenc->header, &data_len);
888 buf1 = gst_speexenc_buffer_from_data (speexenc, data, data_len, 0);
890 /* create comment buffer */
892 gst_speexenc_buffer_from_data (speexenc, speexenc->comments,
893 speexenc->comment_len, 0);
895 /* mark and put on caps */
896 caps = gst_pad_get_caps (speexenc->srcpad);
897 gst_speexenc_set_header_on_caps (caps, buf1, buf2);
899 /* negotiate with these caps */
900 GST_DEBUG ("here are the caps: %" GST_PTR_FORMAT, caps);
901 gst_pad_try_set_caps (speexenc->srcpad, caps);
903 /* push out buffers */
904 gst_speexenc_push_buffer (speexenc, buf1);
905 gst_speexenc_push_buffer (speexenc, buf2);
907 speex_bits_init (&speexenc->bits);
908 speex_bits_reset (&speexenc->bits);
910 speexenc->header_sent = TRUE;
914 gint frame_size = speexenc->frame_size;
915 gint bytes = frame_size * 2 * speexenc->channels;
917 /* push buffer to adapter */
918 gst_adapter_push (speexenc->adapter, buf);
920 while (gst_adapter_available (speexenc->adapter) >= bytes) {
923 gint outsize, written;
926 data = (gint16 *) gst_adapter_peek (speexenc->adapter, bytes);
928 for (i = 0; i < frame_size * speexenc->channels; i++) {
929 speexenc->input[i] = (gfloat) data[i];
931 gst_adapter_flush (speexenc->adapter, bytes);
933 speexenc->samples_in += frame_size;
935 if (speexenc->channels == 2) {
936 speex_encode_stereo (speexenc->input, frame_size, &speexenc->bits);
938 speex_encode (speexenc->state, speexenc->input, &speexenc->bits);
942 if ((speexenc->frameno % speexenc->nframes) != 0)
945 speex_bits_insert_terminator (&speexenc->bits);
946 outsize = speex_bits_nbytes (&speexenc->bits);
948 gst_pad_alloc_buffer (speexenc->srcpad, GST_BUFFER_OFFSET_NONE,
951 speex_bits_write (&speexenc->bits, GST_BUFFER_DATA (outbuf),
953 g_assert (written == outsize);
954 speex_bits_reset (&speexenc->bits);
956 GST_BUFFER_TIMESTAMP (outbuf) =
957 (speexenc->frameno * frame_size -
958 speexenc->lookahead) * GST_SECOND / speexenc->rate;
959 GST_BUFFER_DURATION (outbuf) = frame_size * GST_SECOND / speexenc->rate;
960 GST_BUFFER_OFFSET (outbuf) = speexenc->bytes_out;
961 GST_BUFFER_OFFSET_END (outbuf) =
962 speexenc->frameno * frame_size - speexenc->lookahead;
964 gst_speexenc_push_buffer (speexenc, outbuf);
970 /* clean up and exit. */
971 gst_pad_push (speexenc->srcpad, GST_DATA (gst_event_new (GST_EVENT_EOS)));
972 gst_element_set_eos (GST_ELEMENT (speexenc));
977 gst_speexenc_get_property (GObject * object, guint prop_id, GValue * value,
980 GstSpeexEnc *speexenc;
982 g_return_if_fail (GST_IS_SPEEXENC (object));
984 speexenc = GST_SPEEXENC (object);
988 g_value_set_float (value, speexenc->quality);
991 g_value_set_int (value, speexenc->bitrate);
994 g_value_set_boolean (value, speexenc->vbr);
997 g_value_set_int (value, speexenc->abr);
1000 g_value_set_boolean (value, speexenc->vad);
1003 g_value_set_boolean (value, speexenc->dtx);
1005 case ARG_COMPLEXITY:
1006 g_value_set_int (value, speexenc->complexity);
1009 g_value_set_int (value, speexenc->nframes);
1011 case ARG_LAST_MESSAGE:
1012 g_value_set_string (value, speexenc->last_message);
1015 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1021 gst_speexenc_set_property (GObject * object, guint prop_id,
1022 const GValue * value, GParamSpec * pspec)
1024 GstSpeexEnc *speexenc;
1026 g_return_if_fail (GST_IS_SPEEXENC (object));
1028 speexenc = GST_SPEEXENC (object);
1032 speexenc->quality = g_value_get_float (value);
1035 speexenc->bitrate = g_value_get_int (value);
1038 speexenc->vbr = g_value_get_boolean (value);
1041 speexenc->abr = g_value_get_int (value);
1044 speexenc->vad = g_value_get_boolean (value);
1047 speexenc->dtx = g_value_get_boolean (value);
1049 case ARG_COMPLEXITY:
1050 speexenc->complexity = g_value_get_int (value);
1053 speexenc->nframes = g_value_get_int (value);
1056 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1061 static GstStateChangeReturn
1062 gst_speexenc_change_state (GstElement * element, GstStateChange transition)
1064 GstSpeexEnc *speexenc = GST_SPEEXENC (element);
1066 switch (transition) {
1067 case GST_STATE_CHANGE_NULL_TO_READY:
1069 case GST_STATE_CHANGE_READY_TO_PAUSED:
1070 speexenc->eos = FALSE;
1071 speexenc->frameno = 0;
1072 speexenc->samples_in = 0;
1074 case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
1075 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
1077 case GST_STATE_CHANGE_PAUSED_TO_READY:
1078 speexenc->setup = FALSE;
1079 speexenc->header_sent = FALSE;
1080 gst_tag_list_free (speexenc->tags);
1081 speexenc->tags = gst_tag_list_new ();
1083 case GST_STATE_CHANGE_READY_TO_NULL:
1088 if (GST_ELEMENT_CLASS (parent_class)->change_state)
1089 return GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1091 return GST_STATE_CHANGE_SUCCESS;