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);
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_ref (GST_TYPE_ELEMENT);
235 gstelement_class->change_state = gst_speexenc_change_state;
239 gst_speexenc_sink_setcaps (GstPad * pad, GstCaps * caps)
241 GstSpeexEnc *speexenc;
242 GstStructure *structure;
244 speexenc = GST_SPEEXENC (GST_PAD_PARENT (pad));
245 speexenc->setup = FALSE;
247 structure = gst_caps_get_structure (caps, 0);
248 gst_structure_get_int (structure, "channels", &speexenc->channels);
249 gst_structure_get_int (structure, "rate", &speexenc->rate);
251 gst_speexenc_setup (speexenc);
260 gst_speexenc_convert_src (GstPad * pad, GstFormat src_format, gint64 src_value,
261 GstFormat * dest_format, gint64 * dest_value)
264 GstSpeexEnc *speexenc;
267 speexenc = GST_SPEEXENC (GST_PAD_PARENT (pad));
269 if (speexenc->samples_in == 0 ||
270 speexenc->bytes_out == 0 || speexenc->rate == 0)
273 avg = (speexenc->bytes_out * speexenc->rate) / (speexenc->samples_in);
275 switch (src_format) {
276 case GST_FORMAT_BYTES:
277 switch (*dest_format) {
278 case GST_FORMAT_TIME:
279 *dest_value = src_value * GST_SECOND / avg;
285 case GST_FORMAT_TIME:
286 switch (*dest_format) {
287 case GST_FORMAT_BYTES:
288 *dest_value = src_value * avg / GST_SECOND;
301 gst_speexenc_convert_sink (GstPad * pad, GstFormat src_format,
302 gint64 src_value, GstFormat * dest_format, gint64 * dest_value)
306 gint bytes_per_sample;
307 GstSpeexEnc *speexenc;
309 speexenc = GST_SPEEXENC (GST_PAD_PARENT (pad));
311 bytes_per_sample = speexenc->channels * 2;
313 switch (src_format) {
314 case GST_FORMAT_BYTES:
315 switch (*dest_format) {
316 case GST_FORMAT_DEFAULT:
317 if (bytes_per_sample == 0)
319 *dest_value = src_value / bytes_per_sample;
321 case GST_FORMAT_TIME:
323 gint byterate = bytes_per_sample * speexenc->rate;
327 *dest_value = src_value * GST_SECOND / byterate;
334 case GST_FORMAT_DEFAULT:
335 switch (*dest_format) {
336 case GST_FORMAT_BYTES:
337 *dest_value = src_value * bytes_per_sample;
339 case GST_FORMAT_TIME:
340 if (speexenc->rate == 0)
342 *dest_value = src_value * GST_SECOND / speexenc->rate;
348 case GST_FORMAT_TIME:
349 switch (*dest_format) {
350 case GST_FORMAT_BYTES:
351 scale = bytes_per_sample;
353 case GST_FORMAT_DEFAULT:
354 *dest_value = src_value * scale * speexenc->rate / GST_SECOND;
366 static const GstQueryType *
367 gst_speexenc_get_query_types (GstPad * pad)
369 static const GstQueryType gst_speexenc_src_query_types[] = {
374 return gst_speexenc_src_query_types;
378 gst_speexenc_src_query (GstPad * pad, GstQuery * query)
381 GstSpeexEnc *speexenc;
383 speexenc = GST_SPEEXENC (GST_PAD_PARENT (pad));
385 switch (GST_QUERY_TYPE (query)) {
386 case GST_QUERY_POSITION:
390 case GST_FORMAT_BYTES:
391 case GST_FORMAT_TIME:
394 const GstFormat *peer_formats;
398 peer_formats = gst_pad_get_formats (GST_PAD_PEER (speexenc->sinkpad));
400 while (peer_formats && *peer_formats && !res) {
402 GstFormat peer_format = *peer_formats;
405 if (gst_pad_query (GST_PAD_PEER (speexenc->sinkpad),
406 GST_QUERY_TOTAL, &peer_format, &peer_value)) {
407 GstFormat conv_format;
409 /* convert to TIME */
410 conv_format = GST_FORMAT_TIME;
411 res = gst_pad_convert (speexenc->sinkpad,
412 peer_format, peer_value, &conv_format, value);
413 /* and to final format */
414 res &= gst_pad_convert (pad,
415 GST_FORMAT_TIME, *value, format, value);
426 case GST_QUERY_CONVERT:
428 GstFormat src_fmt, dest_fmt;
429 gint64 src_val, dest_val;
431 gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, &dest_val);
432 if (!(res = gst_speexenc_convert_src (pad, src_fmt, src_val, &dest_fmt,
435 gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val);
448 gst_speexenc_sink_query (GstPad * pad, GstQuery * query)
451 GstSpeexEnc *speexenc;
453 speexenc = GST_SPEEXENC (GST_PAD_PARENT (pad));
455 switch (GST_QUERY_TYPE (query)) {
456 case GST_QUERY_CONVERT:
458 GstFormat src_fmt, dest_fmt;
459 gint64 src_val, dest_val;
461 gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, &dest_val);
463 gst_speexenc_convert_sink (pad, src_fmt, src_val, &dest_fmt,
466 gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val);
479 gst_speexenc_init (GstSpeexEnc * speexenc)
482 gst_pad_new_from_template (gst_speexenc_sink_template, "sink");
483 gst_element_add_pad (GST_ELEMENT (speexenc), speexenc->sinkpad);
484 gst_pad_set_event_function (speexenc->sinkpad, gst_speexenc_sinkevent);
485 gst_pad_set_chain_function (speexenc->sinkpad, gst_speexenc_chain);
486 gst_pad_set_setcaps_function (speexenc->sinkpad, gst_speexenc_sink_setcaps);
487 gst_pad_set_query_function (speexenc->sinkpad,
488 GST_DEBUG_FUNCPTR (gst_speexenc_sink_query));
491 gst_pad_new_from_template (gst_speexenc_src_template, "src");
492 gst_pad_set_query_function (speexenc->srcpad,
493 GST_DEBUG_FUNCPTR (gst_speexenc_src_query));
494 gst_pad_set_query_type_function (speexenc->srcpad,
495 GST_DEBUG_FUNCPTR (gst_speexenc_get_query_types));
496 gst_element_add_pad (GST_ELEMENT (speexenc), speexenc->srcpad);
498 speexenc->channels = -1;
501 speexenc->quality = DEFAULT_QUALITY;
502 speexenc->bitrate = DEFAULT_BITRATE;
503 speexenc->vbr = DEFAULT_VBR;
504 speexenc->abr = DEFAULT_ABR;
505 speexenc->vad = DEFAULT_VAD;
506 speexenc->dtx = DEFAULT_DTX;
507 speexenc->complexity = DEFAULT_COMPLEXITY;
508 speexenc->nframes = DEFAULT_NFRAMES;
510 speexenc->setup = FALSE;
511 speexenc->header_sent = FALSE;
513 speexenc->adapter = gst_adapter_new ();
518 gst_speexenc_get_tag_value (const GstTagList * list, const gchar * tag,
521 gchar *speexvalue = NULL;
527 /* get tag name right */
528 if ((strcmp (tag, GST_TAG_TRACK_NUMBER) == 0)
529 || (strcmp (tag, GST_TAG_ALBUM_VOLUME_NUMBER) == 0)
530 || (strcmp (tag, GST_TAG_TRACK_COUNT) == 0)
531 || (strcmp (tag, GST_TAG_ALBUM_VOLUME_COUNT) == 0)) {
534 if (!gst_tag_list_get_uint_index (list, tag, index, &track_no))
535 g_assert_not_reached ();
536 speexvalue = g_strdup_printf ("%u", track_no);
537 } else if (strcmp (tag, GST_TAG_DATE) == 0) {
538 /* FIXME: how are dates represented in speex files? */
542 if (!gst_tag_list_get_uint_index (list, tag, index, &u))
543 g_assert_not_reached ();
544 date = g_date_new_julian (u);
546 g_strdup_printf ("%04d-%02d-%02d", (gint) g_date_get_year (date),
547 (gint) g_date_get_month (date), (gint) g_date_get_day (date));
549 } else if (gst_tag_get_type (tag) == G_TYPE_STRING) {
550 if (!gst_tag_list_get_string_index (list, tag, index, &speexvalue))
551 g_assert_not_reached ();
558 * Comments will be stored in the Vorbis style.
559 * It is describled in the "Structure" section of
560 * http://www.xiph.org/ogg/vorbis/doc/v-comment.html
562 * The comment header is decoded as follows:
563 * 1) [vendor_length] = read an unsigned integer of 32 bits
564 * 2) [vendor_string] = read a UTF-8 vector as [vendor_length] octets
565 * 3) [user_comment_list_length] = read an unsigned integer of 32 bits
566 * 4) iterate [user_comment_list_length] times {
567 * 5) [length] = read an unsigned integer of 32 bits
568 * 6) this iteration's user comment = read a UTF-8 vector as [length] octets
570 * 7) [framing_bit] = read a single bit as boolean
571 * 8) if ( [framing_bit] unset or end of packet ) then ERROR
574 * If you have troubles, please write to ymnk@jcraft.com.
576 #define readint(buf, base) (((buf[base+3]<<24) & 0xff000000)| \
577 ((buf[base+2]<<16) & 0xff0000)| \
578 ((buf[base+1]<< 8) & 0xff00)| \
580 #define writeint(buf, base, val) do{ buf[base+3] = ((val)>>24) & 0xff; \
581 buf[base+2] = ((val)>>16) & 0xff; \
582 buf[base+1] = ((val)>> 8) & 0xff; \
583 buf[base ] = (val) & 0xff; \
587 comment_init (guint8 ** comments, int *length, char *vendor_string)
589 int vendor_length = strlen (vendor_string);
590 int user_comment_list_length = 0;
591 int len = 4 + vendor_length + 4;
592 guint8 *p = g_malloc (len);
594 writeint (p, 0, vendor_length);
595 memcpy (p + 4, (guint8 *) vendor_string, vendor_length);
596 writeint (p, 4 + vendor_length, user_comment_list_length);
601 comment_add (guint8 ** comments, int *length, const char *tag, char *val)
603 guint8 *p = *comments;
604 int vendor_length = readint (p, 0);
605 int user_comment_list_length = readint (p, 4 + vendor_length);
606 int tag_len = (tag ? strlen (tag) : 0);
607 int val_len = strlen (val);
608 int len = (*length) + 4 + tag_len + val_len;
610 p = g_realloc (p, len);
612 writeint (p, *length, tag_len + val_len); /* length of comment */
614 memcpy (p + *length + 4, (guint8 *) tag, tag_len); /* comment */
615 memcpy (p + *length + 4 + tag_len, val, val_len); /* comment */
616 writeint (p, 4 + vendor_length, user_comment_list_length + 1);
626 gst_speexenc_metadata_set1 (const GstTagList * list, const gchar * tag,
629 const gchar *speextag = NULL;
630 gchar *speexvalue = NULL;
632 GstSpeexEnc *enc = GST_SPEEXENC (speexenc);
634 speextag = gst_tag_to_vorbis_tag (tag);
635 if (speextag == NULL) {
639 count = gst_tag_list_get_tag_size (list, tag);
640 for (i = 0; i < count; i++) {
641 speexvalue = gst_speexenc_get_tag_value (list, tag, i);
643 if (speexvalue != NULL) {
644 comment_add (&enc->comments, &enc->comment_len, speextag, speexvalue);
650 gst_speexenc_set_metadata (GstSpeexEnc * speexenc)
653 const GstTagList *user_tags;
655 user_tags = gst_tag_setter_get_list (GST_TAG_SETTER (speexenc));
656 if (!(speexenc->tags || user_tags))
659 comment_init (&speexenc->comments, &speexenc->comment_len,
660 "Encoded with GStreamer Speexenc");
662 gst_tag_list_merge (user_tags, speexenc->tags,
663 gst_tag_setter_get_merge_mode (GST_TAG_SETTER (speexenc)));
664 gst_tag_list_foreach (copy, gst_speexenc_metadata_set1, speexenc);
665 gst_tag_list_free (copy);
669 gst_speexenc_setup (GstSpeexEnc * speexenc)
671 speexenc->setup = FALSE;
673 switch (speexenc->mode) {
674 case GST_SPEEXENC_MODE_UWB:
675 speexenc->speex_mode = (SpeexMode *) & speex_uwb_mode;
677 case GST_SPEEXENC_MODE_WB:
678 speexenc->speex_mode = (SpeexMode *) & speex_wb_mode;
680 case GST_SPEEXENC_MODE_NB:
681 speexenc->speex_mode = (SpeexMode *) & speex_nb_mode;
683 case GST_SPEEXENC_MODE_AUTO:
689 if (speexenc->rate > 25000) {
690 if (speexenc->mode == GST_SPEEXENC_MODE_AUTO) {
691 speexenc->speex_mode = (SpeexMode *) & speex_uwb_mode;
693 if (speexenc->speex_mode != &speex_uwb_mode) {
694 speexenc->last_message =
696 ("Warning: suggest to use ultra wide band mode for this rate");
697 g_object_notify (G_OBJECT (speexenc), "last_message");
700 } else if (speexenc->rate > 12500) {
701 if (speexenc->mode == GST_SPEEXENC_MODE_AUTO) {
702 speexenc->speex_mode = (SpeexMode *) & speex_wb_mode;
704 if (speexenc->speex_mode != &speex_wb_mode) {
705 speexenc->last_message =
707 ("Warning: suggest to use wide band mode for this rate");
708 g_object_notify (G_OBJECT (speexenc), "last_message");
712 if (speexenc->mode == GST_SPEEXENC_MODE_AUTO) {
713 speexenc->speex_mode = (SpeexMode *) & speex_nb_mode;
715 if (speexenc->speex_mode != &speex_nb_mode) {
716 speexenc->last_message =
718 ("Warning: suggest to use narrow band mode for this rate");
719 g_object_notify (G_OBJECT (speexenc), "last_message");
724 if (speexenc->rate != 8000 && speexenc->rate != 16000
725 && speexenc->rate != 32000) {
726 speexenc->last_message =
727 g_strdup_printf ("Warning: speex is optimized for 8, 16 and 32 KHz");
728 g_object_notify (G_OBJECT (speexenc), "last_message");
731 speex_init_header (&speexenc->header, speexenc->rate, 1,
732 speexenc->speex_mode);
733 speexenc->header.frames_per_packet = speexenc->nframes;
734 speexenc->header.vbr = speexenc->vbr;
735 speexenc->header.nb_channels = speexenc->channels;
737 /*Initialize Speex encoder */
738 speexenc->state = speex_encoder_init (speexenc->speex_mode);
740 speex_encoder_ctl (speexenc->state, SPEEX_GET_FRAME_SIZE,
741 &speexenc->frame_size);
742 speex_encoder_ctl (speexenc->state, SPEEX_SET_COMPLEXITY,
743 &speexenc->complexity);
744 speex_encoder_ctl (speexenc->state, SPEEX_SET_SAMPLING_RATE, &speexenc->rate);
747 speex_encoder_ctl (speexenc->state, SPEEX_SET_VBR_QUALITY,
750 gint tmp = floor (speexenc->quality);
752 speex_encoder_ctl (speexenc->state, SPEEX_SET_QUALITY, &tmp);
754 if (speexenc->bitrate) {
755 if (speexenc->quality >= 0.0 && speexenc->vbr) {
756 speexenc->last_message =
757 g_strdup_printf ("Warning: bitrate option is overriding quality");
758 g_object_notify (G_OBJECT (speexenc), "last_message");
760 speex_encoder_ctl (speexenc->state, SPEEX_SET_BITRATE, &speexenc->bitrate);
765 speex_encoder_ctl (speexenc->state, SPEEX_SET_VBR, &tmp);
766 } else if (speexenc->vad) {
769 speex_encoder_ctl (speexenc->state, SPEEX_SET_VAD, &tmp);
775 speex_encoder_ctl (speexenc->state, SPEEX_SET_DTX, &tmp);
778 if (speexenc->dtx && !(speexenc->vbr || speexenc->abr || speexenc->vad)) {
779 speexenc->last_message =
780 g_strdup_printf ("Warning: dtx is useless without vad, vbr or abr");
781 g_object_notify (G_OBJECT (speexenc), "last_message");
782 } else if ((speexenc->vbr || speexenc->abr) && (speexenc->vad)) {
783 speexenc->last_message =
784 g_strdup_printf ("Warning: vad is already implied by vbr or abr");
785 g_object_notify (G_OBJECT (speexenc), "last_message");
789 speex_encoder_ctl (speexenc->state, SPEEX_SET_ABR, &speexenc->abr);
792 speex_encoder_ctl (speexenc->state, SPEEX_GET_LOOKAHEAD,
793 &speexenc->lookahead);
795 speexenc->setup = TRUE;
800 /* prepare a buffer for transmission */
802 gst_speexenc_buffer_from_data (GstSpeexEnc * speexenc, guchar * data,
803 gint data_len, guint64 granulepos)
807 outbuf = gst_buffer_new_and_alloc (data_len);
808 memcpy (GST_BUFFER_DATA (outbuf), data, data_len);
809 GST_BUFFER_OFFSET (outbuf) = speexenc->bytes_out;
810 GST_BUFFER_OFFSET_END (outbuf) = granulepos;
812 GST_DEBUG ("encoded buffer of %d bytes", GST_BUFFER_SIZE (outbuf));
816 /* push out the buffer and do internal bookkeeping */
818 gst_speexenc_push_buffer (GstSpeexEnc * speexenc, GstBuffer * buffer)
820 speexenc->bytes_out += GST_BUFFER_SIZE (buffer);
822 if (GST_PAD_IS_USABLE (speexenc->srcpad)) {
823 gst_pad_push (speexenc->srcpad, buffer);
825 gst_buffer_unref (buffer);
830 gst_speexenc_set_header_on_caps (GstCaps * caps, GstBuffer * buf1,
833 caps = gst_caps_make_writable (caps);
834 GstStructure *structure = gst_caps_get_structure (caps, 0);
836 GValue value = { 0 };
839 GST_BUFFER_FLAG_SET (buf1, GST_BUFFER_FLAG_IN_CAPS);
840 GST_BUFFER_FLAG_SET (buf2, GST_BUFFER_FLAG_IN_CAPS);
842 /* put buffers in a fixed list */
843 g_value_init (&list, GST_TYPE_ARRAY);
844 g_value_init (&value, GST_TYPE_BUFFER);
845 gst_value_set_buffer (&value, buf1);
846 gst_value_list_append_value (&list, &value);
847 g_value_unset (&value);
848 g_value_init (&value, GST_TYPE_BUFFER);
849 gst_value_set_buffer (&value, buf2);
850 gst_value_list_append_value (&list, &value);
851 gst_structure_set_value (structure, "streamheader", &list);
852 g_value_unset (&value);
853 g_value_unset (&list);
860 gst_speexenc_sinkevent (GstPad * pad, GstEvent * event)
863 GstSpeexEnc *speexenc;
865 speexenc = GST_SPEEXENC (GST_PAD_PARENT (pad));
867 switch (GST_EVENT_TYPE (event)) {
869 speexenc->eos = TRUE;
870 res = gst_pad_event_default (pad, event);
876 gst_event_parse_tag (event, &list);
877 if (speexenc->tags) {
878 gst_tag_list_insert (speexenc->tags, list,
879 gst_tag_setter_get_merge_mode (GST_TAG_SETTER (speexenc)));
881 g_assert_not_reached ();
883 res = gst_pad_event_default (pad, event);
887 res = gst_pad_event_default (pad, event);
894 gst_speexenc_chain (GstPad * pad, GstBuffer * buf)
896 GstSpeexEnc *speexenc;
898 speexenc = GST_SPEEXENC (GST_PAD_PARENT (pad));
900 if (!speexenc->setup) {
901 gst_buffer_unref (buf);
902 GST_ELEMENT_ERROR (speexenc, CORE, NEGOTIATION, (NULL),
903 ("encoder not initialized (input is not audio?)"));
904 return GST_FLOW_UNEXPECTED;
907 if (!speexenc->header_sent) {
908 /* Speex streams begin with two headers; the initial header (with
909 most of the codec setup parameters) which is mandated by the Ogg
910 bitstream spec. The second header holds any comment fields.
911 We merely need to make the headers, then pass them to libspeex
912 one at a time; libspeex handles the additional Ogg bitstream
914 GstBuffer *buf1, *buf2;
919 gst_speexenc_set_metadata (speexenc);
921 /* create header buffer */
922 data = (guint8 *) speex_header_to_packet (&speexenc->header, &data_len);
923 buf1 = gst_speexenc_buffer_from_data (speexenc, data, data_len, 0);
925 /* create comment buffer */
927 gst_speexenc_buffer_from_data (speexenc, speexenc->comments,
928 speexenc->comment_len, 0);
930 /* mark and put on caps */
931 caps = gst_pad_get_caps (speexenc->srcpad);
932 caps = gst_speexenc_set_header_on_caps (caps, buf1, buf2);
934 /* negotiate with these caps */
935 GST_DEBUG ("here are the caps: %" GST_PTR_FORMAT, caps);
936 gst_pad_set_caps (speexenc->srcpad, caps);
938 gst_buffer_set_caps (buf1, caps);
939 gst_buffer_set_caps (buf2, caps);
941 /* push out buffers */
942 gst_speexenc_push_buffer (speexenc, buf1);
943 gst_speexenc_push_buffer (speexenc, buf2);
945 speex_bits_init (&speexenc->bits);
946 speex_bits_reset (&speexenc->bits);
948 speexenc->header_sent = TRUE;
952 gint frame_size = speexenc->frame_size;
953 gint bytes = frame_size * 2 * speexenc->channels;
955 /* push buffer to adapter */
956 gst_adapter_push (speexenc->adapter, buf);
958 while (gst_adapter_available (speexenc->adapter) >= bytes) {
961 gint outsize, written;
964 data = (gint16 *) gst_adapter_peek (speexenc->adapter, bytes);
966 for (i = 0; i < frame_size * speexenc->channels; i++) {
967 speexenc->input[i] = (gfloat) data[i];
969 gst_adapter_flush (speexenc->adapter, bytes);
971 speexenc->samples_in += frame_size;
973 if (speexenc->channels == 2) {
974 speex_encode_stereo (speexenc->input, frame_size, &speexenc->bits);
976 speex_encode (speexenc->state, speexenc->input, &speexenc->bits);
980 if ((speexenc->frameno % speexenc->nframes) != 0)
983 speex_bits_insert_terminator (&speexenc->bits);
984 outsize = speex_bits_nbytes (&speexenc->bits);
986 gst_pad_alloc_buffer (speexenc->srcpad,
987 GST_BUFFER_OFFSET_NONE, outsize, GST_PAD_CAPS (speexenc->srcpad),
990 written = speex_bits_write (&speexenc->bits,
991 (gchar *) GST_BUFFER_DATA (outbuf), outsize);
992 g_assert (written == outsize);
993 speex_bits_reset (&speexenc->bits);
995 GST_BUFFER_TIMESTAMP (outbuf) =
996 (speexenc->frameno * frame_size -
997 speexenc->lookahead) * GST_SECOND / speexenc->rate;
998 GST_BUFFER_DURATION (outbuf) = frame_size * GST_SECOND / speexenc->rate;
999 GST_BUFFER_OFFSET (outbuf) = speexenc->bytes_out;
1000 GST_BUFFER_OFFSET_END (outbuf) =
1001 speexenc->frameno * frame_size - speexenc->lookahead;
1003 gst_speexenc_push_buffer (speexenc, outbuf);
1011 gst_speexenc_get_property (GObject * object, guint prop_id, GValue * value,
1014 GstSpeexEnc *speexenc;
1016 g_return_if_fail (GST_IS_SPEEXENC (object));
1018 speexenc = GST_SPEEXENC (object);
1022 g_value_set_float (value, speexenc->quality);
1025 g_value_set_int (value, speexenc->bitrate);
1028 g_value_set_boolean (value, speexenc->vbr);
1031 g_value_set_int (value, speexenc->abr);
1034 g_value_set_boolean (value, speexenc->vad);
1037 g_value_set_boolean (value, speexenc->dtx);
1039 case ARG_COMPLEXITY:
1040 g_value_set_int (value, speexenc->complexity);
1043 g_value_set_int (value, speexenc->nframes);
1045 case ARG_LAST_MESSAGE:
1046 g_value_set_string (value, speexenc->last_message);
1049 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1055 gst_speexenc_set_property (GObject * object, guint prop_id,
1056 const GValue * value, GParamSpec * pspec)
1058 GstSpeexEnc *speexenc;
1060 g_return_if_fail (GST_IS_SPEEXENC (object));
1062 speexenc = GST_SPEEXENC (object);
1066 speexenc->quality = g_value_get_float (value);
1069 speexenc->bitrate = g_value_get_int (value);
1072 speexenc->vbr = g_value_get_boolean (value);
1075 speexenc->abr = g_value_get_int (value);
1078 speexenc->vad = g_value_get_boolean (value);
1081 speexenc->dtx = g_value_get_boolean (value);
1083 case ARG_COMPLEXITY:
1084 speexenc->complexity = g_value_get_int (value);
1087 speexenc->nframes = g_value_get_int (value);
1090 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1095 static GstStateChangeReturn
1096 gst_speexenc_change_state (GstElement * element, GstStateChange transition)
1098 GstSpeexEnc *speexenc = GST_SPEEXENC (element);
1099 GstStateChangeReturn res;
1101 switch (transition) {
1102 case GST_STATE_CHANGE_NULL_TO_READY:
1103 speexenc->tags = gst_tag_list_new ();
1105 case GST_STATE_CHANGE_READY_TO_PAUSED:
1106 speexenc->frameno = 0;
1107 speexenc->samples_in = 0;
1109 case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
1115 res = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1117 switch (transition) {
1118 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
1120 case GST_STATE_CHANGE_PAUSED_TO_READY:
1121 speexenc->setup = FALSE;
1122 speexenc->header_sent = FALSE;
1124 case GST_STATE_CHANGE_READY_TO_NULL:
1125 gst_tag_list_free (speexenc->tags);
1126 speexenc->tags = NULL;