1 /* GStreamer Speex Encoder
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 <gst/audio/audio.h>
34 #include "gstspeexenc.h"
36 GST_DEBUG_CATEGORY_STATIC (speexenc_debug);
37 #define GST_CAT_DEFAULT speexenc_debug
39 static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
42 GST_STATIC_CAPS ("audio/x-raw-int, "
43 "rate = (int) [ 6000, 48000 ], "
44 "channels = (int) [ 1, 2 ], "
45 "endianness = (int) BYTE_ORDER, "
46 "signed = (boolean) TRUE, " "width = (int) 16, " "depth = (int) 16")
49 static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
52 GST_STATIC_CAPS ("audio/x-speex, "
53 "rate = (int) [ 6000, 48000 ], " "channels = (int) [ 1, 2]")
56 static const GstElementDetails speexenc_details =
57 GST_ELEMENT_DETAILS ("Speex audio encoder",
58 "Codec/Encoder/Audio",
59 "Encodes audio in Speex format",
60 "Wim Taymans <wim@fluendo.com>");
62 #define DEFAULT_QUALITY 8.0
63 #define DEFAULT_BITRATE 0
64 #define DEFAULT_MODE GST_SPEEX_ENC_MODE_AUTO
65 #define DEFAULT_VBR FALSE
67 #define DEFAULT_VAD FALSE
68 #define DEFAULT_DTX FALSE
69 #define DEFAULT_COMPLEXITY 3
70 #define DEFAULT_NFRAMES 1
87 #define GST_TYPE_SPEEX_ENC_MODE (gst_speex_enc_mode_get_type())
89 gst_speex_enc_mode_get_type (void)
91 static GType speex_enc_mode_type = 0;
92 static const GEnumValue speex_enc_modes[] = {
93 {GST_SPEEX_ENC_MODE_AUTO, "Auto", "auto"},
94 {GST_SPEEX_ENC_MODE_UWB, "Ultra Wide Band", "uwb"},
95 {GST_SPEEX_ENC_MODE_WB, "Wide Band", "wb"},
96 {GST_SPEEX_ENC_MODE_NB, "Narrow Band", "nb"},
99 if (G_UNLIKELY (speex_enc_mode_type == 0)) {
100 speex_enc_mode_type = g_enum_register_static ("GstSpeexEncMode",
103 return speex_enc_mode_type;
107 static const GstFormat *
108 gst_speex_enc_get_formats (GstPad * pad)
110 static const GstFormat src_formats[] = {
115 static const GstFormat sink_formats[] = {
122 return (GST_PAD_IS_SRC (pad) ? src_formats : sink_formats);
126 static void gst_speex_enc_finalize (GObject * object);
128 static gboolean gst_speex_enc_sinkevent (GstPad * pad, GstEvent * event);
129 static GstFlowReturn gst_speex_enc_chain (GstPad * pad, GstBuffer * buf);
130 static gboolean gst_speex_enc_setup (GstSpeexEnc * enc);
132 static void gst_speex_enc_get_property (GObject * object, guint prop_id,
133 GValue * value, GParamSpec * pspec);
134 static void gst_speex_enc_set_property (GObject * object, guint prop_id,
135 const GValue * value, GParamSpec * pspec);
136 static GstStateChangeReturn gst_speex_enc_change_state (GstElement * element,
137 GstStateChange transition);
139 static GstFlowReturn gst_speex_enc_encode (GstSpeexEnc * enc, gboolean flush);
142 gst_speex_enc_setup_interfaces (GType speexenc_type)
144 static const GInterfaceInfo tag_setter_info = { NULL, NULL, NULL };
146 g_type_add_interface_static (speexenc_type, GST_TYPE_TAG_SETTER,
149 GST_DEBUG_CATEGORY_INIT (speexenc_debug, "speexenc", 0, "Speex encoder");
152 GST_BOILERPLATE_FULL (GstSpeexEnc, gst_speex_enc, GstElement, GST_TYPE_ELEMENT,
153 gst_speex_enc_setup_interfaces);
156 gst_speex_enc_base_init (gpointer g_class)
158 GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
160 gst_element_class_add_pad_template (element_class,
161 gst_static_pad_template_get (&src_factory));
162 gst_element_class_add_pad_template (element_class,
163 gst_static_pad_template_get (&sink_factory));
164 gst_element_class_set_details (element_class, &speexenc_details);
168 gst_speex_enc_class_init (GstSpeexEncClass * klass)
170 GObjectClass *gobject_class;
171 GstElementClass *gstelement_class;
173 gobject_class = (GObjectClass *) klass;
174 gstelement_class = (GstElementClass *) klass;
176 gobject_class->set_property = gst_speex_enc_set_property;
177 gobject_class->get_property = gst_speex_enc_get_property;
179 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_QUALITY,
180 g_param_spec_float ("quality", "Quality", "Encoding quality",
181 0.0, 10.0, DEFAULT_QUALITY, G_PARAM_READWRITE));
182 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_BITRATE,
183 g_param_spec_int ("bitrate", "Encoding Bit-rate",
184 "Specify an encoding bit-rate (in bps). (0 = automatic)",
185 0, G_MAXINT, DEFAULT_BITRATE, G_PARAM_READWRITE));
186 g_object_class_install_property (gobject_class, PROP_MODE,
187 g_param_spec_enum ("mode", "Mode", "The encoding mode",
188 GST_TYPE_SPEEX_ENC_MODE, GST_SPEEX_ENC_MODE_AUTO,
189 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
190 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_VBR,
191 g_param_spec_boolean ("vbr", "VBR",
192 "Enable variable bit-rate", DEFAULT_VBR, G_PARAM_READWRITE));
193 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_ABR,
194 g_param_spec_int ("abr", "ABR",
195 "Enable average bit-rate (0 = disabled)",
196 0, G_MAXINT, DEFAULT_ABR, G_PARAM_READWRITE));
197 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_VAD,
198 g_param_spec_boolean ("vad", "VAD",
199 "Enable voice activity detection", DEFAULT_VAD, G_PARAM_READWRITE));
200 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_DTX,
201 g_param_spec_boolean ("dtx", "DTX",
202 "Enable discontinuous transmission", DEFAULT_DTX, G_PARAM_READWRITE));
203 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_COMPLEXITY,
204 g_param_spec_int ("complexity", "Complexity",
205 "Set encoding complexity",
206 0, G_MAXINT, DEFAULT_COMPLEXITY, G_PARAM_READWRITE));
207 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_NFRAMES,
208 g_param_spec_int ("nframes", "NFrames",
209 "Number of frames per buffer",
210 0, G_MAXINT, DEFAULT_NFRAMES, G_PARAM_READWRITE));
211 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_LAST_MESSAGE,
212 g_param_spec_string ("last-message", "last-message",
213 "The last status message", NULL, G_PARAM_READABLE));
215 gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_speex_enc_finalize);
217 gstelement_class->change_state =
218 GST_DEBUG_FUNCPTR (gst_speex_enc_change_state);
222 gst_speex_enc_finalize (GObject * object)
226 enc = GST_SPEEX_ENC (object);
228 g_free (enc->last_message);
229 g_object_unref (enc->adapter);
231 G_OBJECT_CLASS (parent_class)->finalize (object);
235 gst_speex_enc_sink_setcaps (GstPad * pad, GstCaps * caps)
238 GstStructure *structure;
240 enc = GST_SPEEX_ENC (GST_PAD_PARENT (pad));
243 structure = gst_caps_get_structure (caps, 0);
244 gst_structure_get_int (structure, "channels", &enc->channels);
245 gst_structure_get_int (structure, "rate", &enc->rate);
247 gst_speex_enc_setup (enc);
254 gst_speex_enc_sink_getcaps (GstPad * pad)
256 GstCaps *caps = gst_caps_copy (gst_pad_get_pad_template_caps (pad));
257 GstCaps *peercaps = NULL;
258 GstSpeexEnc *enc = GST_SPEEX_ENC (gst_pad_get_parent_element (pad));
260 peercaps = gst_pad_peer_get_caps (enc->srcpad);
263 if (!gst_caps_is_empty (peercaps) && !gst_caps_is_any (peercaps)) {
264 GstStructure *ps = gst_caps_get_structure (peercaps, 0);
265 GstStructure *s = gst_caps_get_structure (caps, 0);
268 if (gst_structure_get_int (ps, "rate", &rate)) {
269 gst_structure_fixate_field_nearest_int (s, "rate", rate);
272 if (gst_structure_get_int (ps, "channels", &channels)) {
273 gst_structure_fixate_field_nearest_int (s, "channels", channels);
276 gst_caps_unref (peercaps);
279 gst_object_unref (enc);
286 gst_speex_enc_convert_src (GstPad * pad, GstFormat src_format, gint64 src_value,
287 GstFormat * dest_format, gint64 * dest_value)
293 enc = GST_SPEEX_ENC (GST_PAD_PARENT (pad));
295 if (enc->samples_in == 0 || enc->bytes_out == 0 || enc->rate == 0)
298 avg = (enc->bytes_out * enc->rate) / (enc->samples_in);
300 switch (src_format) {
301 case GST_FORMAT_BYTES:
302 switch (*dest_format) {
303 case GST_FORMAT_TIME:
304 *dest_value = src_value * GST_SECOND / avg;
310 case GST_FORMAT_TIME:
311 switch (*dest_format) {
312 case GST_FORMAT_BYTES:
313 *dest_value = src_value * avg / GST_SECOND;
326 gst_speex_enc_convert_sink (GstPad * pad, GstFormat src_format,
327 gint64 src_value, GstFormat * dest_format, gint64 * dest_value)
331 gint bytes_per_sample;
334 enc = GST_SPEEX_ENC (GST_PAD_PARENT (pad));
336 bytes_per_sample = enc->channels * 2;
338 switch (src_format) {
339 case GST_FORMAT_BYTES:
340 switch (*dest_format) {
341 case GST_FORMAT_DEFAULT:
342 if (bytes_per_sample == 0)
344 *dest_value = src_value / bytes_per_sample;
346 case GST_FORMAT_TIME:
348 gint byterate = bytes_per_sample * enc->rate;
352 *dest_value = src_value * GST_SECOND / byterate;
359 case GST_FORMAT_DEFAULT:
360 switch (*dest_format) {
361 case GST_FORMAT_BYTES:
362 *dest_value = src_value * bytes_per_sample;
364 case GST_FORMAT_TIME:
367 *dest_value = src_value * GST_SECOND / enc->rate;
373 case GST_FORMAT_TIME:
374 switch (*dest_format) {
375 case GST_FORMAT_BYTES:
376 scale = bytes_per_sample;
378 case GST_FORMAT_DEFAULT:
379 *dest_value = src_value * scale * enc->rate / GST_SECOND;
392 gst_speex_enc_get_latency (GstSpeexEnc * enc)
394 return 30 * GST_MSECOND;
397 static const GstQueryType *
398 gst_speex_enc_get_query_types (GstPad * pad)
400 static const GstQueryType gst_speex_enc_src_query_types[] = {
408 return gst_speex_enc_src_query_types;
412 gst_speex_enc_src_query (GstPad * pad, GstQuery * query)
417 enc = GST_SPEEX_ENC (gst_pad_get_parent (pad));
419 switch (GST_QUERY_TYPE (query)) {
420 case GST_QUERY_POSITION:
422 GstFormat fmt, req_fmt;
425 gst_query_parse_position (query, &req_fmt, NULL);
426 if ((res = gst_pad_query_peer_position (enc->sinkpad, &req_fmt, &val))) {
427 gst_query_set_position (query, req_fmt, val);
431 fmt = GST_FORMAT_TIME;
432 if (!(res = gst_pad_query_peer_position (enc->sinkpad, &fmt, &pos)))
436 gst_pad_query_peer_convert (enc->sinkpad, fmt, pos, &req_fmt,
438 gst_query_set_position (query, req_fmt, val);
442 case GST_QUERY_DURATION:
444 GstFormat fmt, req_fmt;
447 gst_query_parse_duration (query, &req_fmt, NULL);
448 if ((res = gst_pad_query_peer_duration (enc->sinkpad, &req_fmt, &val))) {
449 gst_query_set_duration (query, req_fmt, val);
453 fmt = GST_FORMAT_TIME;
454 if (!(res = gst_pad_query_peer_duration (enc->sinkpad, &fmt, &dur)))
458 gst_pad_query_peer_convert (enc->sinkpad, fmt, dur, &req_fmt,
460 gst_query_set_duration (query, req_fmt, val);
464 case GST_QUERY_CONVERT:
466 GstFormat src_fmt, dest_fmt;
467 gint64 src_val, dest_val;
469 gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, &dest_val);
470 if (!(res = gst_speex_enc_convert_src (pad, src_fmt, src_val, &dest_fmt,
473 gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val);
476 case GST_QUERY_LATENCY:
479 GstClockTime min_latency, max_latency;
482 if ((res = gst_pad_peer_query (pad, query))) {
483 gst_query_parse_latency (query, &live, &min_latency, &max_latency);
485 latency = gst_speex_enc_get_latency (enc);
487 /* add our latency */
488 min_latency += latency;
489 if (max_latency != -1)
490 max_latency += latency;
492 gst_query_set_latency (query, live, min_latency, max_latency);
497 res = gst_pad_peer_query (pad, query);
503 gst_object_unref (enc);
509 gst_speex_enc_sink_query (GstPad * pad, GstQuery * query)
514 enc = GST_SPEEX_ENC (GST_PAD_PARENT (pad));
516 switch (GST_QUERY_TYPE (query)) {
517 case GST_QUERY_CONVERT:
519 GstFormat src_fmt, dest_fmt;
520 gint64 src_val, dest_val;
522 gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, &dest_val);
524 gst_speex_enc_convert_sink (pad, src_fmt, src_val, &dest_fmt,
527 gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val);
531 res = gst_pad_query_default (pad, query);
540 gst_speex_enc_init (GstSpeexEnc * enc, GstSpeexEncClass * klass)
542 enc->sinkpad = gst_pad_new_from_static_template (&sink_factory, "sink");
543 gst_element_add_pad (GST_ELEMENT (enc), enc->sinkpad);
544 gst_pad_set_event_function (enc->sinkpad,
545 GST_DEBUG_FUNCPTR (gst_speex_enc_sinkevent));
546 gst_pad_set_chain_function (enc->sinkpad,
547 GST_DEBUG_FUNCPTR (gst_speex_enc_chain));
548 gst_pad_set_setcaps_function (enc->sinkpad,
549 GST_DEBUG_FUNCPTR (gst_speex_enc_sink_setcaps));
550 gst_pad_set_getcaps_function (enc->sinkpad,
551 GST_DEBUG_FUNCPTR (gst_speex_enc_sink_getcaps));
552 gst_pad_set_query_function (enc->sinkpad,
553 GST_DEBUG_FUNCPTR (gst_speex_enc_sink_query));
555 enc->srcpad = gst_pad_new_from_static_template (&src_factory, "src");
556 gst_pad_set_query_function (enc->srcpad,
557 GST_DEBUG_FUNCPTR (gst_speex_enc_src_query));
558 gst_pad_set_query_type_function (enc->srcpad,
559 GST_DEBUG_FUNCPTR (gst_speex_enc_get_query_types));
560 gst_element_add_pad (GST_ELEMENT (enc), enc->srcpad);
565 enc->quality = DEFAULT_QUALITY;
566 enc->bitrate = DEFAULT_BITRATE;
567 enc->mode = DEFAULT_MODE;
568 enc->vbr = DEFAULT_VBR;
569 enc->abr = DEFAULT_ABR;
570 enc->vad = DEFAULT_VAD;
571 enc->dtx = DEFAULT_DTX;
572 enc->complexity = DEFAULT_COMPLEXITY;
573 enc->nframes = DEFAULT_NFRAMES;
576 enc->header_sent = FALSE;
578 enc->adapter = gst_adapter_new ();
582 gst_speex_enc_create_metadata_buffer (GstSpeexEnc * enc)
584 const GstTagList *user_tags;
585 GstTagList *merged_tags;
586 GstBuffer *comments = NULL;
588 user_tags = gst_tag_setter_get_tag_list (GST_TAG_SETTER (enc));
590 GST_DEBUG_OBJECT (enc, "upstream tags = %" GST_PTR_FORMAT, enc->tags);
591 GST_DEBUG_OBJECT (enc, "user-set tags = %" GST_PTR_FORMAT, user_tags);
593 /* gst_tag_list_merge() will handle NULL for either or both lists fine */
594 merged_tags = gst_tag_list_merge (user_tags, enc->tags,
595 gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (enc)));
597 if (merged_tags == NULL)
598 merged_tags = gst_tag_list_new ();
600 GST_DEBUG_OBJECT (enc, "merged tags = %" GST_PTR_FORMAT, merged_tags);
601 comments = gst_tag_list_to_vorbiscomment_buffer (merged_tags, NULL,
602 0, "Encoded with GStreamer Speexenc");
603 gst_tag_list_free (merged_tags);
605 GST_BUFFER_OFFSET (comments) = enc->bytes_out;
606 GST_BUFFER_OFFSET_END (comments) = 0;
612 gst_speex_enc_set_last_msg (GstSpeexEnc * enc, const gchar * msg)
614 g_free (enc->last_message);
615 enc->last_message = g_strdup (msg);
616 GST_WARNING_OBJECT (enc, "%s", msg);
617 g_object_notify (G_OBJECT (enc), "last-message");
621 gst_speex_enc_setup (GstSpeexEnc * enc)
626 case GST_SPEEX_ENC_MODE_UWB:
627 GST_LOG_OBJECT (enc, "configuring for requested UWB mode");
628 enc->speex_mode = (SpeexMode *) & speex_uwb_mode;
630 case GST_SPEEX_ENC_MODE_WB:
631 GST_LOG_OBJECT (enc, "configuring for requested WB mode");
632 enc->speex_mode = (SpeexMode *) & speex_wb_mode;
634 case GST_SPEEX_ENC_MODE_NB:
635 GST_LOG_OBJECT (enc, "configuring for requested NB mode");
636 enc->speex_mode = (SpeexMode *) & speex_nb_mode;
638 case GST_SPEEX_ENC_MODE_AUTO:
640 GST_LOG_OBJECT (enc, "finding best mode");
645 if (enc->rate > 25000) {
646 if (enc->mode == GST_SPEEX_ENC_MODE_AUTO) {
647 GST_LOG_OBJECT (enc, "selected UWB mode for samplerate %d", enc->rate);
648 enc->speex_mode = (SpeexMode *) & speex_uwb_mode;
650 if (enc->speex_mode != &speex_uwb_mode) {
651 gst_speex_enc_set_last_msg (enc,
652 "Warning: suggest to use ultra wide band mode for this rate");
655 } else if (enc->rate > 12500) {
656 if (enc->mode == GST_SPEEX_ENC_MODE_AUTO) {
657 GST_LOG_OBJECT (enc, "selected WB mode for samplerate %d", enc->rate);
658 enc->speex_mode = (SpeexMode *) & speex_wb_mode;
660 if (enc->speex_mode != &speex_wb_mode) {
661 gst_speex_enc_set_last_msg (enc,
662 "Warning: suggest to use wide band mode for this rate");
666 if (enc->mode == GST_SPEEX_ENC_MODE_AUTO) {
667 GST_LOG_OBJECT (enc, "selected NB mode for samplerate %d", enc->rate);
668 enc->speex_mode = (SpeexMode *) & speex_nb_mode;
670 if (enc->speex_mode != &speex_nb_mode) {
671 gst_speex_enc_set_last_msg (enc,
672 "Warning: suggest to use narrow band mode for this rate");
677 if (enc->rate != 8000 && enc->rate != 16000 && enc->rate != 32000) {
678 gst_speex_enc_set_last_msg (enc,
679 "Warning: speex is optimized for 8, 16 and 32 KHz");
682 speex_init_header (&enc->header, enc->rate, 1, enc->speex_mode);
683 enc->header.frames_per_packet = enc->nframes;
684 enc->header.vbr = enc->vbr;
685 enc->header.nb_channels = enc->channels;
687 /*Initialize Speex encoder */
688 enc->state = speex_encoder_init (enc->speex_mode);
690 speex_encoder_ctl (enc->state, SPEEX_GET_FRAME_SIZE, &enc->frame_size);
691 speex_encoder_ctl (enc->state, SPEEX_SET_COMPLEXITY, &enc->complexity);
692 speex_encoder_ctl (enc->state, SPEEX_SET_SAMPLING_RATE, &enc->rate);
695 speex_encoder_ctl (enc->state, SPEEX_SET_VBR_QUALITY, &enc->quality);
697 gint tmp = floor (enc->quality);
699 speex_encoder_ctl (enc->state, SPEEX_SET_QUALITY, &tmp);
702 if (enc->quality >= 0.0 && enc->vbr) {
703 gst_speex_enc_set_last_msg (enc,
704 "Warning: bitrate option is overriding quality");
706 speex_encoder_ctl (enc->state, SPEEX_SET_BITRATE, &enc->bitrate);
711 speex_encoder_ctl (enc->state, SPEEX_SET_VBR, &tmp);
712 } else if (enc->vad) {
715 speex_encoder_ctl (enc->state, SPEEX_SET_VAD, &tmp);
721 speex_encoder_ctl (enc->state, SPEEX_SET_DTX, &tmp);
724 if (enc->dtx && !(enc->vbr || enc->abr || enc->vad)) {
725 gst_speex_enc_set_last_msg (enc,
726 "Warning: dtx is useless without vad, vbr or abr");
727 } else if ((enc->vbr || enc->abr) && (enc->vad)) {
728 gst_speex_enc_set_last_msg (enc,
729 "Warning: vad is already implied by vbr or abr");
733 speex_encoder_ctl (enc->state, SPEEX_SET_ABR, &enc->abr);
736 speex_encoder_ctl (enc->state, SPEEX_GET_LOOKAHEAD, &enc->lookahead);
738 GST_LOG_OBJECT (enc, "we have frame size %d, lookahead %d", enc->frame_size,
746 /* prepare a buffer for transmission */
748 gst_speex_enc_buffer_from_data (GstSpeexEnc * enc, guchar * data,
749 gint data_len, guint64 granulepos)
753 outbuf = gst_buffer_new_and_alloc (data_len);
754 memcpy (GST_BUFFER_DATA (outbuf), data, data_len);
755 GST_BUFFER_OFFSET (outbuf) = enc->bytes_out;
756 GST_BUFFER_OFFSET_END (outbuf) = granulepos;
758 GST_LOG_OBJECT (enc, "encoded buffer of %d bytes", GST_BUFFER_SIZE (outbuf));
763 /* push out the buffer and do internal bookkeeping */
765 gst_speex_enc_push_buffer (GstSpeexEnc * enc, GstBuffer * buffer)
769 size = GST_BUFFER_SIZE (buffer);
771 enc->bytes_out += size;
773 GST_DEBUG_OBJECT (enc, "pushing output buffer of size %u", size);
775 return gst_pad_push (enc->srcpad, buffer);
779 gst_speex_enc_set_header_on_caps (GstCaps * caps, GstBuffer * buf1,
782 GstStructure *structure = NULL;
784 GValue array = { 0 };
785 GValue value = { 0 };
787 caps = gst_caps_make_writable (caps);
788 structure = gst_caps_get_structure (caps, 0);
790 g_assert (gst_buffer_is_metadata_writable (buf1));
791 g_assert (gst_buffer_is_metadata_writable (buf2));
794 GST_BUFFER_FLAG_SET (buf1, GST_BUFFER_FLAG_IN_CAPS);
795 GST_BUFFER_FLAG_SET (buf2, GST_BUFFER_FLAG_IN_CAPS);
797 /* put buffers in a fixed list */
798 g_value_init (&array, GST_TYPE_ARRAY);
799 g_value_init (&value, GST_TYPE_BUFFER);
800 buf = gst_buffer_copy (buf1);
801 gst_value_set_buffer (&value, buf);
802 gst_buffer_unref (buf);
803 gst_value_array_append_value (&array, &value);
804 g_value_unset (&value);
805 g_value_init (&value, GST_TYPE_BUFFER);
806 buf = gst_buffer_copy (buf2);
807 gst_value_set_buffer (&value, buf);
808 gst_buffer_unref (buf);
809 gst_value_array_append_value (&array, &value);
810 gst_structure_set_value (structure, "streamheader", &array);
811 g_value_unset (&value);
812 g_value_unset (&array);
819 gst_speex_enc_sinkevent (GstPad * pad, GstEvent * event)
824 enc = GST_SPEEX_ENC (gst_pad_get_parent (pad));
826 switch (GST_EVENT_TYPE (event)) {
828 gst_speex_enc_encode (enc, TRUE);
829 res = gst_pad_event_default (pad, event);
835 gst_event_parse_tag (event, &list);
837 gst_tag_list_insert (enc->tags, list,
838 gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (enc)));
840 res = gst_pad_event_default (pad, event);
844 res = gst_pad_event_default (pad, event);
848 gst_object_unref (enc);
854 gst_speex_enc_encode (GstSpeexEnc * enc, gboolean flush)
856 gint frame_size = enc->frame_size;
857 gint bytes = frame_size * 2 * enc->channels;
858 GstFlowReturn ret = GST_FLOW_OK;
860 if (flush && gst_adapter_available (enc->adapter) % bytes != 0) {
861 guint diff = gst_adapter_available (enc->adapter) % bytes;
862 GstBuffer *buf = gst_buffer_new_and_alloc (diff);
864 memset (GST_BUFFER_DATA (buf), 0, diff);
865 gst_adapter_push (enc->adapter, buf);
868 while (gst_adapter_available (enc->adapter) >= bytes) {
871 gint outsize, written;
874 data = (gint16 *) gst_adapter_peek (enc->adapter, bytes);
876 for (i = 0; i < frame_size * enc->channels; i++) {
877 enc->input[i] = (gfloat) data[i];
879 gst_adapter_flush (enc->adapter, bytes);
881 enc->samples_in += frame_size;
883 GST_DEBUG_OBJECT (enc, "encoding %d samples (%d bytes)", frame_size, bytes);
885 if (enc->channels == 2) {
886 speex_encode_stereo (enc->input, frame_size, &enc->bits);
888 speex_encode (enc->state, enc->input, &enc->bits);
893 if ((enc->frameno % enc->nframes) != 0)
896 speex_bits_insert_terminator (&enc->bits);
897 outsize = speex_bits_nbytes (&enc->bits);
899 ret = gst_pad_alloc_buffer_and_set_caps (enc->srcpad,
900 GST_BUFFER_OFFSET_NONE, outsize, GST_PAD_CAPS (enc->srcpad), &outbuf);
902 if ((GST_FLOW_OK != ret))
905 written = speex_bits_write (&enc->bits,
906 (gchar *) GST_BUFFER_DATA (outbuf), outsize);
907 g_assert (written == outsize);
908 speex_bits_reset (&enc->bits);
910 GST_BUFFER_TIMESTAMP (outbuf) = enc->start_ts +
911 gst_util_uint64_scale_int ((enc->frameno_out - 1) * frame_size -
912 enc->lookahead, GST_SECOND, enc->rate);
913 GST_BUFFER_DURATION (outbuf) = gst_util_uint64_scale_int (frame_size,
914 GST_SECOND, enc->rate);
915 /* set gp time and granulepos; see gst-plugins-base/ext/ogg/README */
916 GST_BUFFER_OFFSET_END (outbuf) = enc->granulepos_offset +
917 ((enc->frameno_out) * frame_size - enc->lookahead);
918 GST_BUFFER_OFFSET (outbuf) =
919 gst_util_uint64_scale_int (GST_BUFFER_OFFSET_END (outbuf), GST_SECOND,
922 ret = gst_speex_enc_push_buffer (enc, outbuf);
924 if ((GST_FLOW_OK != ret) && (GST_FLOW_NOT_LINKED != ret))
934 gst_speex_enc_chain (GstPad * pad, GstBuffer * buf)
937 GstFlowReturn ret = GST_FLOW_OK;
939 enc = GST_SPEEX_ENC (GST_PAD_PARENT (pad));
944 if (!enc->header_sent) {
945 /* Speex streams begin with two headers; the initial header (with
946 most of the codec setup parameters) which is mandated by the Ogg
947 bitstream spec. The second header holds any comment fields.
948 We merely need to make the headers, then pass them to libspeex
949 one at a time; libspeex handles the additional Ogg bitstream
951 GstBuffer *buf1, *buf2;
956 /* create header buffer */
957 data = (guint8 *) speex_header_to_packet (&enc->header, &data_len);
958 buf1 = gst_speex_enc_buffer_from_data (enc, data, data_len, 0);
961 /* create comment buffer */
962 buf2 = gst_speex_enc_create_metadata_buffer (enc);
964 /* mark and put on caps */
965 caps = gst_pad_get_caps (enc->srcpad);
966 caps = gst_speex_enc_set_header_on_caps (caps, buf1, buf2);
968 gst_caps_set_simple (caps,
969 "rate", G_TYPE_INT, enc->rate,
970 "channels", G_TYPE_INT, enc->channels, NULL);
972 /* negotiate with these caps */
973 GST_DEBUG_OBJECT (enc, "here are the caps: %" GST_PTR_FORMAT, caps);
974 gst_pad_set_caps (enc->srcpad, caps);
976 gst_buffer_set_caps (buf1, caps);
977 gst_buffer_set_caps (buf2, caps);
978 gst_caps_unref (caps);
980 /* push out buffers */
981 ret = gst_speex_enc_push_buffer (enc, buf1);
983 if (ret != GST_FLOW_OK) {
984 gst_buffer_unref (buf2);
988 ret = gst_speex_enc_push_buffer (enc, buf2);
990 if (ret != GST_FLOW_OK)
993 speex_bits_reset (&enc->bits);
995 enc->header_sent = TRUE;
998 /* Save the timestamp of the first buffer. This will be later
999 * used as offset for all following buffers */
1000 if (enc->start_ts == GST_CLOCK_TIME_NONE) {
1001 if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)) {
1002 enc->start_ts = GST_BUFFER_TIMESTAMP (buf);
1003 enc->granulepos_offset = gst_util_uint64_scale
1004 (GST_BUFFER_TIMESTAMP (buf), enc->rate, GST_SECOND);
1007 enc->granulepos_offset = 0;
1011 /* Check if we have a continous stream, if not drop some samples or the buffer or
1012 * insert some silence samples */
1013 if (enc->next_ts != GST_CLOCK_TIME_NONE &&
1014 GST_BUFFER_TIMESTAMP (buf) < enc->next_ts) {
1015 guint64 diff = enc->next_ts - GST_BUFFER_TIMESTAMP (buf);
1018 GST_WARNING_OBJECT (enc, "Buffer is older than previous "
1019 "timestamp + duration (%" GST_TIME_FORMAT "< %" GST_TIME_FORMAT
1020 "), cannot handle. Clipping buffer.",
1021 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
1022 GST_TIME_ARGS (enc->next_ts));
1024 diff_bytes = GST_CLOCK_TIME_TO_FRAMES (diff, enc->rate) * enc->channels * 2;
1025 if (diff_bytes >= GST_BUFFER_SIZE (buf)) {
1026 gst_buffer_unref (buf);
1029 buf = gst_buffer_make_metadata_writable (buf);
1030 GST_BUFFER_DATA (buf) += diff_bytes;
1031 GST_BUFFER_SIZE (buf) -= diff_bytes;
1033 GST_BUFFER_TIMESTAMP (buf) += diff;
1034 if (GST_BUFFER_DURATION_IS_VALID (buf))
1035 GST_BUFFER_DURATION (buf) -= diff;
1038 if (enc->next_ts != GST_CLOCK_TIME_NONE
1039 && GST_BUFFER_TIMESTAMP_IS_VALID (buf)) {
1041 gst_util_uint64_scale (enc->frame_size, GST_SECOND, enc->rate);
1043 if (GST_BUFFER_TIMESTAMP (buf) != enc->next_ts &&
1044 GST_BUFFER_TIMESTAMP (buf) - enc->next_ts > max_diff) {
1045 GST_WARNING_OBJECT (enc,
1046 "Discontinuity detected: %" G_GUINT64_FORMAT " > %" G_GUINT64_FORMAT,
1047 GST_BUFFER_TIMESTAMP (buf) - enc->next_ts, max_diff);
1049 gst_speex_enc_encode (enc, TRUE);
1051 enc->frameno_out = 0;
1052 enc->start_ts = GST_BUFFER_TIMESTAMP (buf);
1053 enc->granulepos_offset = gst_util_uint64_scale
1054 (GST_BUFFER_TIMESTAMP (buf), enc->rate, GST_SECOND);
1058 if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)
1059 && GST_BUFFER_DURATION_IS_VALID (buf))
1060 enc->next_ts = GST_BUFFER_TIMESTAMP (buf) + GST_BUFFER_DURATION (buf);
1062 enc->next_ts = GST_CLOCK_TIME_NONE;
1064 GST_DEBUG_OBJECT (enc, "received buffer of %u bytes", GST_BUFFER_SIZE (buf));
1066 /* push buffer to adapter */
1067 gst_adapter_push (enc->adapter, buf);
1070 ret = gst_speex_enc_encode (enc, FALSE);
1075 gst_buffer_unref (buf);
1082 GST_ELEMENT_ERROR (enc, CORE, NEGOTIATION, (NULL),
1083 ("encoder not initialized (input is not audio?)"));
1084 ret = GST_FLOW_NOT_NEGOTIATED;
1092 gst_speex_enc_get_property (GObject * object, guint prop_id, GValue * value,
1097 enc = GST_SPEEX_ENC (object);
1101 g_value_set_float (value, enc->quality);
1104 g_value_set_int (value, enc->bitrate);
1107 g_value_set_enum (value, enc->mode);
1110 g_value_set_boolean (value, enc->vbr);
1113 g_value_set_int (value, enc->abr);
1116 g_value_set_boolean (value, enc->vad);
1119 g_value_set_boolean (value, enc->dtx);
1121 case PROP_COMPLEXITY:
1122 g_value_set_int (value, enc->complexity);
1125 g_value_set_int (value, enc->nframes);
1127 case PROP_LAST_MESSAGE:
1128 g_value_set_string (value, enc->last_message);
1131 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1137 gst_speex_enc_set_property (GObject * object, guint prop_id,
1138 const GValue * value, GParamSpec * pspec)
1142 enc = GST_SPEEX_ENC (object);
1146 enc->quality = g_value_get_float (value);
1149 enc->bitrate = g_value_get_int (value);
1152 enc->mode = g_value_get_enum (value);
1155 enc->vbr = g_value_get_boolean (value);
1158 enc->abr = g_value_get_int (value);
1161 enc->vad = g_value_get_boolean (value);
1164 enc->dtx = g_value_get_boolean (value);
1166 case PROP_COMPLEXITY:
1167 enc->complexity = g_value_get_int (value);
1170 enc->nframes = g_value_get_int (value);
1173 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1178 static GstStateChangeReturn
1179 gst_speex_enc_change_state (GstElement * element, GstStateChange transition)
1181 GstSpeexEnc *enc = GST_SPEEX_ENC (element);
1182 GstStateChangeReturn res;
1184 switch (transition) {
1185 case GST_STATE_CHANGE_NULL_TO_READY:
1186 enc->tags = gst_tag_list_new ();
1188 case GST_STATE_CHANGE_READY_TO_PAUSED:
1189 speex_bits_init (&enc->bits);
1191 enc->frameno_out = 0;
1192 enc->samples_in = 0;
1193 enc->start_ts = GST_CLOCK_TIME_NONE;
1194 enc->next_ts = GST_CLOCK_TIME_NONE;
1195 enc->granulepos_offset = 0;
1197 case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
1203 res = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1204 if (res == GST_STATE_CHANGE_FAILURE)
1207 switch (transition) {
1208 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
1210 case GST_STATE_CHANGE_PAUSED_TO_READY:
1212 enc->header_sent = FALSE;
1214 speex_encoder_destroy (enc->state);
1217 speex_bits_destroy (&enc->bits);
1219 case GST_STATE_CHANGE_READY_TO_NULL:
1220 gst_tag_list_free (enc->tags);