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 ();
517 /* FIXME: why are we not using the from/to vorbiscomment
518 * functions that are in -lgsttagedit-0.9 here? */
521 gst_speexenc_get_tag_value (const GstTagList * list, const gchar * tag,
525 gchar *speexvalue = NULL;
530 tag_type = gst_tag_get_type (tag);
532 /* get tag name right */
533 if ((strcmp (tag, GST_TAG_TRACK_NUMBER) == 0)
534 || (strcmp (tag, GST_TAG_ALBUM_VOLUME_NUMBER) == 0)
535 || (strcmp (tag, GST_TAG_TRACK_COUNT) == 0)
536 || (strcmp (tag, GST_TAG_ALBUM_VOLUME_COUNT) == 0)) {
539 if (gst_tag_list_get_uint_index (list, tag, index, &track_no)) {
540 speexvalue = g_strdup_printf ("%u", track_no);
542 GST_WARNING ("Failed to extract int tag %d for '%s'", index, tag);
544 } else if (tag_type == GST_TYPE_DATE) {
545 /* FIXME: how are dates represented in speex files? */
548 if (gst_tag_list_get_date_index (list, tag, index, &date)) {
550 g_strdup_printf ("%04d-%02d-%02d", (gint) g_date_get_year (date),
551 (gint) g_date_get_month (date), (gint) g_date_get_day (date));
554 GST_WARNING ("Failed to extract date tag %d for '%s'", index, tag);
556 } else if (tag_type == G_TYPE_STRING) {
557 if (!gst_tag_list_get_string_index (list, tag, index, &speexvalue))
558 GST_WARNING ("Failed to extract string tag %d for '%s'", index, tag);
565 * Comments will be stored in the Vorbis style.
566 * It is describled in the "Structure" section of
567 * http://www.xiph.org/ogg/vorbis/doc/v-comment.html
569 * The comment header is decoded as follows:
570 * 1) [vendor_length] = read an unsigned integer of 32 bits
571 * 2) [vendor_string] = read a UTF-8 vector as [vendor_length] octets
572 * 3) [user_comment_list_length] = read an unsigned integer of 32 bits
573 * 4) iterate [user_comment_list_length] times {
574 * 5) [length] = read an unsigned integer of 32 bits
575 * 6) this iteration's user comment = read a UTF-8 vector as [length] octets
577 * 7) [framing_bit] = read a single bit as boolean
578 * 8) if ( [framing_bit] unset or end of packet ) then ERROR
581 * If you have troubles, please write to ymnk@jcraft.com.
584 comment_init (guint8 ** comments, int *length, char *vendor_string)
586 int vendor_length = strlen (vendor_string);
587 int user_comment_list_length = 0;
588 int len = 4 + vendor_length + 4;
589 guint8 *p = g_malloc (len);
591 GST_WRITE_UINT32_LE (p, vendor_length);
592 memcpy (p + 4, vendor_string, vendor_length);
593 GST_WRITE_UINT32_LE (p + 4 + vendor_length, user_comment_list_length);
598 comment_add (guint8 ** comments, int *length, const char *tag, char *val)
600 guint8 *p = *comments;
601 int vendor_length = GST_READ_UINT32_LE (p);
602 int user_comment_list_length = GST_READ_UINT32_LE (p + 4 + vendor_length);
603 int tag_len = (tag ? strlen (tag) : 0);
604 int val_len = strlen (val);
605 int len = (*length) + 4 + tag_len + val_len;
607 p = g_realloc (p, len);
609 GST_WRITE_UINT32_LE (p + *length, tag_len + val_len); /* length of comment */
611 memcpy (p + *length + 4, (guint8 *) tag, tag_len); /* comment */
612 memcpy (p + *length + 4 + tag_len, val, val_len); /* comment */
613 GST_WRITE_UINT32_LE (p + 4 + vendor_length, user_comment_list_length + 1);
620 gst_speexenc_metadata_set1 (const GstTagList * list, const gchar * tag,
623 const gchar *speextag = NULL;
624 gchar *speexvalue = NULL;
626 GstSpeexEnc *enc = GST_SPEEXENC (speexenc);
628 speextag = gst_tag_to_vorbis_tag (tag);
629 if (speextag == NULL) {
633 count = gst_tag_list_get_tag_size (list, tag);
634 for (i = 0; i < count; i++) {
635 speexvalue = gst_speexenc_get_tag_value (list, tag, i);
637 if (speexvalue != NULL) {
638 comment_add (&enc->comments, &enc->comment_len, speextag, speexvalue);
644 gst_speexenc_set_metadata (GstSpeexEnc * speexenc)
647 const GstTagList *user_tags;
649 user_tags = gst_tag_setter_get_list (GST_TAG_SETTER (speexenc));
650 if (!(speexenc->tags || user_tags))
653 comment_init (&speexenc->comments, &speexenc->comment_len,
654 "Encoded with GStreamer Speexenc");
656 gst_tag_list_merge (user_tags, speexenc->tags,
657 gst_tag_setter_get_merge_mode (GST_TAG_SETTER (speexenc)));
658 gst_tag_list_foreach (copy, gst_speexenc_metadata_set1, speexenc);
659 gst_tag_list_free (copy);
663 gst_speexenc_setup (GstSpeexEnc * speexenc)
665 speexenc->setup = FALSE;
667 switch (speexenc->mode) {
668 case GST_SPEEXENC_MODE_UWB:
669 speexenc->speex_mode = (SpeexMode *) & speex_uwb_mode;
671 case GST_SPEEXENC_MODE_WB:
672 speexenc->speex_mode = (SpeexMode *) & speex_wb_mode;
674 case GST_SPEEXENC_MODE_NB:
675 speexenc->speex_mode = (SpeexMode *) & speex_nb_mode;
677 case GST_SPEEXENC_MODE_AUTO:
683 if (speexenc->rate > 25000) {
684 if (speexenc->mode == GST_SPEEXENC_MODE_AUTO) {
685 speexenc->speex_mode = (SpeexMode *) & speex_uwb_mode;
687 if (speexenc->speex_mode != &speex_uwb_mode) {
688 speexenc->last_message =
690 ("Warning: suggest to use ultra wide band mode for this rate");
691 g_object_notify (G_OBJECT (speexenc), "last_message");
694 } else if (speexenc->rate > 12500) {
695 if (speexenc->mode == GST_SPEEXENC_MODE_AUTO) {
696 speexenc->speex_mode = (SpeexMode *) & speex_wb_mode;
698 if (speexenc->speex_mode != &speex_wb_mode) {
699 speexenc->last_message =
701 ("Warning: suggest to use wide band mode for this rate");
702 g_object_notify (G_OBJECT (speexenc), "last_message");
706 if (speexenc->mode == GST_SPEEXENC_MODE_AUTO) {
707 speexenc->speex_mode = (SpeexMode *) & speex_nb_mode;
709 if (speexenc->speex_mode != &speex_nb_mode) {
710 speexenc->last_message =
712 ("Warning: suggest to use narrow band mode for this rate");
713 g_object_notify (G_OBJECT (speexenc), "last_message");
718 if (speexenc->rate != 8000 && speexenc->rate != 16000
719 && speexenc->rate != 32000) {
720 speexenc->last_message =
721 g_strdup_printf ("Warning: speex is optimized for 8, 16 and 32 KHz");
722 g_object_notify (G_OBJECT (speexenc), "last_message");
725 speex_init_header (&speexenc->header, speexenc->rate, 1,
726 speexenc->speex_mode);
727 speexenc->header.frames_per_packet = speexenc->nframes;
728 speexenc->header.vbr = speexenc->vbr;
729 speexenc->header.nb_channels = speexenc->channels;
731 /*Initialize Speex encoder */
732 speexenc->state = speex_encoder_init (speexenc->speex_mode);
734 speex_encoder_ctl (speexenc->state, SPEEX_GET_FRAME_SIZE,
735 &speexenc->frame_size);
736 speex_encoder_ctl (speexenc->state, SPEEX_SET_COMPLEXITY,
737 &speexenc->complexity);
738 speex_encoder_ctl (speexenc->state, SPEEX_SET_SAMPLING_RATE, &speexenc->rate);
741 speex_encoder_ctl (speexenc->state, SPEEX_SET_VBR_QUALITY,
744 gint tmp = floor (speexenc->quality);
746 speex_encoder_ctl (speexenc->state, SPEEX_SET_QUALITY, &tmp);
748 if (speexenc->bitrate) {
749 if (speexenc->quality >= 0.0 && speexenc->vbr) {
750 speexenc->last_message =
751 g_strdup_printf ("Warning: bitrate option is overriding quality");
752 g_object_notify (G_OBJECT (speexenc), "last_message");
754 speex_encoder_ctl (speexenc->state, SPEEX_SET_BITRATE, &speexenc->bitrate);
759 speex_encoder_ctl (speexenc->state, SPEEX_SET_VBR, &tmp);
760 } else if (speexenc->vad) {
763 speex_encoder_ctl (speexenc->state, SPEEX_SET_VAD, &tmp);
769 speex_encoder_ctl (speexenc->state, SPEEX_SET_DTX, &tmp);
772 if (speexenc->dtx && !(speexenc->vbr || speexenc->abr || speexenc->vad)) {
773 speexenc->last_message =
774 g_strdup_printf ("Warning: dtx is useless without vad, vbr or abr");
775 g_object_notify (G_OBJECT (speexenc), "last_message");
776 } else if ((speexenc->vbr || speexenc->abr) && (speexenc->vad)) {
777 speexenc->last_message =
778 g_strdup_printf ("Warning: vad is already implied by vbr or abr");
779 g_object_notify (G_OBJECT (speexenc), "last_message");
783 speex_encoder_ctl (speexenc->state, SPEEX_SET_ABR, &speexenc->abr);
786 speex_encoder_ctl (speexenc->state, SPEEX_GET_LOOKAHEAD,
787 &speexenc->lookahead);
789 speexenc->setup = TRUE;
794 /* prepare a buffer for transmission */
796 gst_speexenc_buffer_from_data (GstSpeexEnc * speexenc, guchar * data,
797 gint data_len, guint64 granulepos)
801 outbuf = gst_buffer_new_and_alloc (data_len);
802 memcpy (GST_BUFFER_DATA (outbuf), data, data_len);
803 GST_BUFFER_OFFSET (outbuf) = speexenc->bytes_out;
804 GST_BUFFER_OFFSET_END (outbuf) = granulepos;
806 GST_DEBUG ("encoded buffer of %d bytes", GST_BUFFER_SIZE (outbuf));
810 /* push out the buffer and do internal bookkeeping */
812 gst_speexenc_push_buffer (GstSpeexEnc * speexenc, GstBuffer * buffer)
814 speexenc->bytes_out += GST_BUFFER_SIZE (buffer);
816 if (GST_PAD_IS_USABLE (speexenc->srcpad)) {
817 gst_pad_push (speexenc->srcpad, buffer);
819 gst_buffer_unref (buffer);
824 gst_speexenc_set_header_on_caps (GstCaps * caps, GstBuffer * buf1,
827 caps = gst_caps_make_writable (caps);
828 GstStructure *structure = gst_caps_get_structure (caps, 0);
830 GValue value = { 0 };
833 GST_BUFFER_FLAG_SET (buf1, GST_BUFFER_FLAG_IN_CAPS);
834 GST_BUFFER_FLAG_SET (buf2, GST_BUFFER_FLAG_IN_CAPS);
836 /* put buffers in a fixed list */
837 g_value_init (&list, GST_TYPE_ARRAY);
838 g_value_init (&value, GST_TYPE_BUFFER);
839 gst_value_set_buffer (&value, buf1);
840 gst_value_list_append_value (&list, &value);
841 g_value_unset (&value);
842 g_value_init (&value, GST_TYPE_BUFFER);
843 gst_value_set_buffer (&value, buf2);
844 gst_value_list_append_value (&list, &value);
845 gst_structure_set_value (structure, "streamheader", &list);
846 g_value_unset (&value);
847 g_value_unset (&list);
854 gst_speexenc_sinkevent (GstPad * pad, GstEvent * event)
857 GstSpeexEnc *speexenc;
859 speexenc = GST_SPEEXENC (GST_PAD_PARENT (pad));
861 switch (GST_EVENT_TYPE (event)) {
863 speexenc->eos = TRUE;
864 res = gst_pad_event_default (pad, event);
870 gst_event_parse_tag (event, &list);
871 if (speexenc->tags) {
872 gst_tag_list_insert (speexenc->tags, list,
873 gst_tag_setter_get_merge_mode (GST_TAG_SETTER (speexenc)));
875 g_assert_not_reached ();
877 res = gst_pad_event_default (pad, event);
881 res = gst_pad_event_default (pad, event);
888 gst_speexenc_chain (GstPad * pad, GstBuffer * buf)
890 GstSpeexEnc *speexenc;
892 speexenc = GST_SPEEXENC (GST_PAD_PARENT (pad));
894 if (!speexenc->setup) {
895 gst_buffer_unref (buf);
896 GST_ELEMENT_ERROR (speexenc, CORE, NEGOTIATION, (NULL),
897 ("encoder not initialized (input is not audio?)"));
898 return GST_FLOW_UNEXPECTED;
901 if (!speexenc->header_sent) {
902 /* Speex streams begin with two headers; the initial header (with
903 most of the codec setup parameters) which is mandated by the Ogg
904 bitstream spec. The second header holds any comment fields.
905 We merely need to make the headers, then pass them to libspeex
906 one at a time; libspeex handles the additional Ogg bitstream
908 GstBuffer *buf1, *buf2;
913 gst_speexenc_set_metadata (speexenc);
915 /* create header buffer */
916 data = (guint8 *) speex_header_to_packet (&speexenc->header, &data_len);
917 buf1 = gst_speexenc_buffer_from_data (speexenc, data, data_len, 0);
919 /* create comment buffer */
921 gst_speexenc_buffer_from_data (speexenc, speexenc->comments,
922 speexenc->comment_len, 0);
924 /* mark and put on caps */
925 caps = gst_pad_get_caps (speexenc->srcpad);
926 caps = gst_speexenc_set_header_on_caps (caps, buf1, buf2);
928 /* negotiate with these caps */
929 GST_DEBUG ("here are the caps: %" GST_PTR_FORMAT, caps);
930 gst_pad_set_caps (speexenc->srcpad, caps);
932 gst_buffer_set_caps (buf1, caps);
933 gst_buffer_set_caps (buf2, caps);
935 /* push out buffers */
936 gst_speexenc_push_buffer (speexenc, buf1);
937 gst_speexenc_push_buffer (speexenc, buf2);
939 speex_bits_init (&speexenc->bits);
940 speex_bits_reset (&speexenc->bits);
942 speexenc->header_sent = TRUE;
946 gint frame_size = speexenc->frame_size;
947 gint bytes = frame_size * 2 * speexenc->channels;
949 /* push buffer to adapter */
950 gst_adapter_push (speexenc->adapter, buf);
952 while (gst_adapter_available (speexenc->adapter) >= bytes) {
955 gint outsize, written;
958 data = (gint16 *) gst_adapter_peek (speexenc->adapter, bytes);
960 for (i = 0; i < frame_size * speexenc->channels; i++) {
961 speexenc->input[i] = (gfloat) data[i];
963 gst_adapter_flush (speexenc->adapter, bytes);
965 speexenc->samples_in += frame_size;
967 if (speexenc->channels == 2) {
968 speex_encode_stereo (speexenc->input, frame_size, &speexenc->bits);
970 speex_encode (speexenc->state, speexenc->input, &speexenc->bits);
974 if ((speexenc->frameno % speexenc->nframes) != 0)
977 speex_bits_insert_terminator (&speexenc->bits);
978 outsize = speex_bits_nbytes (&speexenc->bits);
980 gst_pad_alloc_buffer (speexenc->srcpad,
981 GST_BUFFER_OFFSET_NONE, outsize, GST_PAD_CAPS (speexenc->srcpad),
984 written = speex_bits_write (&speexenc->bits,
985 (gchar *) GST_BUFFER_DATA (outbuf), outsize);
986 g_assert (written == outsize);
987 speex_bits_reset (&speexenc->bits);
989 GST_BUFFER_TIMESTAMP (outbuf) =
990 (speexenc->frameno * frame_size -
991 speexenc->lookahead) * GST_SECOND / speexenc->rate;
992 GST_BUFFER_DURATION (outbuf) = frame_size * GST_SECOND / speexenc->rate;
993 GST_BUFFER_OFFSET (outbuf) = speexenc->bytes_out;
994 GST_BUFFER_OFFSET_END (outbuf) =
995 speexenc->frameno * frame_size - speexenc->lookahead;
997 gst_speexenc_push_buffer (speexenc, outbuf);
1005 gst_speexenc_get_property (GObject * object, guint prop_id, GValue * value,
1008 GstSpeexEnc *speexenc;
1010 g_return_if_fail (GST_IS_SPEEXENC (object));
1012 speexenc = GST_SPEEXENC (object);
1016 g_value_set_float (value, speexenc->quality);
1019 g_value_set_int (value, speexenc->bitrate);
1022 g_value_set_boolean (value, speexenc->vbr);
1025 g_value_set_int (value, speexenc->abr);
1028 g_value_set_boolean (value, speexenc->vad);
1031 g_value_set_boolean (value, speexenc->dtx);
1033 case ARG_COMPLEXITY:
1034 g_value_set_int (value, speexenc->complexity);
1037 g_value_set_int (value, speexenc->nframes);
1039 case ARG_LAST_MESSAGE:
1040 g_value_set_string (value, speexenc->last_message);
1043 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1049 gst_speexenc_set_property (GObject * object, guint prop_id,
1050 const GValue * value, GParamSpec * pspec)
1052 GstSpeexEnc *speexenc;
1054 g_return_if_fail (GST_IS_SPEEXENC (object));
1056 speexenc = GST_SPEEXENC (object);
1060 speexenc->quality = g_value_get_float (value);
1063 speexenc->bitrate = g_value_get_int (value);
1066 speexenc->vbr = g_value_get_boolean (value);
1069 speexenc->abr = g_value_get_int (value);
1072 speexenc->vad = g_value_get_boolean (value);
1075 speexenc->dtx = g_value_get_boolean (value);
1077 case ARG_COMPLEXITY:
1078 speexenc->complexity = g_value_get_int (value);
1081 speexenc->nframes = g_value_get_int (value);
1084 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1089 static GstStateChangeReturn
1090 gst_speexenc_change_state (GstElement * element, GstStateChange transition)
1092 GstSpeexEnc *speexenc = GST_SPEEXENC (element);
1093 GstStateChangeReturn res;
1095 switch (transition) {
1096 case GST_STATE_CHANGE_NULL_TO_READY:
1097 speexenc->tags = gst_tag_list_new ();
1099 case GST_STATE_CHANGE_READY_TO_PAUSED:
1100 speexenc->frameno = 0;
1101 speexenc->samples_in = 0;
1103 case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
1109 res = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1111 switch (transition) {
1112 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
1114 case GST_STATE_CHANGE_PAUSED_TO_READY:
1115 speexenc->setup = FALSE;
1116 speexenc->header_sent = FALSE;
1118 case GST_STATE_CHANGE_READY_TO_NULL:
1119 gst_tag_list_free (speexenc->tags);
1120 speexenc->tags = NULL;