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 = {
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
79 static const GstFormat *
80 gst_speexenc_get_formats (GstPad * pad)
82 static const GstFormat src_formats[] = {
87 static const GstFormat sink_formats[] = {
94 return (GST_PAD_IS_SRC (pad) ? src_formats : sink_formats);
98 static void gst_speexenc_base_init (gpointer g_class);
99 static void gst_speexenc_class_init (GstSpeexEncClass * klass);
100 static void gst_speexenc_init (GstSpeexEnc * speexenc);
101 static void gst_speexenc_finalize (GObject * object);
103 static gboolean gst_speexenc_sinkevent (GstPad * pad, GstEvent * event);
104 static GstFlowReturn gst_speexenc_chain (GstPad * pad, GstBuffer * buf);
105 static gboolean gst_speexenc_setup (GstSpeexEnc * speexenc);
107 static void gst_speexenc_get_property (GObject * object, guint prop_id,
108 GValue * value, GParamSpec * pspec);
109 static void gst_speexenc_set_property (GObject * object, guint prop_id,
110 const GValue * value, GParamSpec * pspec);
111 static GstStateChangeReturn gst_speexenc_change_state (GstElement * element,
112 GstStateChange transition);
114 static GstElementClass *parent_class = NULL;
116 /*static guint gst_speexenc_signals[LAST_SIGNAL] = { 0 }; */
119 gst_speexenc_get_type (void)
121 static GType speexenc_type = 0;
123 if (!speexenc_type) {
124 static const GTypeInfo speexenc_info = {
125 sizeof (GstSpeexEncClass),
126 gst_speexenc_base_init,
128 (GClassInitFunc) gst_speexenc_class_init,
131 sizeof (GstSpeexEnc),
133 (GInstanceInitFunc) gst_speexenc_init,
135 static const GInterfaceInfo tag_setter_info = {
142 g_type_register_static (GST_TYPE_ELEMENT, "GstSpeexEnc", &speexenc_info,
145 g_type_add_interface_static (speexenc_type, GST_TYPE_TAG_SETTER,
148 GST_DEBUG_CATEGORY_INIT (speexenc_debug, "speexenc", 0, "Speex encoder");
150 return speexenc_type;
154 speex_caps_factory (void)
156 return gst_caps_new_simple ("audio/x-speex", NULL);
160 raw_caps_factory (void)
163 gst_caps_new_simple ("audio/x-raw-int",
164 "rate", GST_TYPE_INT_RANGE, 6000, 48000,
165 "channels", GST_TYPE_INT_RANGE, 1, 2,
166 "endianness", G_TYPE_INT, G_BYTE_ORDER,
167 "signed", G_TYPE_BOOLEAN, TRUE,
168 "width", G_TYPE_INT, 16, "depth", G_TYPE_INT, 16, NULL);
172 gst_speexenc_base_init (gpointer g_class)
174 GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
175 GstCaps *raw_caps, *speex_caps;
177 raw_caps = raw_caps_factory ();
178 speex_caps = speex_caps_factory ();
180 gst_speexenc_sink_template = gst_pad_template_new ("sink", GST_PAD_SINK,
181 GST_PAD_ALWAYS, raw_caps);
182 gst_speexenc_src_template = gst_pad_template_new ("src", GST_PAD_SRC,
183 GST_PAD_ALWAYS, speex_caps);
184 gst_element_class_add_pad_template (element_class,
185 gst_speexenc_sink_template);
186 gst_element_class_add_pad_template (element_class, gst_speexenc_src_template);
187 gst_element_class_set_details (element_class, &speexenc_details);
191 gst_speexenc_class_init (GstSpeexEncClass * klass)
193 GObjectClass *gobject_class;
194 GstElementClass *gstelement_class;
196 gobject_class = (GObjectClass *) klass;
197 gstelement_class = (GstElementClass *) klass;
199 gobject_class->set_property = gst_speexenc_set_property;
200 gobject_class->get_property = gst_speexenc_get_property;
202 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_QUALITY,
203 g_param_spec_float ("quality", "Quality", "Encoding quality",
204 0.0, 10.0, DEFAULT_QUALITY, G_PARAM_READWRITE));
205 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_BITRATE,
206 g_param_spec_int ("bitrate", "Encoding Bit-rate",
207 "Specify an encoding bit-rate (in bps). (0 = automatic)",
208 0, G_MAXINT, DEFAULT_BITRATE, G_PARAM_READWRITE));
209 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_VBR,
210 g_param_spec_boolean ("vbr", "VBR",
211 "Enable variable bit-rate", DEFAULT_VBR, G_PARAM_READWRITE));
212 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_ABR,
213 g_param_spec_int ("abr", "ABR",
214 "Enable average bit-rate (0 = disabled)",
215 0, G_MAXINT, DEFAULT_ABR, G_PARAM_READWRITE));
216 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_VAD,
217 g_param_spec_boolean ("vad", "VAD",
218 "Enable voice activity detection", DEFAULT_VAD, G_PARAM_READWRITE));
219 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_DTX,
220 g_param_spec_boolean ("dtx", "DTX",
221 "Enable discontinuous transmission", DEFAULT_DTX, G_PARAM_READWRITE));
222 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_COMPLEXITY,
223 g_param_spec_int ("complexity", "Complexity",
224 "Set encoding complexity",
225 0, G_MAXINT, DEFAULT_COMPLEXITY, G_PARAM_READWRITE));
226 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_NFRAMES,
227 g_param_spec_int ("nframes", "NFrames",
228 "Number of frames per buffer",
229 0, G_MAXINT, DEFAULT_NFRAMES, G_PARAM_READWRITE));
230 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_LAST_MESSAGE,
231 g_param_spec_string ("last-message", "last-message",
232 "The last status message", NULL, G_PARAM_READABLE));
234 parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
236 gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_speexenc_finalize);
238 gstelement_class->change_state =
239 GST_DEBUG_FUNCPTR (gst_speexenc_change_state);
243 gst_speexenc_finalize (GObject * object)
245 GstSpeexEnc *speexenc;
247 speexenc = GST_SPEEXENC (object);
249 g_object_unref (speexenc->adapter);
251 G_OBJECT_CLASS (parent_class)->finalize (object);
255 gst_speexenc_sink_setcaps (GstPad * pad, GstCaps * caps)
257 GstSpeexEnc *speexenc;
258 GstStructure *structure;
260 speexenc = GST_SPEEXENC (gst_pad_get_parent (pad));
261 speexenc->setup = FALSE;
263 structure = gst_caps_get_structure (caps, 0);
264 gst_structure_get_int (structure, "channels", &speexenc->channels);
265 gst_structure_get_int (structure, "rate", &speexenc->rate);
267 gst_speexenc_setup (speexenc);
269 gst_object_unref (speexenc);
271 return speexenc->setup;
275 gst_speexenc_convert_src (GstPad * pad, GstFormat src_format, gint64 src_value,
276 GstFormat * dest_format, gint64 * dest_value)
279 GstSpeexEnc *speexenc;
282 speexenc = GST_SPEEXENC (GST_PAD_PARENT (pad));
284 if (speexenc->samples_in == 0 ||
285 speexenc->bytes_out == 0 || speexenc->rate == 0)
288 avg = (speexenc->bytes_out * speexenc->rate) / (speexenc->samples_in);
290 switch (src_format) {
291 case GST_FORMAT_BYTES:
292 switch (*dest_format) {
293 case GST_FORMAT_TIME:
294 *dest_value = src_value * GST_SECOND / avg;
300 case GST_FORMAT_TIME:
301 switch (*dest_format) {
302 case GST_FORMAT_BYTES:
303 *dest_value = src_value * avg / GST_SECOND;
316 gst_speexenc_convert_sink (GstPad * pad, GstFormat src_format,
317 gint64 src_value, GstFormat * dest_format, gint64 * dest_value)
321 gint bytes_per_sample;
322 GstSpeexEnc *speexenc;
324 speexenc = GST_SPEEXENC (GST_PAD_PARENT (pad));
326 bytes_per_sample = speexenc->channels * 2;
328 switch (src_format) {
329 case GST_FORMAT_BYTES:
330 switch (*dest_format) {
331 case GST_FORMAT_DEFAULT:
332 if (bytes_per_sample == 0)
334 *dest_value = src_value / bytes_per_sample;
336 case GST_FORMAT_TIME:
338 gint byterate = bytes_per_sample * speexenc->rate;
342 *dest_value = src_value * GST_SECOND / byterate;
349 case GST_FORMAT_DEFAULT:
350 switch (*dest_format) {
351 case GST_FORMAT_BYTES:
352 *dest_value = src_value * bytes_per_sample;
354 case GST_FORMAT_TIME:
355 if (speexenc->rate == 0)
357 *dest_value = src_value * GST_SECOND / speexenc->rate;
363 case GST_FORMAT_TIME:
364 switch (*dest_format) {
365 case GST_FORMAT_BYTES:
366 scale = bytes_per_sample;
368 case GST_FORMAT_DEFAULT:
369 *dest_value = src_value * scale * speexenc->rate / GST_SECOND;
381 static const GstQueryType *
382 gst_speexenc_get_query_types (GstPad * pad)
384 static const GstQueryType gst_speexenc_src_query_types[] = {
391 return gst_speexenc_src_query_types;
395 gst_speexenc_src_query (GstPad * pad, GstQuery * query)
398 GstSpeexEnc *speexenc;
401 speexenc = GST_SPEEXENC (gst_pad_get_parent (pad));
402 peerpad = gst_pad_get_peer (GST_PAD (speexenc->sinkpad));
404 switch (GST_QUERY_TYPE (query)) {
405 case GST_QUERY_POSITION:
407 GstFormat fmt, req_fmt;
410 gst_query_parse_position (query, &req_fmt, NULL);
411 if ((res = gst_pad_query_position (peerpad, &req_fmt, &val))) {
412 gst_query_set_position (query, req_fmt, val);
416 fmt = GST_FORMAT_TIME;
417 if (!(res = gst_pad_query_position (peerpad, &fmt, &pos)))
420 if ((res = gst_pad_query_convert (peerpad, fmt, pos, &req_fmt, &val)))
421 gst_query_set_position (query, req_fmt, val);
425 case GST_QUERY_DURATION:
427 GstFormat fmt, req_fmt;
430 gst_query_parse_duration (query, &req_fmt, NULL);
431 if ((res = gst_pad_query_duration (peerpad, &req_fmt, &val))) {
432 gst_query_set_duration (query, req_fmt, val);
436 fmt = GST_FORMAT_TIME;
437 if (!(res = gst_pad_query_duration (peerpad, &fmt, &dur)))
440 if ((res = gst_pad_query_convert (peerpad, fmt, dur, &req_fmt, &val))) {
441 gst_query_set_duration (query, req_fmt, val);
445 case GST_QUERY_CONVERT:
447 GstFormat src_fmt, dest_fmt;
448 gint64 src_val, dest_val;
450 gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, &dest_val);
451 if (!(res = gst_speexenc_convert_src (pad, src_fmt, src_val, &dest_fmt,
454 gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val);
458 res = gst_pad_query_default (pad, query);
463 gst_object_unref (peerpad);
464 gst_object_unref (speexenc);
469 gst_speexenc_sink_query (GstPad * pad, GstQuery * query)
472 GstSpeexEnc *speexenc;
474 speexenc = GST_SPEEXENC (GST_PAD_PARENT (pad));
476 switch (GST_QUERY_TYPE (query)) {
477 case GST_QUERY_CONVERT:
479 GstFormat src_fmt, dest_fmt;
480 gint64 src_val, dest_val;
482 gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, &dest_val);
484 gst_speexenc_convert_sink (pad, src_fmt, src_val, &dest_fmt,
487 gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val);
491 res = gst_pad_query_default (pad, query);
500 gst_speexenc_init (GstSpeexEnc * speexenc)
503 gst_pad_new_from_template (gst_speexenc_sink_template, "sink");
504 gst_element_add_pad (GST_ELEMENT (speexenc), speexenc->sinkpad);
505 gst_pad_set_event_function (speexenc->sinkpad, gst_speexenc_sinkevent);
506 gst_pad_set_chain_function (speexenc->sinkpad, gst_speexenc_chain);
507 gst_pad_set_setcaps_function (speexenc->sinkpad, gst_speexenc_sink_setcaps);
508 gst_pad_set_query_function (speexenc->sinkpad,
509 GST_DEBUG_FUNCPTR (gst_speexenc_sink_query));
512 gst_pad_new_from_template (gst_speexenc_src_template, "src");
513 gst_pad_set_query_function (speexenc->srcpad,
514 GST_DEBUG_FUNCPTR (gst_speexenc_src_query));
515 gst_pad_set_query_type_function (speexenc->srcpad,
516 GST_DEBUG_FUNCPTR (gst_speexenc_get_query_types));
517 gst_element_add_pad (GST_ELEMENT (speexenc), speexenc->srcpad);
519 speexenc->channels = -1;
522 speexenc->quality = DEFAULT_QUALITY;
523 speexenc->bitrate = DEFAULT_BITRATE;
524 speexenc->vbr = DEFAULT_VBR;
525 speexenc->abr = DEFAULT_ABR;
526 speexenc->vad = DEFAULT_VAD;
527 speexenc->dtx = DEFAULT_DTX;
528 speexenc->complexity = DEFAULT_COMPLEXITY;
529 speexenc->nframes = DEFAULT_NFRAMES;
531 speexenc->setup = FALSE;
532 speexenc->header_sent = FALSE;
534 speexenc->adapter = gst_adapter_new ();
538 /* FIXME: why are we not using the from/to vorbiscomment
539 * functions that are in -lgsttagedit-0.9 here? */
542 gst_speexenc_get_tag_value (const GstTagList * list, const gchar * tag,
546 gchar *speexvalue = NULL;
551 tag_type = gst_tag_get_type (tag);
553 /* get tag name right */
554 if ((strcmp (tag, GST_TAG_TRACK_NUMBER) == 0)
555 || (strcmp (tag, GST_TAG_ALBUM_VOLUME_NUMBER) == 0)
556 || (strcmp (tag, GST_TAG_TRACK_COUNT) == 0)
557 || (strcmp (tag, GST_TAG_ALBUM_VOLUME_COUNT) == 0)) {
560 if (gst_tag_list_get_uint_index (list, tag, index, &track_no)) {
561 speexvalue = g_strdup_printf ("%u", track_no);
563 GST_WARNING ("Failed to extract int tag %d for '%s'", index, tag);
565 } else if (tag_type == GST_TYPE_DATE) {
566 /* FIXME: how are dates represented in speex files? */
569 if (gst_tag_list_get_date_index (list, tag, index, &date)) {
571 g_strdup_printf ("%04d-%02d-%02d", (gint) g_date_get_year (date),
572 (gint) g_date_get_month (date), (gint) g_date_get_day (date));
575 GST_WARNING ("Failed to extract date tag %d for '%s'", index, tag);
577 } else if (tag_type == G_TYPE_STRING) {
578 if (!gst_tag_list_get_string_index (list, tag, index, &speexvalue))
579 GST_WARNING ("Failed to extract string tag %d for '%s'", index, tag);
586 * Comments will be stored in the Vorbis style.
587 * It is describled in the "Structure" section of
588 * http://www.xiph.org/ogg/vorbis/doc/v-comment.html
590 * The comment header is decoded as follows:
591 * 1) [vendor_length] = read an unsigned integer of 32 bits
592 * 2) [vendor_string] = read a UTF-8 vector as [vendor_length] octets
593 * 3) [user_comment_list_length] = read an unsigned integer of 32 bits
594 * 4) iterate [user_comment_list_length] times {
595 * 5) [length] = read an unsigned integer of 32 bits
596 * 6) this iteration's user comment = read a UTF-8 vector as [length] octets
598 * 7) [framing_bit] = read a single bit as boolean
599 * 8) if ( [framing_bit] unset or end of packet ) then ERROR
602 * If you have troubles, please write to ymnk@jcraft.com.
605 comment_init (guint8 ** comments, int *length, char *vendor_string)
607 int vendor_length = strlen (vendor_string);
608 int user_comment_list_length = 0;
609 int len = 4 + vendor_length + 4;
610 guint8 *p = g_malloc (len);
612 GST_WRITE_UINT32_LE (p, vendor_length);
613 memcpy (p + 4, vendor_string, vendor_length);
614 GST_WRITE_UINT32_LE (p + 4 + vendor_length, user_comment_list_length);
619 comment_add (guint8 ** comments, int *length, const char *tag, char *val)
621 guint8 *p = *comments;
622 int vendor_length = GST_READ_UINT32_LE (p);
623 int user_comment_list_length = GST_READ_UINT32_LE (p + 4 + vendor_length);
624 int tag_len = (tag ? strlen (tag) : 0);
625 int val_len = strlen (val);
626 int len = (*length) + 4 + tag_len + val_len;
628 p = g_realloc (p, len);
630 GST_WRITE_UINT32_LE (p + *length, tag_len + val_len); /* length of comment */
632 memcpy (p + *length + 4, (guint8 *) tag, tag_len); /* comment */
633 memcpy (p + *length + 4 + tag_len, val, val_len); /* comment */
634 GST_WRITE_UINT32_LE (p + 4 + vendor_length, user_comment_list_length + 1);
641 gst_speexenc_metadata_set1 (const GstTagList * list, const gchar * tag,
644 const gchar *speextag = NULL;
645 gchar *speexvalue = NULL;
647 GstSpeexEnc *enc = GST_SPEEXENC (speexenc);
649 speextag = gst_tag_to_vorbis_tag (tag);
650 if (speextag == NULL) {
654 count = gst_tag_list_get_tag_size (list, tag);
655 for (i = 0; i < count; i++) {
656 speexvalue = gst_speexenc_get_tag_value (list, tag, i);
658 if (speexvalue != NULL) {
659 comment_add (&enc->comments, &enc->comment_len, speextag, speexvalue);
665 gst_speexenc_set_metadata (GstSpeexEnc * speexenc)
668 const GstTagList *user_tags;
670 user_tags = gst_tag_setter_get_tag_list (GST_TAG_SETTER (speexenc));
671 if (!(speexenc->tags || user_tags))
674 comment_init (&speexenc->comments, &speexenc->comment_len,
675 "Encoded with GStreamer Speexenc");
677 gst_tag_list_merge (user_tags, speexenc->tags,
678 gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (speexenc)));
679 gst_tag_list_foreach (copy, gst_speexenc_metadata_set1, speexenc);
680 gst_tag_list_free (copy);
684 gst_speexenc_setup (GstSpeexEnc * speexenc)
686 speexenc->setup = FALSE;
688 switch (speexenc->mode) {
689 case GST_SPEEXENC_MODE_UWB:
690 speexenc->speex_mode = (SpeexMode *) & speex_uwb_mode;
692 case GST_SPEEXENC_MODE_WB:
693 speexenc->speex_mode = (SpeexMode *) & speex_wb_mode;
695 case GST_SPEEXENC_MODE_NB:
696 speexenc->speex_mode = (SpeexMode *) & speex_nb_mode;
698 case GST_SPEEXENC_MODE_AUTO:
704 if (speexenc->rate > 25000) {
705 if (speexenc->mode == GST_SPEEXENC_MODE_AUTO) {
706 speexenc->speex_mode = (SpeexMode *) & speex_uwb_mode;
708 if (speexenc->speex_mode != &speex_uwb_mode) {
709 speexenc->last_message =
711 ("Warning: suggest to use ultra wide band mode for this rate");
712 g_object_notify (G_OBJECT (speexenc), "last_message");
715 } else if (speexenc->rate > 12500) {
716 if (speexenc->mode == GST_SPEEXENC_MODE_AUTO) {
717 speexenc->speex_mode = (SpeexMode *) & speex_wb_mode;
719 if (speexenc->speex_mode != &speex_wb_mode) {
720 speexenc->last_message =
722 ("Warning: suggest to use wide band mode for this rate");
723 g_object_notify (G_OBJECT (speexenc), "last_message");
727 if (speexenc->mode == GST_SPEEXENC_MODE_AUTO) {
728 speexenc->speex_mode = (SpeexMode *) & speex_nb_mode;
730 if (speexenc->speex_mode != &speex_nb_mode) {
731 speexenc->last_message =
733 ("Warning: suggest to use narrow band mode for this rate");
734 g_object_notify (G_OBJECT (speexenc), "last_message");
739 if (speexenc->rate != 8000 && speexenc->rate != 16000
740 && speexenc->rate != 32000) {
741 speexenc->last_message =
742 g_strdup_printf ("Warning: speex is optimized for 8, 16 and 32 KHz");
743 g_object_notify (G_OBJECT (speexenc), "last_message");
746 speex_init_header (&speexenc->header, speexenc->rate, 1,
747 speexenc->speex_mode);
748 speexenc->header.frames_per_packet = speexenc->nframes;
749 speexenc->header.vbr = speexenc->vbr;
750 speexenc->header.nb_channels = speexenc->channels;
752 /*Initialize Speex encoder */
753 speexenc->state = speex_encoder_init (speexenc->speex_mode);
755 speex_encoder_ctl (speexenc->state, SPEEX_GET_FRAME_SIZE,
756 &speexenc->frame_size);
757 speex_encoder_ctl (speexenc->state, SPEEX_SET_COMPLEXITY,
758 &speexenc->complexity);
759 speex_encoder_ctl (speexenc->state, SPEEX_SET_SAMPLING_RATE, &speexenc->rate);
762 speex_encoder_ctl (speexenc->state, SPEEX_SET_VBR_QUALITY,
765 gint tmp = floor (speexenc->quality);
767 speex_encoder_ctl (speexenc->state, SPEEX_SET_QUALITY, &tmp);
769 if (speexenc->bitrate) {
770 if (speexenc->quality >= 0.0 && speexenc->vbr) {
771 speexenc->last_message =
772 g_strdup_printf ("Warning: bitrate option is overriding quality");
773 g_object_notify (G_OBJECT (speexenc), "last_message");
775 speex_encoder_ctl (speexenc->state, SPEEX_SET_BITRATE, &speexenc->bitrate);
780 speex_encoder_ctl (speexenc->state, SPEEX_SET_VBR, &tmp);
781 } else if (speexenc->vad) {
784 speex_encoder_ctl (speexenc->state, SPEEX_SET_VAD, &tmp);
790 speex_encoder_ctl (speexenc->state, SPEEX_SET_DTX, &tmp);
793 if (speexenc->dtx && !(speexenc->vbr || speexenc->abr || speexenc->vad)) {
794 speexenc->last_message =
795 g_strdup_printf ("Warning: dtx is useless without vad, vbr or abr");
796 g_object_notify (G_OBJECT (speexenc), "last_message");
797 } else if ((speexenc->vbr || speexenc->abr) && (speexenc->vad)) {
798 speexenc->last_message =
799 g_strdup_printf ("Warning: vad is already implied by vbr or abr");
800 g_object_notify (G_OBJECT (speexenc), "last_message");
804 speex_encoder_ctl (speexenc->state, SPEEX_SET_ABR, &speexenc->abr);
807 speex_encoder_ctl (speexenc->state, SPEEX_GET_LOOKAHEAD,
808 &speexenc->lookahead);
810 speexenc->setup = TRUE;
815 /* prepare a buffer for transmission */
817 gst_speexenc_buffer_from_data (GstSpeexEnc * speexenc, guchar * data,
818 gint data_len, guint64 granulepos)
822 outbuf = gst_buffer_new_and_alloc (data_len);
823 memcpy (GST_BUFFER_DATA (outbuf), data, data_len);
824 GST_BUFFER_OFFSET (outbuf) = speexenc->bytes_out;
825 GST_BUFFER_OFFSET_END (outbuf) = granulepos;
827 GST_DEBUG ("encoded buffer of %d bytes", GST_BUFFER_SIZE (outbuf));
832 /* push out the buffer and do internal bookkeeping */
834 gst_speexenc_push_buffer (GstSpeexEnc * speexenc, GstBuffer * buffer)
836 speexenc->bytes_out += GST_BUFFER_SIZE (buffer);
838 return gst_pad_push (speexenc->srcpad, buffer);
843 gst_speexenc_set_header_on_caps (GstCaps * caps, GstBuffer * buf1,
846 caps = gst_caps_make_writable (caps);
847 GstStructure *structure = gst_caps_get_structure (caps, 0);
848 GValue array = { 0 };
849 GValue value = { 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;