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 GstStructure *structure = NULL;
845 GValue array = { 0 };
846 GValue value = { 0 };
848 caps = gst_caps_make_writable (caps);
849 structure = gst_caps_get_structure (caps, 0);
852 GST_BUFFER_FLAG_SET (buf1, GST_BUFFER_FLAG_IN_CAPS);
853 GST_BUFFER_FLAG_SET (buf2, GST_BUFFER_FLAG_IN_CAPS);
855 /* put buffers in a fixed list */
856 g_value_init (&array, GST_TYPE_ARRAY);
857 g_value_init (&value, GST_TYPE_BUFFER);
858 gst_value_set_buffer (&value, buf1);
859 gst_value_array_append_value (&array, &value);
860 g_value_unset (&value);
861 g_value_init (&value, GST_TYPE_BUFFER);
862 gst_value_set_buffer (&value, buf2);
863 gst_value_array_append_value (&array, &value);
864 gst_structure_set_value (structure, "streamheader", &array);
865 g_value_unset (&value);
866 g_value_unset (&array);
873 gst_speexenc_sinkevent (GstPad * pad, GstEvent * event)
876 GstSpeexEnc *speexenc;
878 speexenc = GST_SPEEXENC (GST_PAD_PARENT (pad));
880 switch (GST_EVENT_TYPE (event)) {
882 speexenc->eos = TRUE;
883 res = gst_pad_event_default (pad, event);
889 gst_event_parse_tag (event, &list);
890 if (speexenc->tags) {
891 gst_tag_list_insert (speexenc->tags, list,
892 gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (speexenc)));
894 g_assert_not_reached ();
896 res = gst_pad_event_default (pad, event);
900 res = gst_pad_event_default (pad, event);
908 gst_speexenc_chain (GstPad * pad, GstBuffer * buf)
910 GstSpeexEnc *speexenc;
911 GstFlowReturn ret = GST_FLOW_OK;
913 speexenc = GST_SPEEXENC (gst_pad_get_parent (pad));
915 if (!speexenc->setup)
918 if (!speexenc->header_sent) {
919 /* Speex streams begin with two headers; the initial header (with
920 most of the codec setup parameters) which is mandated by the Ogg
921 bitstream spec. The second header holds any comment fields.
922 We merely need to make the headers, then pass them to libspeex
923 one at a time; libspeex handles the additional Ogg bitstream
925 GstBuffer *buf1, *buf2;
930 gst_speexenc_set_metadata (speexenc);
932 /* create header buffer */
933 data = (guint8 *) speex_header_to_packet (&speexenc->header, &data_len);
934 buf1 = gst_speexenc_buffer_from_data (speexenc, data, data_len, 0);
936 /* create comment buffer */
938 gst_speexenc_buffer_from_data (speexenc, speexenc->comments,
939 speexenc->comment_len, 0);
941 /* mark and put on caps */
942 caps = gst_pad_get_caps (speexenc->srcpad);
943 caps = gst_speexenc_set_header_on_caps (caps, buf1, buf2);
945 /* negotiate with these caps */
946 GST_DEBUG ("here are the caps: %" GST_PTR_FORMAT, caps);
947 gst_pad_set_caps (speexenc->srcpad, caps);
949 gst_buffer_set_caps (buf1, caps);
950 gst_buffer_set_caps (buf2, caps);
952 /* push out buffers */
953 ret = gst_speexenc_push_buffer (speexenc, buf1);
955 if ((GST_FLOW_OK != ret) && (GST_FLOW_NOT_LINKED != ret)) {
956 /* unref buf2 as we are not going to push it anymore */
958 gst_buffer_unref (buf2);
962 ret = gst_speexenc_push_buffer (speexenc, buf2);
964 if ((GST_FLOW_OK != ret) && (GST_FLOW_NOT_LINKED != ret))
967 speex_bits_init (&speexenc->bits);
968 speex_bits_reset (&speexenc->bits);
970 speexenc->header_sent = TRUE;
974 gint frame_size = speexenc->frame_size;
975 gint bytes = frame_size * 2 * speexenc->channels;
977 /* push buffer to adapter */
978 gst_adapter_push (speexenc->adapter, buf);
980 while (gst_adapter_available (speexenc->adapter) >= bytes) {
983 gint outsize, written;
986 data = (gint16 *) gst_adapter_peek (speexenc->adapter, bytes);
988 for (i = 0; i < frame_size * speexenc->channels; i++) {
989 speexenc->input[i] = (gfloat) data[i];
991 gst_adapter_flush (speexenc->adapter, bytes);
993 speexenc->samples_in += frame_size;
995 if (speexenc->channels == 2) {
996 speex_encode_stereo (speexenc->input, frame_size, &speexenc->bits);
998 speex_encode (speexenc->state, speexenc->input, &speexenc->bits);
1000 speexenc->frameno++;
1002 if ((speexenc->frameno % speexenc->nframes) != 0)
1005 speex_bits_insert_terminator (&speexenc->bits);
1006 outsize = speex_bits_nbytes (&speexenc->bits);
1008 ret = gst_pad_alloc_buffer_and_set_caps (speexenc->srcpad,
1009 GST_BUFFER_OFFSET_NONE, outsize, GST_PAD_CAPS (speexenc->srcpad),
1012 if ((GST_FLOW_OK != ret))
1015 written = speex_bits_write (&speexenc->bits,
1016 (gchar *) GST_BUFFER_DATA (outbuf), outsize);
1017 g_assert (written == outsize);
1018 speex_bits_reset (&speexenc->bits);
1020 GST_BUFFER_TIMESTAMP (outbuf) =
1021 gst_util_uint64_scale_int (speexenc->frameno * frame_size -
1022 speexenc->lookahead, GST_SECOND, speexenc->rate);
1023 GST_BUFFER_DURATION (outbuf) = gst_util_uint64_scale_int (frame_size,
1024 GST_SECOND, speexenc->rate);
1025 /* set gp time and granulepos; see gst-plugins-base/ext/ogg/README */
1026 GST_BUFFER_OFFSET_END (outbuf) =
1027 ((speexenc->frameno + 1) * frame_size - speexenc->lookahead);
1028 GST_BUFFER_OFFSET (outbuf) =
1029 gst_util_uint64_scale_int (GST_BUFFER_OFFSET_END (outbuf), GST_SECOND,
1032 ret = gst_speexenc_push_buffer (speexenc, outbuf);
1034 if ((GST_FLOW_OK != ret) && (GST_FLOW_NOT_LINKED != ret))
1040 gst_object_unref (speexenc);
1046 gst_buffer_unref (buf);
1047 GST_ELEMENT_ERROR (speexenc, CORE, NEGOTIATION, (NULL),
1048 ("encoder not initialized (input is not audio?)"));
1049 ret = GST_FLOW_NOT_NEGOTIATED;
1057 gst_speexenc_get_property (GObject * object, guint prop_id, GValue * value,
1060 GstSpeexEnc *speexenc;
1062 g_return_if_fail (GST_IS_SPEEXENC (object));
1064 speexenc = GST_SPEEXENC (object);
1068 g_value_set_float (value, speexenc->quality);
1071 g_value_set_int (value, speexenc->bitrate);
1074 g_value_set_boolean (value, speexenc->vbr);
1077 g_value_set_int (value, speexenc->abr);
1080 g_value_set_boolean (value, speexenc->vad);
1083 g_value_set_boolean (value, speexenc->dtx);
1085 case ARG_COMPLEXITY:
1086 g_value_set_int (value, speexenc->complexity);
1089 g_value_set_int (value, speexenc->nframes);
1091 case ARG_LAST_MESSAGE:
1092 g_value_set_string (value, speexenc->last_message);
1095 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1101 gst_speexenc_set_property (GObject * object, guint prop_id,
1102 const GValue * value, GParamSpec * pspec)
1104 GstSpeexEnc *speexenc;
1106 g_return_if_fail (GST_IS_SPEEXENC (object));
1108 speexenc = GST_SPEEXENC (object);
1112 speexenc->quality = g_value_get_float (value);
1115 speexenc->bitrate = g_value_get_int (value);
1118 speexenc->vbr = g_value_get_boolean (value);
1121 speexenc->abr = g_value_get_int (value);
1124 speexenc->vad = g_value_get_boolean (value);
1127 speexenc->dtx = g_value_get_boolean (value);
1129 case ARG_COMPLEXITY:
1130 speexenc->complexity = g_value_get_int (value);
1133 speexenc->nframes = g_value_get_int (value);
1136 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1141 static GstStateChangeReturn
1142 gst_speexenc_change_state (GstElement * element, GstStateChange transition)
1144 GstSpeexEnc *speexenc = GST_SPEEXENC (element);
1145 GstStateChangeReturn res;
1147 switch (transition) {
1148 case GST_STATE_CHANGE_NULL_TO_READY:
1149 speexenc->tags = gst_tag_list_new ();
1151 case GST_STATE_CHANGE_READY_TO_PAUSED:
1152 speexenc->frameno = 0;
1153 speexenc->samples_in = 0;
1155 case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
1161 res = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1163 switch (transition) {
1164 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
1166 case GST_STATE_CHANGE_PAUSED_TO_READY:
1167 speexenc->setup = FALSE;
1168 speexenc->header_sent = FALSE;
1170 case GST_STATE_CHANGE_READY_TO_NULL:
1171 gst_tag_list_free (speexenc->tags);
1172 speexenc->tags = NULL;