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/gsttagsetter.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 = GST_ELEMENT_DETAILS ("Speex audio encoder",
42 "Codec/Encoder/Audio",
43 "Encodes audio in Speex format",
44 "Wim Taymans <wim@fluendo.com>");
46 /* GstSpeexEnc signals and args */
53 #define DEFAULT_QUALITY 8.0
54 #define DEFAULT_BITRATE 0
55 #define DEFAULT_VBR FALSE
57 #define DEFAULT_VAD FALSE
58 #define DEFAULT_DTX FALSE
59 #define DEFAULT_COMPLEXITY 3
60 #define DEFAULT_NFRAMES 1
77 static const GstFormat *
78 gst_speexenc_get_formats (GstPad * pad)
80 static const GstFormat src_formats[] = {
85 static const GstFormat sink_formats[] = {
92 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);
99 static void gst_speexenc_finalize (GObject * object);
101 static gboolean gst_speexenc_sinkevent (GstPad * pad, GstEvent * event);
102 static GstFlowReturn gst_speexenc_chain (GstPad * pad, GstBuffer * buf);
103 static gboolean gst_speexenc_setup (GstSpeexEnc * speexenc);
105 static void gst_speexenc_get_property (GObject * object, guint prop_id,
106 GValue * value, GParamSpec * pspec);
107 static void gst_speexenc_set_property (GObject * object, guint prop_id,
108 const GValue * value, GParamSpec * pspec);
109 static GstStateChangeReturn gst_speexenc_change_state (GstElement * element,
110 GstStateChange transition);
112 static GstElementClass *parent_class = NULL;
114 /*static guint gst_speexenc_signals[LAST_SIGNAL] = { 0 }; */
117 gst_speexenc_get_type (void)
119 static GType speexenc_type = 0;
121 if (!speexenc_type) {
122 static const GTypeInfo speexenc_info = {
123 sizeof (GstSpeexEncClass),
124 gst_speexenc_base_init,
126 (GClassInitFunc) gst_speexenc_class_init,
129 sizeof (GstSpeexEnc),
131 (GInstanceInitFunc) gst_speexenc_init,
133 static const GInterfaceInfo tag_setter_info = {
140 g_type_register_static (GST_TYPE_ELEMENT, "GstSpeexEnc", &speexenc_info,
143 g_type_add_interface_static (speexenc_type, GST_TYPE_TAG_SETTER,
146 GST_DEBUG_CATEGORY_INIT (speexenc_debug, "speexenc", 0, "Speex encoder");
148 return speexenc_type;
152 speex_caps_factory (void)
154 return gst_caps_new_simple ("audio/x-speex", NULL);
158 raw_caps_factory (void)
161 gst_caps_new_simple ("audio/x-raw-int",
162 "rate", GST_TYPE_INT_RANGE, 6000, 48000,
163 "channels", GST_TYPE_INT_RANGE, 1, 2,
164 "endianness", G_TYPE_INT, G_BYTE_ORDER,
165 "signed", G_TYPE_BOOLEAN, TRUE,
166 "width", G_TYPE_INT, 16, "depth", G_TYPE_INT, 16, NULL);
170 gst_speexenc_base_init (gpointer g_class)
172 GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
173 GstCaps *raw_caps, *speex_caps;
175 raw_caps = raw_caps_factory ();
176 speex_caps = speex_caps_factory ();
178 gst_speexenc_sink_template = gst_pad_template_new ("sink", GST_PAD_SINK,
179 GST_PAD_ALWAYS, raw_caps);
180 gst_speexenc_src_template = gst_pad_template_new ("src", GST_PAD_SRC,
181 GST_PAD_ALWAYS, speex_caps);
182 gst_element_class_add_pad_template (element_class,
183 gst_speexenc_sink_template);
184 gst_element_class_add_pad_template (element_class, gst_speexenc_src_template);
185 gst_element_class_set_details (element_class, &speexenc_details);
189 gst_speexenc_class_init (GstSpeexEncClass * klass)
191 GObjectClass *gobject_class;
192 GstElementClass *gstelement_class;
194 gobject_class = (GObjectClass *) klass;
195 gstelement_class = (GstElementClass *) klass;
197 gobject_class->set_property = gst_speexenc_set_property;
198 gobject_class->get_property = gst_speexenc_get_property;
200 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_QUALITY,
201 g_param_spec_float ("quality", "Quality", "Encoding quality",
202 0.0, 10.0, DEFAULT_QUALITY, G_PARAM_READWRITE));
203 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_BITRATE,
204 g_param_spec_int ("bitrate", "Encoding Bit-rate",
205 "Specify an encoding bit-rate (in bps). (0 = automatic)",
206 0, G_MAXINT, DEFAULT_BITRATE, G_PARAM_READWRITE));
207 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_VBR,
208 g_param_spec_boolean ("vbr", "VBR",
209 "Enable variable bit-rate", DEFAULT_VBR, G_PARAM_READWRITE));
210 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_ABR,
211 g_param_spec_int ("abr", "ABR",
212 "Enable average bit-rate (0 = disabled)",
213 0, G_MAXINT, DEFAULT_ABR, G_PARAM_READWRITE));
214 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_VAD,
215 g_param_spec_boolean ("vad", "VAD",
216 "Enable voice activity detection", DEFAULT_VAD, G_PARAM_READWRITE));
217 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_DTX,
218 g_param_spec_boolean ("dtx", "DTX",
219 "Enable discontinuous transmission", DEFAULT_DTX, G_PARAM_READWRITE));
220 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_COMPLEXITY,
221 g_param_spec_int ("complexity", "Complexity",
222 "Set encoding complexity",
223 0, G_MAXINT, DEFAULT_COMPLEXITY, G_PARAM_READWRITE));
224 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_NFRAMES,
225 g_param_spec_int ("nframes", "NFrames",
226 "Number of frames per buffer",
227 0, G_MAXINT, DEFAULT_NFRAMES, G_PARAM_READWRITE));
228 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_LAST_MESSAGE,
229 g_param_spec_string ("last-message", "last-message",
230 "The last status message", NULL, G_PARAM_READABLE));
232 parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
234 gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_speexenc_finalize);
236 gstelement_class->change_state =
237 GST_DEBUG_FUNCPTR (gst_speexenc_change_state);
241 gst_speexenc_finalize (GObject * object)
243 GstSpeexEnc *speexenc;
245 speexenc = GST_SPEEXENC (object);
247 g_object_unref (speexenc->adapter);
249 G_OBJECT_CLASS (parent_class)->finalize (object);
253 gst_speexenc_sink_setcaps (GstPad * pad, GstCaps * caps)
255 GstSpeexEnc *speexenc;
256 GstStructure *structure;
258 speexenc = GST_SPEEXENC (gst_pad_get_parent (pad));
259 speexenc->setup = FALSE;
261 structure = gst_caps_get_structure (caps, 0);
262 gst_structure_get_int (structure, "channels", &speexenc->channels);
263 gst_structure_get_int (structure, "rate", &speexenc->rate);
265 gst_speexenc_setup (speexenc);
267 gst_object_unref (speexenc);
269 return speexenc->setup;
273 gst_speexenc_convert_src (GstPad * pad, GstFormat src_format, gint64 src_value,
274 GstFormat * dest_format, gint64 * dest_value)
277 GstSpeexEnc *speexenc;
280 speexenc = GST_SPEEXENC (GST_PAD_PARENT (pad));
282 if (speexenc->samples_in == 0 ||
283 speexenc->bytes_out == 0 || speexenc->rate == 0)
286 avg = (speexenc->bytes_out * speexenc->rate) / (speexenc->samples_in);
288 switch (src_format) {
289 case GST_FORMAT_BYTES:
290 switch (*dest_format) {
291 case GST_FORMAT_TIME:
292 *dest_value = src_value * GST_SECOND / avg;
298 case GST_FORMAT_TIME:
299 switch (*dest_format) {
300 case GST_FORMAT_BYTES:
301 *dest_value = src_value * avg / GST_SECOND;
314 gst_speexenc_convert_sink (GstPad * pad, GstFormat src_format,
315 gint64 src_value, GstFormat * dest_format, gint64 * dest_value)
319 gint bytes_per_sample;
320 GstSpeexEnc *speexenc;
322 speexenc = GST_SPEEXENC (GST_PAD_PARENT (pad));
324 bytes_per_sample = speexenc->channels * 2;
326 switch (src_format) {
327 case GST_FORMAT_BYTES:
328 switch (*dest_format) {
329 case GST_FORMAT_DEFAULT:
330 if (bytes_per_sample == 0)
332 *dest_value = src_value / bytes_per_sample;
334 case GST_FORMAT_TIME:
336 gint byterate = bytes_per_sample * speexenc->rate;
340 *dest_value = src_value * GST_SECOND / byterate;
347 case GST_FORMAT_DEFAULT:
348 switch (*dest_format) {
349 case GST_FORMAT_BYTES:
350 *dest_value = src_value * bytes_per_sample;
352 case GST_FORMAT_TIME:
353 if (speexenc->rate == 0)
355 *dest_value = src_value * GST_SECOND / speexenc->rate;
361 case GST_FORMAT_TIME:
362 switch (*dest_format) {
363 case GST_FORMAT_BYTES:
364 scale = bytes_per_sample;
366 case GST_FORMAT_DEFAULT:
367 *dest_value = src_value * scale * speexenc->rate / GST_SECOND;
379 static const GstQueryType *
380 gst_speexenc_get_query_types (GstPad * pad)
382 static const GstQueryType gst_speexenc_src_query_types[] = {
389 return gst_speexenc_src_query_types;
393 gst_speexenc_src_query (GstPad * pad, GstQuery * query)
396 GstSpeexEnc *speexenc;
399 speexenc = GST_SPEEXENC (gst_pad_get_parent (pad));
400 peerpad = gst_pad_get_peer (GST_PAD (speexenc->sinkpad));
402 switch (GST_QUERY_TYPE (query)) {
403 case GST_QUERY_POSITION:
405 GstFormat fmt, req_fmt;
408 gst_query_parse_position (query, &req_fmt, NULL);
409 if ((res = gst_pad_query_position (peerpad, &req_fmt, &val))) {
410 gst_query_set_position (query, req_fmt, val);
414 fmt = GST_FORMAT_TIME;
415 if (!(res = gst_pad_query_position (peerpad, &fmt, &pos)))
418 if ((res = gst_pad_query_convert (peerpad, fmt, pos, &req_fmt, &val)))
419 gst_query_set_position (query, req_fmt, val);
423 case GST_QUERY_DURATION:
425 GstFormat fmt, req_fmt;
428 gst_query_parse_duration (query, &req_fmt, NULL);
429 if ((res = gst_pad_query_duration (peerpad, &req_fmt, &val))) {
430 gst_query_set_duration (query, req_fmt, val);
434 fmt = GST_FORMAT_TIME;
435 if (!(res = gst_pad_query_duration (peerpad, &fmt, &dur)))
438 if ((res = gst_pad_query_convert (peerpad, fmt, dur, &req_fmt, &val))) {
439 gst_query_set_duration (query, req_fmt, val);
443 case GST_QUERY_CONVERT:
445 GstFormat src_fmt, dest_fmt;
446 gint64 src_val, dest_val;
448 gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, &dest_val);
449 if (!(res = gst_speexenc_convert_src (pad, src_fmt, src_val, &dest_fmt,
452 gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val);
456 res = gst_pad_query_default (pad, query);
461 gst_object_unref (peerpad);
462 gst_object_unref (speexenc);
467 gst_speexenc_sink_query (GstPad * pad, GstQuery * query)
470 GstSpeexEnc *speexenc;
472 speexenc = GST_SPEEXENC (GST_PAD_PARENT (pad));
474 switch (GST_QUERY_TYPE (query)) {
475 case GST_QUERY_CONVERT:
477 GstFormat src_fmt, dest_fmt;
478 gint64 src_val, dest_val;
480 gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, &dest_val);
482 gst_speexenc_convert_sink (pad, src_fmt, src_val, &dest_fmt,
485 gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val);
489 res = gst_pad_query_default (pad, query);
498 gst_speexenc_init (GstSpeexEnc * speexenc)
501 gst_pad_new_from_template (gst_speexenc_sink_template, "sink");
502 gst_element_add_pad (GST_ELEMENT (speexenc), speexenc->sinkpad);
503 gst_pad_set_event_function (speexenc->sinkpad, gst_speexenc_sinkevent);
504 gst_pad_set_chain_function (speexenc->sinkpad, gst_speexenc_chain);
505 gst_pad_set_setcaps_function (speexenc->sinkpad, gst_speexenc_sink_setcaps);
506 gst_pad_set_query_function (speexenc->sinkpad,
507 GST_DEBUG_FUNCPTR (gst_speexenc_sink_query));
510 gst_pad_new_from_template (gst_speexenc_src_template, "src");
511 gst_pad_set_query_function (speexenc->srcpad,
512 GST_DEBUG_FUNCPTR (gst_speexenc_src_query));
513 gst_pad_set_query_type_function (speexenc->srcpad,
514 GST_DEBUG_FUNCPTR (gst_speexenc_get_query_types));
515 gst_element_add_pad (GST_ELEMENT (speexenc), speexenc->srcpad);
517 speexenc->channels = -1;
520 speexenc->quality = DEFAULT_QUALITY;
521 speexenc->bitrate = DEFAULT_BITRATE;
522 speexenc->vbr = DEFAULT_VBR;
523 speexenc->abr = DEFAULT_ABR;
524 speexenc->vad = DEFAULT_VAD;
525 speexenc->dtx = DEFAULT_DTX;
526 speexenc->complexity = DEFAULT_COMPLEXITY;
527 speexenc->nframes = DEFAULT_NFRAMES;
529 speexenc->setup = FALSE;
530 speexenc->header_sent = FALSE;
532 speexenc->adapter = gst_adapter_new ();
536 /* FIXME: why are we not using the from/to vorbiscomment
537 * functions that are in -lgsttagedit-0.9 here? */
540 gst_speexenc_get_tag_value (const GstTagList * list, const gchar * tag,
544 gchar *speexvalue = NULL;
549 tag_type = gst_tag_get_type (tag);
551 /* get tag name right */
552 if ((strcmp (tag, GST_TAG_TRACK_NUMBER) == 0)
553 || (strcmp (tag, GST_TAG_ALBUM_VOLUME_NUMBER) == 0)
554 || (strcmp (tag, GST_TAG_TRACK_COUNT) == 0)
555 || (strcmp (tag, GST_TAG_ALBUM_VOLUME_COUNT) == 0)) {
558 if (gst_tag_list_get_uint_index (list, tag, index, &track_no)) {
559 speexvalue = g_strdup_printf ("%u", track_no);
561 GST_WARNING ("Failed to extract int tag %d for '%s'", index, tag);
563 } else if (tag_type == GST_TYPE_DATE) {
564 /* FIXME: how are dates represented in speex files? */
567 if (gst_tag_list_get_date_index (list, tag, index, &date)) {
569 g_strdup_printf ("%04d-%02d-%02d", (gint) g_date_get_year (date),
570 (gint) g_date_get_month (date), (gint) g_date_get_day (date));
573 GST_WARNING ("Failed to extract date tag %d for '%s'", index, tag);
575 } else if (tag_type == G_TYPE_STRING) {
576 if (!gst_tag_list_get_string_index (list, tag, index, &speexvalue))
577 GST_WARNING ("Failed to extract string tag %d for '%s'", index, tag);
584 * Comments will be stored in the Vorbis style.
585 * It is describled in the "Structure" section of
586 * http://www.xiph.org/ogg/vorbis/doc/v-comment.html
588 * The comment header is decoded as follows:
589 * 1) [vendor_length] = read an unsigned integer of 32 bits
590 * 2) [vendor_string] = read a UTF-8 vector as [vendor_length] octets
591 * 3) [user_comment_list_length] = read an unsigned integer of 32 bits
592 * 4) iterate [user_comment_list_length] times {
593 * 5) [length] = read an unsigned integer of 32 bits
594 * 6) this iteration's user comment = read a UTF-8 vector as [length] octets
596 * 7) [framing_bit] = read a single bit as boolean
597 * 8) if ( [framing_bit] unset or end of packet ) then ERROR
600 * If you have troubles, please write to ymnk@jcraft.com.
603 comment_init (guint8 ** comments, int *length, char *vendor_string)
605 int vendor_length = strlen (vendor_string);
606 int user_comment_list_length = 0;
607 int len = 4 + vendor_length + 4;
608 guint8 *p = g_malloc (len);
610 GST_WRITE_UINT32_LE (p, vendor_length);
611 memcpy (p + 4, vendor_string, vendor_length);
612 GST_WRITE_UINT32_LE (p + 4 + vendor_length, user_comment_list_length);
617 comment_add (guint8 ** comments, int *length, const char *tag, char *val)
619 guint8 *p = *comments;
620 int vendor_length = GST_READ_UINT32_LE (p);
621 int user_comment_list_length = GST_READ_UINT32_LE (p + 4 + vendor_length);
622 int tag_len = (tag ? strlen (tag) : 0);
623 int val_len = strlen (val);
624 int len = (*length) + 4 + tag_len + val_len;
626 p = g_realloc (p, len);
628 GST_WRITE_UINT32_LE (p + *length, tag_len + val_len); /* length of comment */
630 memcpy (p + *length + 4, (guint8 *) tag, tag_len); /* comment */
631 memcpy (p + *length + 4 + tag_len, val, val_len); /* comment */
632 GST_WRITE_UINT32_LE (p + 4 + vendor_length, user_comment_list_length + 1);
639 gst_speexenc_metadata_set1 (const GstTagList * list, const gchar * tag,
642 const gchar *speextag = NULL;
643 gchar *speexvalue = NULL;
645 GstSpeexEnc *enc = GST_SPEEXENC (speexenc);
647 speextag = gst_tag_to_vorbis_tag (tag);
648 if (speextag == NULL) {
652 count = gst_tag_list_get_tag_size (list, tag);
653 for (i = 0; i < count; i++) {
654 speexvalue = gst_speexenc_get_tag_value (list, tag, i);
656 if (speexvalue != NULL) {
657 comment_add (&enc->comments, &enc->comment_len, speextag, speexvalue);
663 gst_speexenc_set_metadata (GstSpeexEnc * speexenc)
666 const GstTagList *user_tags;
668 user_tags = gst_tag_setter_get_tag_list (GST_TAG_SETTER (speexenc));
669 if (!(speexenc->tags || user_tags))
672 comment_init (&speexenc->comments, &speexenc->comment_len,
673 "Encoded with GStreamer Speexenc");
675 gst_tag_list_merge (user_tags, speexenc->tags,
676 gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (speexenc)));
677 gst_tag_list_foreach (copy, gst_speexenc_metadata_set1, speexenc);
678 gst_tag_list_free (copy);
682 gst_speexenc_setup (GstSpeexEnc * speexenc)
684 speexenc->setup = FALSE;
686 switch (speexenc->mode) {
687 case GST_SPEEXENC_MODE_UWB:
688 speexenc->speex_mode = (SpeexMode *) & speex_uwb_mode;
690 case GST_SPEEXENC_MODE_WB:
691 speexenc->speex_mode = (SpeexMode *) & speex_wb_mode;
693 case GST_SPEEXENC_MODE_NB:
694 speexenc->speex_mode = (SpeexMode *) & speex_nb_mode;
696 case GST_SPEEXENC_MODE_AUTO:
702 if (speexenc->rate > 25000) {
703 if (speexenc->mode == GST_SPEEXENC_MODE_AUTO) {
704 speexenc->speex_mode = (SpeexMode *) & speex_uwb_mode;
706 if (speexenc->speex_mode != &speex_uwb_mode) {
707 speexenc->last_message =
709 ("Warning: suggest to use ultra wide band mode for this rate");
710 g_object_notify (G_OBJECT (speexenc), "last_message");
713 } else if (speexenc->rate > 12500) {
714 if (speexenc->mode == GST_SPEEXENC_MODE_AUTO) {
715 speexenc->speex_mode = (SpeexMode *) & speex_wb_mode;
717 if (speexenc->speex_mode != &speex_wb_mode) {
718 speexenc->last_message =
720 ("Warning: suggest to use wide band mode for this rate");
721 g_object_notify (G_OBJECT (speexenc), "last_message");
725 if (speexenc->mode == GST_SPEEXENC_MODE_AUTO) {
726 speexenc->speex_mode = (SpeexMode *) & speex_nb_mode;
728 if (speexenc->speex_mode != &speex_nb_mode) {
729 speexenc->last_message =
731 ("Warning: suggest to use narrow band mode for this rate");
732 g_object_notify (G_OBJECT (speexenc), "last_message");
737 if (speexenc->rate != 8000 && speexenc->rate != 16000
738 && speexenc->rate != 32000) {
739 speexenc->last_message =
740 g_strdup_printf ("Warning: speex is optimized for 8, 16 and 32 KHz");
741 g_object_notify (G_OBJECT (speexenc), "last_message");
744 speex_init_header (&speexenc->header, speexenc->rate, 1,
745 speexenc->speex_mode);
746 speexenc->header.frames_per_packet = speexenc->nframes;
747 speexenc->header.vbr = speexenc->vbr;
748 speexenc->header.nb_channels = speexenc->channels;
750 /*Initialize Speex encoder */
751 speexenc->state = speex_encoder_init (speexenc->speex_mode);
753 speex_encoder_ctl (speexenc->state, SPEEX_GET_FRAME_SIZE,
754 &speexenc->frame_size);
755 speex_encoder_ctl (speexenc->state, SPEEX_SET_COMPLEXITY,
756 &speexenc->complexity);
757 speex_encoder_ctl (speexenc->state, SPEEX_SET_SAMPLING_RATE, &speexenc->rate);
760 speex_encoder_ctl (speexenc->state, SPEEX_SET_VBR_QUALITY,
763 gint tmp = floor (speexenc->quality);
765 speex_encoder_ctl (speexenc->state, SPEEX_SET_QUALITY, &tmp);
767 if (speexenc->bitrate) {
768 if (speexenc->quality >= 0.0 && speexenc->vbr) {
769 speexenc->last_message =
770 g_strdup_printf ("Warning: bitrate option is overriding quality");
771 g_object_notify (G_OBJECT (speexenc), "last_message");
773 speex_encoder_ctl (speexenc->state, SPEEX_SET_BITRATE, &speexenc->bitrate);
778 speex_encoder_ctl (speexenc->state, SPEEX_SET_VBR, &tmp);
779 } else if (speexenc->vad) {
782 speex_encoder_ctl (speexenc->state, SPEEX_SET_VAD, &tmp);
788 speex_encoder_ctl (speexenc->state, SPEEX_SET_DTX, &tmp);
791 if (speexenc->dtx && !(speexenc->vbr || speexenc->abr || speexenc->vad)) {
792 speexenc->last_message =
793 g_strdup_printf ("Warning: dtx is useless without vad, vbr or abr");
794 g_object_notify (G_OBJECT (speexenc), "last_message");
795 } else if ((speexenc->vbr || speexenc->abr) && (speexenc->vad)) {
796 speexenc->last_message =
797 g_strdup_printf ("Warning: vad is already implied by vbr or abr");
798 g_object_notify (G_OBJECT (speexenc), "last_message");
802 speex_encoder_ctl (speexenc->state, SPEEX_SET_ABR, &speexenc->abr);
805 speex_encoder_ctl (speexenc->state, SPEEX_GET_LOOKAHEAD,
806 &speexenc->lookahead);
808 speexenc->setup = TRUE;
813 /* prepare a buffer for transmission */
815 gst_speexenc_buffer_from_data (GstSpeexEnc * speexenc, guchar * data,
816 gint data_len, guint64 granulepos)
820 outbuf = gst_buffer_new_and_alloc (data_len);
821 memcpy (GST_BUFFER_DATA (outbuf), data, data_len);
822 GST_BUFFER_OFFSET (outbuf) = speexenc->bytes_out;
823 GST_BUFFER_OFFSET_END (outbuf) = granulepos;
825 GST_DEBUG ("encoded buffer of %d bytes", GST_BUFFER_SIZE (outbuf));
830 /* push out the buffer and do internal bookkeeping */
832 gst_speexenc_push_buffer (GstSpeexEnc * speexenc, GstBuffer * buffer)
834 speexenc->bytes_out += GST_BUFFER_SIZE (buffer);
836 return gst_pad_push (speexenc->srcpad, buffer);
841 gst_speexenc_set_header_on_caps (GstCaps * caps, GstBuffer * buf1,
844 caps = gst_caps_make_writable (caps);
845 GstStructure *structure = gst_caps_get_structure (caps, 0);
846 GValue array = { 0 };
847 GValue value = { 0 };
850 GST_BUFFER_FLAG_SET (buf1, GST_BUFFER_FLAG_IN_CAPS);
851 GST_BUFFER_FLAG_SET (buf2, GST_BUFFER_FLAG_IN_CAPS);
853 /* put buffers in a fixed list */
854 g_value_init (&array, GST_TYPE_ARRAY);
855 g_value_init (&value, GST_TYPE_BUFFER);
856 gst_value_set_buffer (&value, buf1);
857 gst_value_array_append_value (&array, &value);
858 g_value_unset (&value);
859 g_value_init (&value, GST_TYPE_BUFFER);
860 gst_value_set_buffer (&value, buf2);
861 gst_value_array_append_value (&array, &value);
862 gst_structure_set_value (structure, "streamheader", &array);
863 g_value_unset (&value);
864 g_value_unset (&array);
871 gst_speexenc_sinkevent (GstPad * pad, GstEvent * event)
874 GstSpeexEnc *speexenc;
876 speexenc = GST_SPEEXENC (GST_PAD_PARENT (pad));
878 switch (GST_EVENT_TYPE (event)) {
880 speexenc->eos = TRUE;
881 res = gst_pad_event_default (pad, event);
887 gst_event_parse_tag (event, &list);
888 if (speexenc->tags) {
889 gst_tag_list_insert (speexenc->tags, list,
890 gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (speexenc)));
892 g_assert_not_reached ();
894 res = gst_pad_event_default (pad, event);
898 res = gst_pad_event_default (pad, event);
906 gst_speexenc_chain (GstPad * pad, GstBuffer * buf)
908 GstSpeexEnc *speexenc;
909 GstFlowReturn ret = GST_FLOW_OK;
911 speexenc = GST_SPEEXENC (gst_pad_get_parent (pad));
913 if (!speexenc->setup)
916 if (!speexenc->header_sent) {
917 /* Speex streams begin with two headers; the initial header (with
918 most of the codec setup parameters) which is mandated by the Ogg
919 bitstream spec. The second header holds any comment fields.
920 We merely need to make the headers, then pass them to libspeex
921 one at a time; libspeex handles the additional Ogg bitstream
923 GstBuffer *buf1, *buf2;
928 gst_speexenc_set_metadata (speexenc);
930 /* create header buffer */
931 data = (guint8 *) speex_header_to_packet (&speexenc->header, &data_len);
932 buf1 = gst_speexenc_buffer_from_data (speexenc, data, data_len, 0);
934 /* create comment buffer */
936 gst_speexenc_buffer_from_data (speexenc, speexenc->comments,
937 speexenc->comment_len, 0);
939 /* mark and put on caps */
940 caps = gst_pad_get_caps (speexenc->srcpad);
941 caps = gst_speexenc_set_header_on_caps (caps, buf1, buf2);
943 /* negotiate with these caps */
944 GST_DEBUG ("here are the caps: %" GST_PTR_FORMAT, caps);
945 gst_pad_set_caps (speexenc->srcpad, caps);
947 gst_buffer_set_caps (buf1, caps);
948 gst_buffer_set_caps (buf2, caps);
950 /* push out buffers */
951 ret = gst_speexenc_push_buffer (speexenc, buf1);
953 if ((GST_FLOW_OK != ret) && (GST_FLOW_NOT_LINKED != ret)) {
954 /* unref buf2 as we are not going to push it anymore */
956 gst_buffer_unref (buf2);
960 ret = gst_speexenc_push_buffer (speexenc, buf2);
962 if ((GST_FLOW_OK != ret) && (GST_FLOW_NOT_LINKED != ret))
965 speex_bits_init (&speexenc->bits);
966 speex_bits_reset (&speexenc->bits);
968 speexenc->header_sent = TRUE;
972 gint frame_size = speexenc->frame_size;
973 gint bytes = frame_size * 2 * speexenc->channels;
975 /* push buffer to adapter */
976 gst_adapter_push (speexenc->adapter, buf);
978 while (gst_adapter_available (speexenc->adapter) >= bytes) {
981 gint outsize, written;
984 data = (gint16 *) gst_adapter_peek (speexenc->adapter, bytes);
986 for (i = 0; i < frame_size * speexenc->channels; i++) {
987 speexenc->input[i] = (gfloat) data[i];
989 gst_adapter_flush (speexenc->adapter, bytes);
991 speexenc->samples_in += frame_size;
993 if (speexenc->channels == 2) {
994 speex_encode_stereo (speexenc->input, frame_size, &speexenc->bits);
996 speex_encode (speexenc->state, speexenc->input, &speexenc->bits);
1000 if ((speexenc->frameno % speexenc->nframes) != 0)
1003 speex_bits_insert_terminator (&speexenc->bits);
1004 outsize = speex_bits_nbytes (&speexenc->bits);
1006 ret = gst_pad_alloc_buffer_and_set_caps (speexenc->srcpad,
1007 GST_BUFFER_OFFSET_NONE, outsize, GST_PAD_CAPS (speexenc->srcpad),
1010 if ((GST_FLOW_OK != ret))
1013 written = speex_bits_write (&speexenc->bits,
1014 (gchar *) GST_BUFFER_DATA (outbuf), outsize);
1015 g_assert (written == outsize);
1016 speex_bits_reset (&speexenc->bits);
1018 GST_BUFFER_TIMESTAMP (outbuf) =
1019 gst_util_uint64_scale_int (speexenc->frameno * frame_size -
1020 speexenc->lookahead, GST_SECOND, speexenc->rate);
1021 GST_BUFFER_DURATION (outbuf) = gst_util_uint64_scale_int (frame_size,
1022 GST_SECOND, speexenc->rate);
1023 /* set gp time and granulepos; see gst-plugins-base/ext/ogg/README */
1024 GST_BUFFER_OFFSET_END (outbuf) =
1025 ((speexenc->frameno + 1) * frame_size - speexenc->lookahead);
1026 GST_BUFFER_OFFSET (outbuf) =
1027 gst_util_uint64_scale_int (GST_BUFFER_OFFSET_END (outbuf), GST_SECOND,
1030 ret = gst_speexenc_push_buffer (speexenc, outbuf);
1032 if ((GST_FLOW_OK != ret) && (GST_FLOW_NOT_LINKED != ret))
1038 gst_object_unref (speexenc);
1044 gst_buffer_unref (buf);
1045 GST_ELEMENT_ERROR (speexenc, CORE, NEGOTIATION, (NULL),
1046 ("encoder not initialized (input is not audio?)"));
1047 ret = GST_FLOW_NOT_NEGOTIATED;
1055 gst_speexenc_get_property (GObject * object, guint prop_id, GValue * value,
1058 GstSpeexEnc *speexenc;
1060 g_return_if_fail (GST_IS_SPEEXENC (object));
1062 speexenc = GST_SPEEXENC (object);
1066 g_value_set_float (value, speexenc->quality);
1069 g_value_set_int (value, speexenc->bitrate);
1072 g_value_set_boolean (value, speexenc->vbr);
1075 g_value_set_int (value, speexenc->abr);
1078 g_value_set_boolean (value, speexenc->vad);
1081 g_value_set_boolean (value, speexenc->dtx);
1083 case ARG_COMPLEXITY:
1084 g_value_set_int (value, speexenc->complexity);
1087 g_value_set_int (value, speexenc->nframes);
1089 case ARG_LAST_MESSAGE:
1090 g_value_set_string (value, speexenc->last_message);
1093 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1099 gst_speexenc_set_property (GObject * object, guint prop_id,
1100 const GValue * value, GParamSpec * pspec)
1102 GstSpeexEnc *speexenc;
1104 g_return_if_fail (GST_IS_SPEEXENC (object));
1106 speexenc = GST_SPEEXENC (object);
1110 speexenc->quality = g_value_get_float (value);
1113 speexenc->bitrate = g_value_get_int (value);
1116 speexenc->vbr = g_value_get_boolean (value);
1119 speexenc->abr = g_value_get_int (value);
1122 speexenc->vad = g_value_get_boolean (value);
1125 speexenc->dtx = g_value_get_boolean (value);
1127 case ARG_COMPLEXITY:
1128 speexenc->complexity = g_value_get_int (value);
1131 speexenc->nframes = g_value_get_int (value);
1134 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1139 static GstStateChangeReturn
1140 gst_speexenc_change_state (GstElement * element, GstStateChange transition)
1142 GstSpeexEnc *speexenc = GST_SPEEXENC (element);
1143 GstStateChangeReturn res;
1145 switch (transition) {
1146 case GST_STATE_CHANGE_NULL_TO_READY:
1147 speexenc->tags = gst_tag_list_new ();
1149 case GST_STATE_CHANGE_READY_TO_PAUSED:
1150 speexenc->frameno = 0;
1151 speexenc->samples_in = 0;
1153 case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
1159 res = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1161 switch (transition) {
1162 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
1164 case GST_STATE_CHANGE_PAUSED_TO_READY:
1165 speexenc->setup = FALSE;
1166 speexenc->header_sent = FALSE;
1168 case GST_STATE_CHANGE_READY_TO_NULL:
1169 gst_tag_list_free (speexenc->tags);
1170 speexenc->tags = NULL;