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 (char **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 char *p = (char *) malloc (len);
596 writeint (p, 0, vendor_length);
597 memcpy (p + 4, vendor_string, vendor_length);
598 writeint (p, 4 + vendor_length, user_comment_list_length);
603 comment_add (char **comments, int *length, const char *tag, char *val)
606 int vendor_length = readint (p, 0);
607 int user_comment_list_length = readint (p, 4 + vendor_length);
608 int tag_len = (tag ? strlen (tag) : 0);
609 int val_len = strlen (val);
610 int len = (*length) + 4 + tag_len + val_len;
612 p = (char *) realloc (p, len);
614 writeint (p, *length, tag_len + val_len); /* length of comment */
616 memcpy (p + *length + 4, tag, tag_len); /* comment */
617 memcpy (p + *length + 4 + tag_len, val, val_len); /* comment */
618 writeint (p, 4 + vendor_length, user_comment_list_length + 1);
628 gst_speexenc_metadata_set1 (const GstTagList * list, const gchar * tag,
631 const gchar *speextag = NULL;
632 gchar *speexvalue = NULL;
634 GstSpeexEnc *enc = GST_SPEEXENC (speexenc);
636 speextag = gst_tag_to_vorbis_tag (tag);
637 if (speextag == NULL) {
641 count = gst_tag_list_get_tag_size (list, tag);
642 for (i = 0; i < count; i++) {
643 speexvalue = gst_speexenc_get_tag_value (list, tag, i);
645 if (speexvalue != NULL) {
646 comment_add (&enc->comments, &enc->comment_len, speextag, speexvalue);
652 gst_speexenc_set_metadata (GstSpeexEnc * speexenc)
655 const GstTagList *user_tags;
657 user_tags = gst_tag_setter_get_list (GST_TAG_SETTER (speexenc));
658 if (!(speexenc->tags || user_tags))
661 comment_init (&speexenc->comments, &speexenc->comment_len,
662 "Encoded with GStreamer Speexenc");
664 gst_tag_list_merge (user_tags, speexenc->tags,
665 gst_tag_setter_get_merge_mode (GST_TAG_SETTER (speexenc)));
666 gst_tag_list_foreach (copy, gst_speexenc_metadata_set1, speexenc);
667 gst_tag_list_free (copy);
671 gst_speexenc_setup (GstSpeexEnc * speexenc)
673 speexenc->setup = FALSE;
675 switch (speexenc->mode) {
676 case GST_SPEEXENC_MODE_UWB:
677 speexenc->speex_mode = (SpeexMode *) & speex_uwb_mode;
679 case GST_SPEEXENC_MODE_WB:
680 speexenc->speex_mode = (SpeexMode *) & speex_wb_mode;
682 case GST_SPEEXENC_MODE_NB:
683 speexenc->speex_mode = (SpeexMode *) & speex_nb_mode;
685 case GST_SPEEXENC_MODE_AUTO:
691 if (speexenc->rate > 25000) {
692 if (speexenc->mode == GST_SPEEXENC_MODE_AUTO) {
693 speexenc->speex_mode = (SpeexMode *) & speex_uwb_mode;
695 if (speexenc->speex_mode != &speex_uwb_mode) {
696 speexenc->last_message =
698 ("Warning: suggest to use ultra wide band mode for this rate");
699 g_object_notify (G_OBJECT (speexenc), "last_message");
702 } else if (speexenc->rate > 12500) {
703 if (speexenc->mode == GST_SPEEXENC_MODE_AUTO) {
704 speexenc->speex_mode = (SpeexMode *) & speex_wb_mode;
706 if (speexenc->speex_mode != &speex_wb_mode) {
707 speexenc->last_message =
709 ("Warning: suggest to use wide band mode for this rate");
710 g_object_notify (G_OBJECT (speexenc), "last_message");
714 if (speexenc->mode == GST_SPEEXENC_MODE_AUTO) {
715 speexenc->speex_mode = (SpeexMode *) & speex_nb_mode;
717 if (speexenc->speex_mode != &speex_nb_mode) {
718 speexenc->last_message =
720 ("Warning: suggest to use narrow band mode for this rate");
721 g_object_notify (G_OBJECT (speexenc), "last_message");
726 if (speexenc->rate != 8000 && speexenc->rate != 16000
727 && speexenc->rate != 32000) {
728 speexenc->last_message =
729 g_strdup_printf ("Warning: speex is optimized for 8, 16 and 32 KHz");
730 g_object_notify (G_OBJECT (speexenc), "last_message");
733 speex_init_header (&speexenc->header, speexenc->rate, 1,
734 speexenc->speex_mode);
735 speexenc->header.frames_per_packet = speexenc->nframes;
736 speexenc->header.vbr = speexenc->vbr;
737 speexenc->header.nb_channels = speexenc->channels;
739 /*Initialize Speex encoder */
740 speexenc->state = speex_encoder_init (speexenc->speex_mode);
742 speex_encoder_ctl (speexenc->state, SPEEX_GET_FRAME_SIZE,
743 &speexenc->frame_size);
744 speex_encoder_ctl (speexenc->state, SPEEX_SET_COMPLEXITY,
745 &speexenc->complexity);
746 speex_encoder_ctl (speexenc->state, SPEEX_SET_SAMPLING_RATE, &speexenc->rate);
749 speex_encoder_ctl (speexenc->state, SPEEX_SET_VBR_QUALITY,
752 gint tmp = floor (speexenc->quality);
754 speex_encoder_ctl (speexenc->state, SPEEX_SET_QUALITY, &tmp);
756 if (speexenc->bitrate) {
757 if (speexenc->quality >= 0.0 && speexenc->vbr) {
758 speexenc->last_message =
759 g_strdup_printf ("Warning: bitrate option is overriding quality");
760 g_object_notify (G_OBJECT (speexenc), "last_message");
762 speex_encoder_ctl (speexenc->state, SPEEX_SET_BITRATE, &speexenc->bitrate);
767 speex_encoder_ctl (speexenc->state, SPEEX_SET_VBR, &tmp);
768 } else if (speexenc->vad) {
771 speex_encoder_ctl (speexenc->state, SPEEX_SET_VAD, &tmp);
777 speex_encoder_ctl (speexenc->state, SPEEX_SET_DTX, &tmp);
780 if (speexenc->dtx && !(speexenc->vbr || speexenc->abr || speexenc->vad)) {
781 speexenc->last_message =
782 g_strdup_printf ("Warning: dtx is useless without vad, vbr or abr");
783 g_object_notify (G_OBJECT (speexenc), "last_message");
784 } else if ((speexenc->vbr || speexenc->abr) && (speexenc->vad)) {
785 speexenc->last_message =
786 g_strdup_printf ("Warning: vad is already implied by vbr or abr");
787 g_object_notify (G_OBJECT (speexenc), "last_message");
791 speex_encoder_ctl (speexenc->state, SPEEX_SET_ABR, &speexenc->abr);
794 speex_encoder_ctl (speexenc->state, SPEEX_GET_LOOKAHEAD,
795 &speexenc->lookahead);
797 speexenc->setup = TRUE;
802 /* prepare a buffer for transmission */
804 gst_speexenc_buffer_from_data (GstSpeexEnc * speexenc, guchar * data,
805 gint data_len, guint64 granulepos)
809 outbuf = gst_buffer_new_and_alloc (data_len);
810 memcpy (GST_BUFFER_DATA (outbuf), data, data_len);
811 GST_BUFFER_OFFSET (outbuf) = speexenc->bytes_out;
812 GST_BUFFER_OFFSET_END (outbuf) = granulepos;
814 GST_DEBUG ("encoded buffer of %d bytes", GST_BUFFER_SIZE (outbuf));
818 /* push out the buffer and do internal bookkeeping */
820 gst_speexenc_push_buffer (GstSpeexEnc * speexenc, GstBuffer * buffer)
822 speexenc->bytes_out += GST_BUFFER_SIZE (buffer);
824 if (GST_PAD_IS_USABLE (speexenc->srcpad)) {
825 gst_pad_push (speexenc->srcpad, buffer);
827 gst_buffer_unref (buffer);
832 gst_speexenc_set_header_on_caps (GstCaps * caps, GstBuffer * buf1,
835 caps = gst_caps_make_writable (caps);
836 GstStructure *structure = gst_caps_get_structure (caps, 0);
838 GValue value = { 0 };
841 GST_BUFFER_FLAG_SET (buf1, GST_BUFFER_FLAG_IN_CAPS);
842 GST_BUFFER_FLAG_SET (buf2, GST_BUFFER_FLAG_IN_CAPS);
844 /* put buffers in a fixed list */
845 g_value_init (&list, GST_TYPE_ARRAY);
846 g_value_init (&value, GST_TYPE_BUFFER);
847 gst_value_set_buffer (&value, buf1);
848 gst_value_list_append_value (&list, &value);
849 g_value_unset (&value);
850 g_value_init (&value, GST_TYPE_BUFFER);
851 gst_value_set_buffer (&value, buf2);
852 gst_value_list_append_value (&list, &value);
853 gst_structure_set_value (structure, "streamheader", &list);
854 g_value_unset (&value);
855 g_value_unset (&list);
862 gst_speexenc_sinkevent (GstPad * pad, GstEvent * event)
865 GstSpeexEnc *speexenc;
867 speexenc = GST_SPEEXENC (GST_PAD_PARENT (pad));
869 switch (GST_EVENT_TYPE (event)) {
871 speexenc->eos = TRUE;
872 res = gst_pad_event_default (pad, event);
878 gst_event_parse_tag (event, &list);
879 if (speexenc->tags) {
880 gst_tag_list_insert (speexenc->tags, list,
881 gst_tag_setter_get_merge_mode (GST_TAG_SETTER (speexenc)));
883 g_assert_not_reached ();
885 res = gst_pad_event_default (pad, event);
889 res = gst_pad_event_default (pad, event);
896 gst_speexenc_chain (GstPad * pad, GstBuffer * buf)
898 GstSpeexEnc *speexenc;
900 speexenc = GST_SPEEXENC (GST_PAD_PARENT (pad));
902 if (!speexenc->setup) {
903 gst_buffer_unref (buf);
904 GST_ELEMENT_ERROR (speexenc, CORE, NEGOTIATION, (NULL),
905 ("encoder not initialized (input is not audio?)"));
906 return GST_FLOW_UNEXPECTED;
909 if (!speexenc->header_sent) {
910 /* Speex streams begin with two headers; the initial header (with
911 most of the codec setup parameters) which is mandated by the Ogg
912 bitstream spec. The second header holds any comment fields.
913 We merely need to make the headers, then pass them to libspeex
914 one at a time; libspeex handles the additional Ogg bitstream
916 GstBuffer *buf1, *buf2;
921 gst_speexenc_set_metadata (speexenc);
923 /* create header buffer */
924 data = speex_header_to_packet (&speexenc->header, &data_len);
925 buf1 = gst_speexenc_buffer_from_data (speexenc, data, data_len, 0);
927 /* create comment buffer */
929 gst_speexenc_buffer_from_data (speexenc, speexenc->comments,
930 speexenc->comment_len, 0);
932 /* mark and put on caps */
933 caps = gst_pad_get_caps (speexenc->srcpad);
934 caps = gst_speexenc_set_header_on_caps (caps, buf1, buf2);
936 /* negotiate with these caps */
937 GST_DEBUG ("here are the caps: %" GST_PTR_FORMAT, caps);
938 gst_pad_set_caps (speexenc->srcpad, caps);
940 gst_buffer_set_caps (buf1, caps);
941 gst_buffer_set_caps (buf2, caps);
943 /* push out buffers */
944 gst_speexenc_push_buffer (speexenc, buf1);
945 gst_speexenc_push_buffer (speexenc, buf2);
947 speex_bits_init (&speexenc->bits);
948 speex_bits_reset (&speexenc->bits);
950 speexenc->header_sent = TRUE;
954 gint frame_size = speexenc->frame_size;
955 gint bytes = frame_size * 2 * speexenc->channels;
957 /* push buffer to adapter */
958 gst_adapter_push (speexenc->adapter, buf);
960 while (gst_adapter_available (speexenc->adapter) >= bytes) {
963 gint outsize, written;
966 data = (gint16 *) gst_adapter_peek (speexenc->adapter, bytes);
968 for (i = 0; i < frame_size * speexenc->channels; i++) {
969 speexenc->input[i] = (gfloat) data[i];
971 gst_adapter_flush (speexenc->adapter, bytes);
973 speexenc->samples_in += frame_size;
975 if (speexenc->channels == 2) {
976 speex_encode_stereo (speexenc->input, frame_size, &speexenc->bits);
978 speex_encode (speexenc->state, speexenc->input, &speexenc->bits);
982 if ((speexenc->frameno % speexenc->nframes) != 0)
985 speex_bits_insert_terminator (&speexenc->bits);
986 outsize = speex_bits_nbytes (&speexenc->bits);
988 gst_pad_alloc_buffer (speexenc->srcpad,
989 GST_BUFFER_OFFSET_NONE, outsize, GST_PAD_CAPS (speexenc->srcpad),
993 speex_bits_write (&speexenc->bits, GST_BUFFER_DATA (outbuf), outsize);
994 g_assert (written == outsize);
995 speex_bits_reset (&speexenc->bits);
997 GST_BUFFER_TIMESTAMP (outbuf) =
998 (speexenc->frameno * frame_size -
999 speexenc->lookahead) * GST_SECOND / speexenc->rate;
1000 GST_BUFFER_DURATION (outbuf) = frame_size * GST_SECOND / speexenc->rate;
1001 GST_BUFFER_OFFSET (outbuf) = speexenc->bytes_out;
1002 GST_BUFFER_OFFSET_END (outbuf) =
1003 speexenc->frameno * frame_size - speexenc->lookahead;
1005 gst_speexenc_push_buffer (speexenc, outbuf);
1013 gst_speexenc_get_property (GObject * object, guint prop_id, GValue * value,
1016 GstSpeexEnc *speexenc;
1018 g_return_if_fail (GST_IS_SPEEXENC (object));
1020 speexenc = GST_SPEEXENC (object);
1024 g_value_set_float (value, speexenc->quality);
1027 g_value_set_int (value, speexenc->bitrate);
1030 g_value_set_boolean (value, speexenc->vbr);
1033 g_value_set_int (value, speexenc->abr);
1036 g_value_set_boolean (value, speexenc->vad);
1039 g_value_set_boolean (value, speexenc->dtx);
1041 case ARG_COMPLEXITY:
1042 g_value_set_int (value, speexenc->complexity);
1045 g_value_set_int (value, speexenc->nframes);
1047 case ARG_LAST_MESSAGE:
1048 g_value_set_string (value, speexenc->last_message);
1051 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1057 gst_speexenc_set_property (GObject * object, guint prop_id,
1058 const GValue * value, GParamSpec * pspec)
1060 GstSpeexEnc *speexenc;
1062 g_return_if_fail (GST_IS_SPEEXENC (object));
1064 speexenc = GST_SPEEXENC (object);
1068 speexenc->quality = g_value_get_float (value);
1071 speexenc->bitrate = g_value_get_int (value);
1074 speexenc->vbr = g_value_get_boolean (value);
1077 speexenc->abr = g_value_get_int (value);
1080 speexenc->vad = g_value_get_boolean (value);
1083 speexenc->dtx = g_value_get_boolean (value);
1085 case ARG_COMPLEXITY:
1086 speexenc->complexity = g_value_get_int (value);
1089 speexenc->nframes = g_value_get_int (value);
1092 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1097 static GstStateChangeReturn
1098 gst_speexenc_change_state (GstElement * element, GstStateChange transition)
1100 GstSpeexEnc *speexenc = GST_SPEEXENC (element);
1101 GstStateChangeReturn res;
1103 switch (transition) {
1104 case GST_STATE_CHANGE_NULL_TO_READY:
1105 speexenc->tags = gst_tag_list_new ();
1107 case GST_STATE_CHANGE_READY_TO_PAUSED:
1108 speexenc->frameno = 0;
1109 speexenc->samples_in = 0;
1111 case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
1117 res = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1119 switch (transition) {
1120 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
1122 case GST_STATE_CHANGE_PAUSED_TO_READY:
1123 speexenc->setup = FALSE;
1124 speexenc->header_sent = FALSE;
1126 case GST_STATE_CHANGE_READY_TO_NULL:
1127 gst_tag_list_free (speexenc->tags);
1128 speexenc->tags = NULL;