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 static const GstElementDetails speexenc_details =
42 GST_ELEMENT_DETAILS ("Speex audio encoder",
43 "Codec/Encoder/Audio",
44 "Encodes audio in Speex format",
45 "Wim Taymans <wim@fluendo.com>");
47 /* GstSpeexEnc signals and args */
54 #define DEFAULT_QUALITY 8.0
55 #define DEFAULT_BITRATE 0
56 #define DEFAULT_VBR FALSE
58 #define DEFAULT_VAD FALSE
59 #define DEFAULT_DTX FALSE
60 #define DEFAULT_COMPLEXITY 3
61 #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);
97 static void gst_speexenc_base_init (gpointer g_class);
98 static void gst_speexenc_class_init (GstSpeexEncClass * klass);
99 static void gst_speexenc_init (GstSpeexEnc * speexenc);
100 static void gst_speexenc_finalize (GObject * object);
102 static gboolean gst_speexenc_sinkevent (GstPad * pad, GstEvent * event);
103 static GstFlowReturn gst_speexenc_chain (GstPad * pad, GstBuffer * buf);
104 static gboolean gst_speexenc_setup (GstSpeexEnc * speexenc);
106 static void gst_speexenc_get_property (GObject * object, guint prop_id,
107 GValue * value, GParamSpec * pspec);
108 static void gst_speexenc_set_property (GObject * object, guint prop_id,
109 const GValue * value, GParamSpec * pspec);
110 static GstStateChangeReturn gst_speexenc_change_state (GstElement * element,
111 GstStateChange transition);
113 static GstElementClass *parent_class = NULL;
115 /*static guint gst_speexenc_signals[LAST_SIGNAL] = { 0 }; */
118 gst_speexenc_get_type (void)
120 static GType speexenc_type = 0;
122 if (!speexenc_type) {
123 static const GTypeInfo speexenc_info = {
124 sizeof (GstSpeexEncClass),
125 gst_speexenc_base_init,
127 (GClassInitFunc) gst_speexenc_class_init,
130 sizeof (GstSpeexEnc),
132 (GInstanceInitFunc) gst_speexenc_init,
134 static const GInterfaceInfo tag_setter_info = {
141 g_type_register_static (GST_TYPE_ELEMENT, "GstSpeexEnc", &speexenc_info,
144 g_type_add_interface_static (speexenc_type, GST_TYPE_TAG_SETTER,
147 GST_DEBUG_CATEGORY_INIT (speexenc_debug, "speexenc", 0, "Speex encoder");
149 return speexenc_type;
153 speex_caps_factory (void)
155 return gst_caps_new_simple ("audio/x-speex", NULL);
159 raw_caps_factory (void)
162 gst_caps_new_simple ("audio/x-raw-int",
163 "rate", GST_TYPE_INT_RANGE, 6000, 48000,
164 "channels", GST_TYPE_INT_RANGE, 1, 2,
165 "endianness", G_TYPE_INT, G_BYTE_ORDER,
166 "signed", G_TYPE_BOOLEAN, TRUE,
167 "width", G_TYPE_INT, 16, "depth", G_TYPE_INT, 16, NULL);
171 gst_speexenc_base_init (gpointer g_class)
173 GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
174 GstCaps *raw_caps, *speex_caps;
176 raw_caps = raw_caps_factory ();
177 speex_caps = speex_caps_factory ();
179 gst_speexenc_sink_template = gst_pad_template_new ("sink", GST_PAD_SINK,
180 GST_PAD_ALWAYS, raw_caps);
181 gst_speexenc_src_template = gst_pad_template_new ("src", GST_PAD_SRC,
182 GST_PAD_ALWAYS, speex_caps);
183 gst_element_class_add_pad_template (element_class,
184 gst_speexenc_sink_template);
185 gst_element_class_add_pad_template (element_class, gst_speexenc_src_template);
186 gst_element_class_set_details (element_class, &speexenc_details);
190 gst_speexenc_class_init (GstSpeexEncClass * klass)
192 GObjectClass *gobject_class;
193 GstElementClass *gstelement_class;
195 gobject_class = (GObjectClass *) klass;
196 gstelement_class = (GstElementClass *) klass;
198 gobject_class->set_property = gst_speexenc_set_property;
199 gobject_class->get_property = gst_speexenc_get_property;
201 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_QUALITY,
202 g_param_spec_float ("quality", "Quality", "Encoding quality",
203 0.0, 10.0, DEFAULT_QUALITY, G_PARAM_READWRITE));
204 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_BITRATE,
205 g_param_spec_int ("bitrate", "Encoding Bit-rate",
206 "Specify an encoding bit-rate (in bps). (0 = automatic)",
207 0, G_MAXINT, DEFAULT_BITRATE, G_PARAM_READWRITE));
208 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_VBR,
209 g_param_spec_boolean ("vbr", "VBR",
210 "Enable variable bit-rate", DEFAULT_VBR, G_PARAM_READWRITE));
211 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_ABR,
212 g_param_spec_int ("abr", "ABR",
213 "Enable average bit-rate (0 = disabled)",
214 0, G_MAXINT, DEFAULT_ABR, G_PARAM_READWRITE));
215 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_VAD,
216 g_param_spec_boolean ("vad", "VAD",
217 "Enable voice activity detection", DEFAULT_VAD, G_PARAM_READWRITE));
218 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_DTX,
219 g_param_spec_boolean ("dtx", "DTX",
220 "Enable discontinuous transmission", DEFAULT_DTX, G_PARAM_READWRITE));
221 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_COMPLEXITY,
222 g_param_spec_int ("complexity", "Complexity",
223 "Set encoding complexity",
224 0, G_MAXINT, DEFAULT_COMPLEXITY, G_PARAM_READWRITE));
225 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_NFRAMES,
226 g_param_spec_int ("nframes", "NFrames",
227 "Number of frames per buffer",
228 0, G_MAXINT, DEFAULT_NFRAMES, G_PARAM_READWRITE));
229 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_LAST_MESSAGE,
230 g_param_spec_string ("last-message", "last-message",
231 "The last status message", NULL, G_PARAM_READABLE));
233 parent_class = g_type_class_peek_parent (klass);
235 gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_speexenc_finalize);
237 gstelement_class->change_state =
238 GST_DEBUG_FUNCPTR (gst_speexenc_change_state);
242 gst_speexenc_finalize (GObject * object)
244 GstSpeexEnc *speexenc;
246 speexenc = GST_SPEEXENC (object);
248 g_object_unref (speexenc->adapter);
250 G_OBJECT_CLASS (parent_class)->finalize (object);
254 gst_speexenc_sink_setcaps (GstPad * pad, GstCaps * caps)
256 GstSpeexEnc *speexenc;
257 GstStructure *structure;
259 speexenc = GST_SPEEXENC (gst_pad_get_parent (pad));
260 speexenc->setup = FALSE;
262 structure = gst_caps_get_structure (caps, 0);
263 gst_structure_get_int (structure, "channels", &speexenc->channels);
264 gst_structure_get_int (structure, "rate", &speexenc->rate);
266 gst_speexenc_setup (speexenc);
268 gst_object_unref (speexenc);
270 return speexenc->setup;
274 gst_speexenc_convert_src (GstPad * pad, GstFormat src_format, gint64 src_value,
275 GstFormat * dest_format, gint64 * dest_value)
278 GstSpeexEnc *speexenc;
281 speexenc = GST_SPEEXENC (GST_PAD_PARENT (pad));
283 if (speexenc->samples_in == 0 ||
284 speexenc->bytes_out == 0 || speexenc->rate == 0)
287 avg = (speexenc->bytes_out * speexenc->rate) / (speexenc->samples_in);
289 switch (src_format) {
290 case GST_FORMAT_BYTES:
291 switch (*dest_format) {
292 case GST_FORMAT_TIME:
293 *dest_value = src_value * GST_SECOND / avg;
299 case GST_FORMAT_TIME:
300 switch (*dest_format) {
301 case GST_FORMAT_BYTES:
302 *dest_value = src_value * avg / GST_SECOND;
315 gst_speexenc_convert_sink (GstPad * pad, GstFormat src_format,
316 gint64 src_value, GstFormat * dest_format, gint64 * dest_value)
320 gint bytes_per_sample;
321 GstSpeexEnc *speexenc;
323 speexenc = GST_SPEEXENC (GST_PAD_PARENT (pad));
325 bytes_per_sample = speexenc->channels * 2;
327 switch (src_format) {
328 case GST_FORMAT_BYTES:
329 switch (*dest_format) {
330 case GST_FORMAT_DEFAULT:
331 if (bytes_per_sample == 0)
333 *dest_value = src_value / bytes_per_sample;
335 case GST_FORMAT_TIME:
337 gint byterate = bytes_per_sample * speexenc->rate;
341 *dest_value = src_value * GST_SECOND / byterate;
348 case GST_FORMAT_DEFAULT:
349 switch (*dest_format) {
350 case GST_FORMAT_BYTES:
351 *dest_value = src_value * bytes_per_sample;
353 case GST_FORMAT_TIME:
354 if (speexenc->rate == 0)
356 *dest_value = src_value * GST_SECOND / speexenc->rate;
362 case GST_FORMAT_TIME:
363 switch (*dest_format) {
364 case GST_FORMAT_BYTES:
365 scale = bytes_per_sample;
367 case GST_FORMAT_DEFAULT:
368 *dest_value = src_value * scale * speexenc->rate / GST_SECOND;
380 static const GstQueryType *
381 gst_speexenc_get_query_types (GstPad * pad)
383 static const GstQueryType gst_speexenc_src_query_types[] = {
390 return gst_speexenc_src_query_types;
394 gst_speexenc_src_query (GstPad * pad, GstQuery * query)
397 GstSpeexEnc *speexenc;
400 speexenc = GST_SPEEXENC (gst_pad_get_parent (pad));
401 peerpad = gst_pad_get_peer (GST_PAD (speexenc->sinkpad));
403 switch (GST_QUERY_TYPE (query)) {
404 case GST_QUERY_POSITION:
406 GstFormat fmt, req_fmt;
409 gst_query_parse_position (query, &req_fmt, NULL);
410 if ((res = gst_pad_query_position (peerpad, &req_fmt, &val))) {
411 gst_query_set_position (query, req_fmt, val);
415 fmt = GST_FORMAT_TIME;
416 if (!(res = gst_pad_query_position (peerpad, &fmt, &pos)))
419 if ((res = gst_pad_query_convert (peerpad, fmt, pos, &req_fmt, &val)))
420 gst_query_set_position (query, req_fmt, val);
424 case GST_QUERY_DURATION:
426 GstFormat fmt, req_fmt;
429 gst_query_parse_duration (query, &req_fmt, NULL);
430 if ((res = gst_pad_query_duration (peerpad, &req_fmt, &val))) {
431 gst_query_set_duration (query, req_fmt, val);
435 fmt = GST_FORMAT_TIME;
436 if (!(res = gst_pad_query_duration (peerpad, &fmt, &dur)))
439 if ((res = gst_pad_query_convert (peerpad, fmt, dur, &req_fmt, &val))) {
440 gst_query_set_duration (query, req_fmt, val);
444 case GST_QUERY_CONVERT:
446 GstFormat src_fmt, dest_fmt;
447 gint64 src_val, dest_val;
449 gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, &dest_val);
450 if (!(res = gst_speexenc_convert_src (pad, src_fmt, src_val, &dest_fmt,
453 gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val);
457 res = gst_pad_query_default (pad, query);
462 gst_object_unref (peerpad);
463 gst_object_unref (speexenc);
468 gst_speexenc_sink_query (GstPad * pad, GstQuery * query)
471 GstSpeexEnc *speexenc;
473 speexenc = GST_SPEEXENC (GST_PAD_PARENT (pad));
475 switch (GST_QUERY_TYPE (query)) {
476 case GST_QUERY_CONVERT:
478 GstFormat src_fmt, dest_fmt;
479 gint64 src_val, dest_val;
481 gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, &dest_val);
483 gst_speexenc_convert_sink (pad, src_fmt, src_val, &dest_fmt,
486 gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val);
490 res = gst_pad_query_default (pad, query);
499 gst_speexenc_init (GstSpeexEnc * speexenc)
502 gst_pad_new_from_template (gst_speexenc_sink_template, "sink");
503 gst_element_add_pad (GST_ELEMENT (speexenc), speexenc->sinkpad);
504 gst_pad_set_event_function (speexenc->sinkpad, gst_speexenc_sinkevent);
505 gst_pad_set_chain_function (speexenc->sinkpad, gst_speexenc_chain);
506 gst_pad_set_setcaps_function (speexenc->sinkpad, gst_speexenc_sink_setcaps);
507 gst_pad_set_query_function (speexenc->sinkpad,
508 GST_DEBUG_FUNCPTR (gst_speexenc_sink_query));
511 gst_pad_new_from_template (gst_speexenc_src_template, "src");
512 gst_pad_set_query_function (speexenc->srcpad,
513 GST_DEBUG_FUNCPTR (gst_speexenc_src_query));
514 gst_pad_set_query_type_function (speexenc->srcpad,
515 GST_DEBUG_FUNCPTR (gst_speexenc_get_query_types));
516 gst_element_add_pad (GST_ELEMENT (speexenc), speexenc->srcpad);
518 speexenc->channels = -1;
521 speexenc->quality = DEFAULT_QUALITY;
522 speexenc->bitrate = DEFAULT_BITRATE;
523 speexenc->vbr = DEFAULT_VBR;
524 speexenc->abr = DEFAULT_ABR;
525 speexenc->vad = DEFAULT_VAD;
526 speexenc->dtx = DEFAULT_DTX;
527 speexenc->complexity = DEFAULT_COMPLEXITY;
528 speexenc->nframes = DEFAULT_NFRAMES;
530 speexenc->setup = FALSE;
531 speexenc->header_sent = FALSE;
533 speexenc->adapter = gst_adapter_new ();
537 /* FIXME: why are we not using the from/to vorbiscomment
538 * functions that are in -lgsttagedit-0.9 here? */
541 gst_speexenc_get_tag_value (const GstTagList * list, const gchar * tag,
545 gchar *speexvalue = NULL;
550 tag_type = gst_tag_get_type (tag);
552 /* get tag name right */
553 if ((strcmp (tag, GST_TAG_TRACK_NUMBER) == 0)
554 || (strcmp (tag, GST_TAG_ALBUM_VOLUME_NUMBER) == 0)
555 || (strcmp (tag, GST_TAG_TRACK_COUNT) == 0)
556 || (strcmp (tag, GST_TAG_ALBUM_VOLUME_COUNT) == 0)) {
559 if (gst_tag_list_get_uint_index (list, tag, index, &track_no)) {
560 speexvalue = g_strdup_printf ("%u", track_no);
562 GST_WARNING ("Failed to extract int tag %d for '%s'", index, tag);
564 } else if (tag_type == GST_TYPE_DATE) {
565 /* FIXME: how are dates represented in speex files? */
568 if (gst_tag_list_get_date_index (list, tag, index, &date)) {
570 g_strdup_printf ("%04d-%02d-%02d", (gint) g_date_get_year (date),
571 (gint) g_date_get_month (date), (gint) g_date_get_day (date));
574 GST_WARNING ("Failed to extract date tag %d for '%s'", index, tag);
576 } else if (tag_type == G_TYPE_STRING) {
577 if (!gst_tag_list_get_string_index (list, tag, index, &speexvalue))
578 GST_WARNING ("Failed to extract string tag %d for '%s'", index, tag);
585 * Comments will be stored in the Vorbis style.
586 * It is describled in the "Structure" section of
587 * http://www.xiph.org/ogg/vorbis/doc/v-comment.html
589 * The comment header is decoded as follows:
590 * 1) [vendor_length] = read an unsigned integer of 32 bits
591 * 2) [vendor_string] = read a UTF-8 vector as [vendor_length] octets
592 * 3) [user_comment_list_length] = read an unsigned integer of 32 bits
593 * 4) iterate [user_comment_list_length] times {
594 * 5) [length] = read an unsigned integer of 32 bits
595 * 6) this iteration's user comment = read a UTF-8 vector as [length] octets
597 * 7) [framing_bit] = read a single bit as boolean
598 * 8) if ( [framing_bit] unset or end of packet ) then ERROR
601 * If you have troubles, please write to ymnk@jcraft.com.
604 comment_init (guint8 ** comments, int *length, char *vendor_string)
606 int vendor_length = strlen (vendor_string);
607 int user_comment_list_length = 0;
608 int len = 4 + vendor_length + 4;
609 guint8 *p = g_malloc (len);
611 GST_WRITE_UINT32_LE (p, vendor_length);
612 memcpy (p + 4, vendor_string, vendor_length);
613 GST_WRITE_UINT32_LE (p + 4 + vendor_length, user_comment_list_length);
618 comment_add (guint8 ** comments, int *length, const char *tag, char *val)
620 guint8 *p = *comments;
621 int vendor_length = GST_READ_UINT32_LE (p);
622 int user_comment_list_length = GST_READ_UINT32_LE (p + 4 + vendor_length);
623 int tag_len = (tag ? strlen (tag) : 0);
624 int val_len = strlen (val);
625 int len = (*length) + 4 + tag_len + val_len;
627 p = g_realloc (p, len);
629 GST_WRITE_UINT32_LE (p + *length, tag_len + val_len); /* length of comment */
631 memcpy (p + *length + 4, (guint8 *) tag, tag_len); /* comment */
632 memcpy (p + *length + 4 + tag_len, val, val_len); /* comment */
633 GST_WRITE_UINT32_LE (p + 4 + vendor_length, user_comment_list_length + 1);
640 gst_speexenc_metadata_set1 (const GstTagList * list, const gchar * tag,
643 const gchar *speextag = NULL;
644 gchar *speexvalue = NULL;
646 GstSpeexEnc *enc = GST_SPEEXENC (speexenc);
648 speextag = gst_tag_to_vorbis_tag (tag);
649 if (speextag == NULL) {
653 count = gst_tag_list_get_tag_size (list, tag);
654 for (i = 0; i < count; i++) {
655 speexvalue = gst_speexenc_get_tag_value (list, tag, i);
657 if (speexvalue != NULL) {
658 comment_add (&enc->comments, &enc->comment_len, speextag, speexvalue);
664 gst_speexenc_set_metadata (GstSpeexEnc * speexenc)
667 const GstTagList *user_tags;
669 user_tags = gst_tag_setter_get_tag_list (GST_TAG_SETTER (speexenc));
670 if (!(speexenc->tags || user_tags))
673 comment_init (&speexenc->comments, &speexenc->comment_len,
674 "Encoded with GStreamer Speexenc");
676 gst_tag_list_merge (user_tags, speexenc->tags,
677 gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (speexenc)));
678 gst_tag_list_foreach (copy, gst_speexenc_metadata_set1, speexenc);
679 gst_tag_list_free (copy);
683 gst_speexenc_setup (GstSpeexEnc * speexenc)
685 speexenc->setup = FALSE;
687 switch (speexenc->mode) {
688 case GST_SPEEXENC_MODE_UWB:
689 speexenc->speex_mode = (SpeexMode *) & speex_uwb_mode;
691 case GST_SPEEXENC_MODE_WB:
692 speexenc->speex_mode = (SpeexMode *) & speex_wb_mode;
694 case GST_SPEEXENC_MODE_NB:
695 speexenc->speex_mode = (SpeexMode *) & speex_nb_mode;
697 case GST_SPEEXENC_MODE_AUTO:
703 if (speexenc->rate > 25000) {
704 if (speexenc->mode == GST_SPEEXENC_MODE_AUTO) {
705 speexenc->speex_mode = (SpeexMode *) & speex_uwb_mode;
707 if (speexenc->speex_mode != &speex_uwb_mode) {
708 speexenc->last_message =
710 ("Warning: suggest to use ultra wide band mode for this rate");
711 g_object_notify (G_OBJECT (speexenc), "last_message");
714 } else if (speexenc->rate > 12500) {
715 if (speexenc->mode == GST_SPEEXENC_MODE_AUTO) {
716 speexenc->speex_mode = (SpeexMode *) & speex_wb_mode;
718 if (speexenc->speex_mode != &speex_wb_mode) {
719 speexenc->last_message =
721 ("Warning: suggest to use wide band mode for this rate");
722 g_object_notify (G_OBJECT (speexenc), "last_message");
726 if (speexenc->mode == GST_SPEEXENC_MODE_AUTO) {
727 speexenc->speex_mode = (SpeexMode *) & speex_nb_mode;
729 if (speexenc->speex_mode != &speex_nb_mode) {
730 speexenc->last_message =
732 ("Warning: suggest to use narrow band mode for this rate");
733 g_object_notify (G_OBJECT (speexenc), "last_message");
738 if (speexenc->rate != 8000 && speexenc->rate != 16000
739 && speexenc->rate != 32000) {
740 speexenc->last_message =
741 g_strdup_printf ("Warning: speex is optimized for 8, 16 and 32 KHz");
742 g_object_notify (G_OBJECT (speexenc), "last_message");
745 speex_init_header (&speexenc->header, speexenc->rate, 1,
746 speexenc->speex_mode);
747 speexenc->header.frames_per_packet = speexenc->nframes;
748 speexenc->header.vbr = speexenc->vbr;
749 speexenc->header.nb_channels = speexenc->channels;
751 /*Initialize Speex encoder */
752 speexenc->state = speex_encoder_init (speexenc->speex_mode);
754 speex_encoder_ctl (speexenc->state, SPEEX_GET_FRAME_SIZE,
755 &speexenc->frame_size);
756 speex_encoder_ctl (speexenc->state, SPEEX_SET_COMPLEXITY,
757 &speexenc->complexity);
758 speex_encoder_ctl (speexenc->state, SPEEX_SET_SAMPLING_RATE, &speexenc->rate);
761 speex_encoder_ctl (speexenc->state, SPEEX_SET_VBR_QUALITY,
764 gint tmp = floor (speexenc->quality);
766 speex_encoder_ctl (speexenc->state, SPEEX_SET_QUALITY, &tmp);
768 if (speexenc->bitrate) {
769 if (speexenc->quality >= 0.0 && speexenc->vbr) {
770 speexenc->last_message =
771 g_strdup_printf ("Warning: bitrate option is overriding quality");
772 g_object_notify (G_OBJECT (speexenc), "last_message");
774 speex_encoder_ctl (speexenc->state, SPEEX_SET_BITRATE, &speexenc->bitrate);
779 speex_encoder_ctl (speexenc->state, SPEEX_SET_VBR, &tmp);
780 } else if (speexenc->vad) {
783 speex_encoder_ctl (speexenc->state, SPEEX_SET_VAD, &tmp);
789 speex_encoder_ctl (speexenc->state, SPEEX_SET_DTX, &tmp);
792 if (speexenc->dtx && !(speexenc->vbr || speexenc->abr || speexenc->vad)) {
793 speexenc->last_message =
794 g_strdup_printf ("Warning: dtx is useless without vad, vbr or abr");
795 g_object_notify (G_OBJECT (speexenc), "last_message");
796 } else if ((speexenc->vbr || speexenc->abr) && (speexenc->vad)) {
797 speexenc->last_message =
798 g_strdup_printf ("Warning: vad is already implied by vbr or abr");
799 g_object_notify (G_OBJECT (speexenc), "last_message");
803 speex_encoder_ctl (speexenc->state, SPEEX_SET_ABR, &speexenc->abr);
806 speex_encoder_ctl (speexenc->state, SPEEX_GET_LOOKAHEAD,
807 &speexenc->lookahead);
809 speexenc->setup = TRUE;
814 /* prepare a buffer for transmission */
816 gst_speexenc_buffer_from_data (GstSpeexEnc * speexenc, guchar * data,
817 gint data_len, guint64 granulepos)
821 outbuf = gst_buffer_new_and_alloc (data_len);
822 memcpy (GST_BUFFER_DATA (outbuf), data, data_len);
823 GST_BUFFER_OFFSET (outbuf) = speexenc->bytes_out;
824 GST_BUFFER_OFFSET_END (outbuf) = granulepos;
826 GST_DEBUG ("encoded buffer of %d bytes", GST_BUFFER_SIZE (outbuf));
831 /* push out the buffer and do internal bookkeeping */
833 gst_speexenc_push_buffer (GstSpeexEnc * speexenc, GstBuffer * buffer)
835 speexenc->bytes_out += GST_BUFFER_SIZE (buffer);
837 return gst_pad_push (speexenc->srcpad, buffer);
842 gst_speexenc_set_header_on_caps (GstCaps * caps, GstBuffer * buf1,
845 GstStructure *structure = NULL;
846 GValue array = { 0 };
847 GValue value = { 0 };
849 caps = gst_caps_make_writable (caps);
850 structure = gst_caps_get_structure (caps, 0);
853 GST_BUFFER_FLAG_SET (buf1, GST_BUFFER_FLAG_IN_CAPS);
854 GST_BUFFER_FLAG_SET (buf2, GST_BUFFER_FLAG_IN_CAPS);
856 /* put buffers in a fixed list */
857 g_value_init (&array, GST_TYPE_ARRAY);
858 g_value_init (&value, GST_TYPE_BUFFER);
859 gst_value_set_buffer (&value, buf1);
860 gst_value_array_append_value (&array, &value);
861 g_value_unset (&value);
862 g_value_init (&value, GST_TYPE_BUFFER);
863 gst_value_set_buffer (&value, buf2);
864 gst_value_array_append_value (&array, &value);
865 gst_structure_set_value (structure, "streamheader", &array);
866 g_value_unset (&value);
867 g_value_unset (&array);
874 gst_speexenc_sinkevent (GstPad * pad, GstEvent * event)
877 GstSpeexEnc *speexenc;
879 speexenc = GST_SPEEXENC (GST_PAD_PARENT (pad));
881 switch (GST_EVENT_TYPE (event)) {
883 speexenc->eos = TRUE;
884 res = gst_pad_event_default (pad, event);
890 gst_event_parse_tag (event, &list);
891 if (speexenc->tags) {
892 gst_tag_list_insert (speexenc->tags, list,
893 gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (speexenc)));
895 g_assert_not_reached ();
897 res = gst_pad_event_default (pad, event);
901 res = gst_pad_event_default (pad, event);
909 gst_speexenc_chain (GstPad * pad, GstBuffer * buf)
911 GstSpeexEnc *speexenc;
912 GstFlowReturn ret = GST_FLOW_OK;
914 speexenc = GST_SPEEXENC (gst_pad_get_parent (pad));
916 if (!speexenc->setup)
919 if (!speexenc->header_sent) {
920 /* Speex streams begin with two headers; the initial header (with
921 most of the codec setup parameters) which is mandated by the Ogg
922 bitstream spec. The second header holds any comment fields.
923 We merely need to make the headers, then pass them to libspeex
924 one at a time; libspeex handles the additional Ogg bitstream
926 GstBuffer *buf1, *buf2;
931 gst_speexenc_set_metadata (speexenc);
933 /* create header buffer */
934 data = (guint8 *) speex_header_to_packet (&speexenc->header, &data_len);
935 buf1 = gst_speexenc_buffer_from_data (speexenc, data, data_len, 0);
937 /* create comment buffer */
939 gst_speexenc_buffer_from_data (speexenc, speexenc->comments,
940 speexenc->comment_len, 0);
942 /* mark and put on caps */
943 caps = gst_pad_get_caps (speexenc->srcpad);
944 caps = gst_speexenc_set_header_on_caps (caps, buf1, buf2);
946 /* negotiate with these caps */
947 GST_DEBUG ("here are the caps: %" GST_PTR_FORMAT, caps);
948 gst_pad_set_caps (speexenc->srcpad, caps);
950 gst_buffer_set_caps (buf1, caps);
951 gst_buffer_set_caps (buf2, caps);
953 /* push out buffers */
954 ret = gst_speexenc_push_buffer (speexenc, buf1);
956 if ((GST_FLOW_OK != ret) && (GST_FLOW_NOT_LINKED != ret)) {
957 /* unref buf2 as we are not going to push it anymore */
959 gst_buffer_unref (buf2);
963 ret = gst_speexenc_push_buffer (speexenc, buf2);
965 if ((GST_FLOW_OK != ret) && (GST_FLOW_NOT_LINKED != ret))
968 speex_bits_init (&speexenc->bits);
969 speex_bits_reset (&speexenc->bits);
971 speexenc->header_sent = TRUE;
975 gint frame_size = speexenc->frame_size;
976 gint bytes = frame_size * 2 * speexenc->channels;
978 /* push buffer to adapter */
979 gst_adapter_push (speexenc->adapter, buf);
981 while (gst_adapter_available (speexenc->adapter) >= bytes) {
984 gint outsize, written;
987 data = (gint16 *) gst_adapter_peek (speexenc->adapter, bytes);
989 for (i = 0; i < frame_size * speexenc->channels; i++) {
990 speexenc->input[i] = (gfloat) data[i];
992 gst_adapter_flush (speexenc->adapter, bytes);
994 speexenc->samples_in += frame_size;
996 if (speexenc->channels == 2) {
997 speex_encode_stereo (speexenc->input, frame_size, &speexenc->bits);
999 speex_encode (speexenc->state, speexenc->input, &speexenc->bits);
1001 speexenc->frameno++;
1003 if ((speexenc->frameno % speexenc->nframes) != 0)
1006 speex_bits_insert_terminator (&speexenc->bits);
1007 outsize = speex_bits_nbytes (&speexenc->bits);
1009 ret = gst_pad_alloc_buffer_and_set_caps (speexenc->srcpad,
1010 GST_BUFFER_OFFSET_NONE, outsize, GST_PAD_CAPS (speexenc->srcpad),
1013 if ((GST_FLOW_OK != ret))
1016 written = speex_bits_write (&speexenc->bits,
1017 (gchar *) GST_BUFFER_DATA (outbuf), outsize);
1018 g_assert (written == outsize);
1019 speex_bits_reset (&speexenc->bits);
1021 GST_BUFFER_TIMESTAMP (outbuf) =
1022 gst_util_uint64_scale_int (speexenc->frameno * frame_size -
1023 speexenc->lookahead, GST_SECOND, speexenc->rate);
1024 GST_BUFFER_DURATION (outbuf) = gst_util_uint64_scale_int (frame_size,
1025 GST_SECOND, speexenc->rate);
1026 /* set gp time and granulepos; see gst-plugins-base/ext/ogg/README */
1027 GST_BUFFER_OFFSET_END (outbuf) =
1028 ((speexenc->frameno + 1) * frame_size - speexenc->lookahead);
1029 GST_BUFFER_OFFSET (outbuf) =
1030 gst_util_uint64_scale_int (GST_BUFFER_OFFSET_END (outbuf), GST_SECOND,
1033 ret = gst_speexenc_push_buffer (speexenc, outbuf);
1035 if ((GST_FLOW_OK != ret) && (GST_FLOW_NOT_LINKED != ret))
1041 gst_object_unref (speexenc);
1047 gst_buffer_unref (buf);
1048 GST_ELEMENT_ERROR (speexenc, CORE, NEGOTIATION, (NULL),
1049 ("encoder not initialized (input is not audio?)"));
1050 ret = GST_FLOW_NOT_NEGOTIATED;
1058 gst_speexenc_get_property (GObject * object, guint prop_id, GValue * value,
1061 GstSpeexEnc *speexenc;
1063 g_return_if_fail (GST_IS_SPEEXENC (object));
1065 speexenc = GST_SPEEXENC (object);
1069 g_value_set_float (value, speexenc->quality);
1072 g_value_set_int (value, speexenc->bitrate);
1075 g_value_set_boolean (value, speexenc->vbr);
1078 g_value_set_int (value, speexenc->abr);
1081 g_value_set_boolean (value, speexenc->vad);
1084 g_value_set_boolean (value, speexenc->dtx);
1086 case ARG_COMPLEXITY:
1087 g_value_set_int (value, speexenc->complexity);
1090 g_value_set_int (value, speexenc->nframes);
1092 case ARG_LAST_MESSAGE:
1093 g_value_set_string (value, speexenc->last_message);
1096 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1102 gst_speexenc_set_property (GObject * object, guint prop_id,
1103 const GValue * value, GParamSpec * pspec)
1105 GstSpeexEnc *speexenc;
1107 g_return_if_fail (GST_IS_SPEEXENC (object));
1109 speexenc = GST_SPEEXENC (object);
1113 speexenc->quality = g_value_get_float (value);
1116 speexenc->bitrate = g_value_get_int (value);
1119 speexenc->vbr = g_value_get_boolean (value);
1122 speexenc->abr = g_value_get_int (value);
1125 speexenc->vad = g_value_get_boolean (value);
1128 speexenc->dtx = g_value_get_boolean (value);
1130 case ARG_COMPLEXITY:
1131 speexenc->complexity = g_value_get_int (value);
1134 speexenc->nframes = g_value_get_int (value);
1137 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1142 static GstStateChangeReturn
1143 gst_speexenc_change_state (GstElement * element, GstStateChange transition)
1145 GstSpeexEnc *speexenc = GST_SPEEXENC (element);
1146 GstStateChangeReturn res;
1148 switch (transition) {
1149 case GST_STATE_CHANGE_NULL_TO_READY:
1150 speexenc->tags = gst_tag_list_new ();
1152 case GST_STATE_CHANGE_READY_TO_PAUSED:
1153 speexenc->frameno = 0;
1154 speexenc->samples_in = 0;
1156 case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
1162 res = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1164 switch (transition) {
1165 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
1167 case GST_STATE_CHANGE_PAUSED_TO_READY:
1168 speexenc->setup = FALSE;
1169 speexenc->header_sent = FALSE;
1171 case GST_STATE_CHANGE_READY_TO_NULL:
1172 gst_tag_list_free (speexenc->tags);
1173 speexenc->tags = NULL;