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.
21 * SECTION:element-speexenc
22 * @see_also: speexdec, oggmux
24 * This element encodes audio as a Speex stream.
25 * <ulink url="http://www.speex.org/">Speex</ulink> is a royalty-free
26 * audio codec maintained by the <ulink url="http://www.xiph.org/">Xiph.org
30 * <title>Example pipelines</title>
32 * gst-launch audiotestsrc num-buffers=100 ! speexenc ! oggmux ! filesink location=beep.ogg
33 * ]| Encode an Ogg/Speex file.
44 #include <speex/speex.h>
45 #include <speex/speex_stereo.h>
47 #include <gst/gsttagsetter.h>
48 #include <gst/tag/tag.h>
49 #include <gst/audio/audio.h>
50 #include "gstspeexenc.h"
52 GST_DEBUG_CATEGORY_STATIC (speexenc_debug);
53 #define GST_CAT_DEFAULT speexenc_debug
55 static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
58 GST_STATIC_CAPS ("audio/x-raw-int, "
59 "rate = (int) [ 6000, 48000 ], "
60 "channels = (int) [ 1, 2 ], "
61 "endianness = (int) BYTE_ORDER, "
62 "signed = (boolean) TRUE, " "width = (int) 16, " "depth = (int) 16")
65 static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
68 GST_STATIC_CAPS ("audio/x-speex, "
69 "rate = (int) [ 6000, 48000 ], " "channels = (int) [ 1, 2]")
72 #define DEFAULT_QUALITY 8.0
73 #define DEFAULT_BITRATE 0
74 #define DEFAULT_MODE GST_SPEEX_ENC_MODE_AUTO
75 #define DEFAULT_VBR FALSE
77 #define DEFAULT_VAD FALSE
78 #define DEFAULT_DTX FALSE
79 #define DEFAULT_COMPLEXITY 3
80 #define DEFAULT_NFRAMES 1
97 #define GST_TYPE_SPEEX_ENC_MODE (gst_speex_enc_mode_get_type())
99 gst_speex_enc_mode_get_type (void)
101 static GType speex_enc_mode_type = 0;
102 static const GEnumValue speex_enc_modes[] = {
103 {GST_SPEEX_ENC_MODE_AUTO, "Auto", "auto"},
104 {GST_SPEEX_ENC_MODE_UWB, "Ultra Wide Band", "uwb"},
105 {GST_SPEEX_ENC_MODE_WB, "Wide Band", "wb"},
106 {GST_SPEEX_ENC_MODE_NB, "Narrow Band", "nb"},
109 if (G_UNLIKELY (speex_enc_mode_type == 0)) {
110 speex_enc_mode_type = g_enum_register_static ("GstSpeexEncMode",
113 return speex_enc_mode_type;
117 static const GstFormat *
118 gst_speex_enc_get_formats (GstPad * pad)
120 static const GstFormat src_formats[] = {
125 static const GstFormat sink_formats[] = {
132 return (GST_PAD_IS_SRC (pad) ? src_formats : sink_formats);
136 static void gst_speex_enc_finalize (GObject * object);
138 static gboolean gst_speex_enc_sinkevent (GstPad * pad, GstEvent * event);
139 static GstFlowReturn gst_speex_enc_chain (GstPad * pad, GstBuffer * buf);
140 static gboolean gst_speex_enc_setup (GstSpeexEnc * enc);
142 static void gst_speex_enc_get_property (GObject * object, guint prop_id,
143 GValue * value, GParamSpec * pspec);
144 static void gst_speex_enc_set_property (GObject * object, guint prop_id,
145 const GValue * value, GParamSpec * pspec);
146 static GstStateChangeReturn gst_speex_enc_change_state (GstElement * element,
147 GstStateChange transition);
149 static GstFlowReturn gst_speex_enc_encode (GstSpeexEnc * enc, gboolean flush);
152 gst_speex_enc_setup_interfaces (GType speexenc_type)
154 static const GInterfaceInfo tag_setter_info = { NULL, NULL, NULL };
155 const GInterfaceInfo preset_interface_info = {
156 NULL, /* interface_init */
157 NULL, /* interface_finalize */
158 NULL /* interface_data */
161 g_type_add_interface_static (speexenc_type, GST_TYPE_TAG_SETTER,
163 g_type_add_interface_static (speexenc_type, GST_TYPE_PRESET,
164 &preset_interface_info);
166 GST_DEBUG_CATEGORY_INIT (speexenc_debug, "speexenc", 0, "Speex encoder");
169 GST_BOILERPLATE_FULL (GstSpeexEnc, gst_speex_enc, GstElement, GST_TYPE_ELEMENT,
170 gst_speex_enc_setup_interfaces);
173 gst_speex_enc_base_init (gpointer g_class)
175 GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
177 gst_element_class_add_pad_template (element_class,
178 gst_static_pad_template_get (&src_factory));
179 gst_element_class_add_pad_template (element_class,
180 gst_static_pad_template_get (&sink_factory));
181 gst_element_class_set_details_simple (element_class, "Speex audio encoder",
182 "Codec/Encoder/Audio",
183 "Encodes audio in Speex format", "Wim Taymans <wim@fluendo.com>");
187 gst_speex_enc_class_init (GstSpeexEncClass * klass)
189 GObjectClass *gobject_class;
190 GstElementClass *gstelement_class;
192 gobject_class = (GObjectClass *) klass;
193 gstelement_class = (GstElementClass *) klass;
195 gobject_class->set_property = gst_speex_enc_set_property;
196 gobject_class->get_property = gst_speex_enc_get_property;
198 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_QUALITY,
199 g_param_spec_float ("quality", "Quality", "Encoding quality",
200 0.0, 10.0, DEFAULT_QUALITY,
201 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
202 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_BITRATE,
203 g_param_spec_int ("bitrate", "Encoding Bit-rate",
204 "Specify an encoding bit-rate (in bps). (0 = automatic)",
205 0, G_MAXINT, DEFAULT_BITRATE,
206 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
207 g_object_class_install_property (gobject_class, PROP_MODE,
208 g_param_spec_enum ("mode", "Mode", "The encoding mode",
209 GST_TYPE_SPEEX_ENC_MODE, GST_SPEEX_ENC_MODE_AUTO,
210 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
211 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_VBR,
212 g_param_spec_boolean ("vbr", "VBR",
213 "Enable variable bit-rate", DEFAULT_VBR,
214 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
215 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_ABR,
216 g_param_spec_int ("abr", "ABR",
217 "Enable average bit-rate (0 = disabled)",
218 0, G_MAXINT, DEFAULT_ABR,
219 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
220 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_VAD,
221 g_param_spec_boolean ("vad", "VAD",
222 "Enable voice activity detection", DEFAULT_VAD,
223 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
224 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_DTX,
225 g_param_spec_boolean ("dtx", "DTX",
226 "Enable discontinuous transmission", DEFAULT_DTX,
227 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
228 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_COMPLEXITY,
229 g_param_spec_int ("complexity", "Complexity",
230 "Set encoding complexity",
231 0, G_MAXINT, DEFAULT_COMPLEXITY,
232 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
233 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_NFRAMES,
234 g_param_spec_int ("nframes", "NFrames",
235 "Number of frames per buffer",
236 0, G_MAXINT, DEFAULT_NFRAMES,
237 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
238 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_LAST_MESSAGE,
239 g_param_spec_string ("last-message", "last-message",
240 "The last status message", NULL,
241 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
243 gobject_class->finalize = gst_speex_enc_finalize;
245 gstelement_class->change_state =
246 GST_DEBUG_FUNCPTR (gst_speex_enc_change_state);
250 gst_speex_enc_finalize (GObject * object)
254 enc = GST_SPEEX_ENC (object);
256 g_free (enc->last_message);
257 g_object_unref (enc->adapter);
259 G_OBJECT_CLASS (parent_class)->finalize (object);
263 gst_speex_enc_sink_setcaps (GstPad * pad, GstCaps * caps)
266 GstStructure *structure;
268 enc = GST_SPEEX_ENC (GST_PAD_PARENT (pad));
271 structure = gst_caps_get_structure (caps, 0);
272 gst_structure_get_int (structure, "channels", &enc->channels);
273 gst_structure_get_int (structure, "rate", &enc->rate);
275 gst_speex_enc_setup (enc);
282 gst_speex_enc_sink_getcaps (GstPad * pad)
284 GstCaps *caps = gst_caps_copy (gst_pad_get_pad_template_caps (pad));
285 GstCaps *peercaps = NULL;
286 GstSpeexEnc *enc = GST_SPEEX_ENC (gst_pad_get_parent_element (pad));
288 peercaps = gst_pad_peer_get_caps (enc->srcpad);
291 if (!gst_caps_is_empty (peercaps) && !gst_caps_is_any (peercaps)) {
292 GstStructure *ps = gst_caps_get_structure (peercaps, 0);
293 GstStructure *s = gst_caps_get_structure (caps, 0);
296 if (gst_structure_get_int (ps, "rate", &rate)) {
297 gst_structure_fixate_field_nearest_int (s, "rate", rate);
300 if (gst_structure_get_int (ps, "channels", &channels)) {
301 gst_structure_fixate_field_nearest_int (s, "channels", channels);
304 gst_caps_unref (peercaps);
307 gst_object_unref (enc);
314 gst_speex_enc_convert_src (GstPad * pad, GstFormat src_format, gint64 src_value,
315 GstFormat * dest_format, gint64 * dest_value)
321 enc = GST_SPEEX_ENC (GST_PAD_PARENT (pad));
323 if (enc->samples_in == 0 || enc->bytes_out == 0 || enc->rate == 0)
326 avg = (enc->bytes_out * enc->rate) / (enc->samples_in);
328 switch (src_format) {
329 case GST_FORMAT_BYTES:
330 switch (*dest_format) {
331 case GST_FORMAT_TIME:
332 *dest_value = src_value * GST_SECOND / avg;
338 case GST_FORMAT_TIME:
339 switch (*dest_format) {
340 case GST_FORMAT_BYTES:
341 *dest_value = src_value * avg / GST_SECOND;
354 gst_speex_enc_convert_sink (GstPad * pad, GstFormat src_format,
355 gint64 src_value, GstFormat * dest_format, gint64 * dest_value)
359 gint bytes_per_sample;
362 enc = GST_SPEEX_ENC (GST_PAD_PARENT (pad));
364 bytes_per_sample = enc->channels * 2;
366 switch (src_format) {
367 case GST_FORMAT_BYTES:
368 switch (*dest_format) {
369 case GST_FORMAT_DEFAULT:
370 if (bytes_per_sample == 0)
372 *dest_value = src_value / bytes_per_sample;
374 case GST_FORMAT_TIME:
376 gint byterate = bytes_per_sample * enc->rate;
380 *dest_value = src_value * GST_SECOND / byterate;
387 case GST_FORMAT_DEFAULT:
388 switch (*dest_format) {
389 case GST_FORMAT_BYTES:
390 *dest_value = src_value * bytes_per_sample;
392 case GST_FORMAT_TIME:
395 *dest_value = src_value * GST_SECOND / enc->rate;
401 case GST_FORMAT_TIME:
402 switch (*dest_format) {
403 case GST_FORMAT_BYTES:
404 scale = bytes_per_sample;
406 case GST_FORMAT_DEFAULT:
407 *dest_value = src_value * scale * enc->rate / GST_SECOND;
420 gst_speex_enc_get_latency (GstSpeexEnc * enc)
422 /* See the Speex manual section "Latency and algorithmic delay" */
423 if (enc->rate == 8000)
424 return 30 * GST_MSECOND;
426 return 34 * GST_MSECOND;
429 static const GstQueryType *
430 gst_speex_enc_get_query_types (GstPad * pad)
432 static const GstQueryType gst_speex_enc_src_query_types[] = {
440 return gst_speex_enc_src_query_types;
444 gst_speex_enc_src_query (GstPad * pad, GstQuery * query)
449 enc = GST_SPEEX_ENC (gst_pad_get_parent (pad));
451 switch (GST_QUERY_TYPE (query)) {
452 case GST_QUERY_POSITION:
454 GstFormat fmt, req_fmt;
457 gst_query_parse_position (query, &req_fmt, NULL);
458 if ((res = gst_pad_query_peer_position (enc->sinkpad, &req_fmt, &val))) {
459 gst_query_set_position (query, req_fmt, val);
463 fmt = GST_FORMAT_TIME;
464 if (!(res = gst_pad_query_peer_position (enc->sinkpad, &fmt, &pos)))
468 gst_pad_query_peer_convert (enc->sinkpad, fmt, pos, &req_fmt,
470 gst_query_set_position (query, req_fmt, val);
474 case GST_QUERY_DURATION:
476 GstFormat fmt, req_fmt;
479 gst_query_parse_duration (query, &req_fmt, NULL);
480 if ((res = gst_pad_query_peer_duration (enc->sinkpad, &req_fmt, &val))) {
481 gst_query_set_duration (query, req_fmt, val);
485 fmt = GST_FORMAT_TIME;
486 if (!(res = gst_pad_query_peer_duration (enc->sinkpad, &fmt, &dur)))
490 gst_pad_query_peer_convert (enc->sinkpad, fmt, dur, &req_fmt,
492 gst_query_set_duration (query, req_fmt, val);
496 case GST_QUERY_CONVERT:
498 GstFormat src_fmt, dest_fmt;
499 gint64 src_val, dest_val;
501 gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, &dest_val);
502 if (!(res = gst_speex_enc_convert_src (pad, src_fmt, src_val, &dest_fmt,
505 gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val);
508 case GST_QUERY_LATENCY:
511 GstClockTime min_latency, max_latency;
514 if ((res = gst_pad_peer_query (enc->sinkpad, query))) {
515 gst_query_parse_latency (query, &live, &min_latency, &max_latency);
516 GST_LOG_OBJECT (pad, "Upstream latency: %" GST_PTR_FORMAT, query);
518 latency = gst_speex_enc_get_latency (enc);
520 /* add our latency */
521 min_latency += latency;
522 if (max_latency != -1)
523 max_latency += latency;
525 gst_query_set_latency (query, live, min_latency, max_latency);
526 GST_LOG_OBJECT (pad, "Adjusted latency: %" GST_PTR_FORMAT, query);
531 res = gst_pad_peer_query (enc->sinkpad, query);
537 gst_object_unref (enc);
543 gst_speex_enc_sink_query (GstPad * pad, GstQuery * query)
547 switch (GST_QUERY_TYPE (query)) {
548 case GST_QUERY_CONVERT:
550 GstFormat src_fmt, dest_fmt;
551 gint64 src_val, dest_val;
553 gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, &dest_val);
555 gst_speex_enc_convert_sink (pad, src_fmt, src_val, &dest_fmt,
558 gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val);
562 res = gst_pad_query_default (pad, query);
571 gst_speex_enc_init (GstSpeexEnc * enc, GstSpeexEncClass * klass)
573 enc->sinkpad = gst_pad_new_from_static_template (&sink_factory, "sink");
574 gst_element_add_pad (GST_ELEMENT (enc), enc->sinkpad);
575 gst_pad_set_event_function (enc->sinkpad,
576 GST_DEBUG_FUNCPTR (gst_speex_enc_sinkevent));
577 gst_pad_set_chain_function (enc->sinkpad,
578 GST_DEBUG_FUNCPTR (gst_speex_enc_chain));
579 gst_pad_set_setcaps_function (enc->sinkpad,
580 GST_DEBUG_FUNCPTR (gst_speex_enc_sink_setcaps));
581 gst_pad_set_getcaps_function (enc->sinkpad,
582 GST_DEBUG_FUNCPTR (gst_speex_enc_sink_getcaps));
583 gst_pad_set_query_function (enc->sinkpad,
584 GST_DEBUG_FUNCPTR (gst_speex_enc_sink_query));
586 enc->srcpad = gst_pad_new_from_static_template (&src_factory, "src");
587 gst_pad_set_query_function (enc->srcpad,
588 GST_DEBUG_FUNCPTR (gst_speex_enc_src_query));
589 gst_pad_set_query_type_function (enc->srcpad,
590 GST_DEBUG_FUNCPTR (gst_speex_enc_get_query_types));
591 gst_element_add_pad (GST_ELEMENT (enc), enc->srcpad);
596 enc->quality = DEFAULT_QUALITY;
597 enc->bitrate = DEFAULT_BITRATE;
598 enc->mode = DEFAULT_MODE;
599 enc->vbr = DEFAULT_VBR;
600 enc->abr = DEFAULT_ABR;
601 enc->vad = DEFAULT_VAD;
602 enc->dtx = DEFAULT_DTX;
603 enc->complexity = DEFAULT_COMPLEXITY;
604 enc->nframes = DEFAULT_NFRAMES;
607 enc->header_sent = FALSE;
609 enc->adapter = gst_adapter_new ();
613 gst_speex_enc_create_metadata_buffer (GstSpeexEnc * enc)
615 const GstTagList *user_tags;
616 GstTagList *merged_tags;
617 GstBuffer *comments = NULL;
619 user_tags = gst_tag_setter_get_tag_list (GST_TAG_SETTER (enc));
621 GST_DEBUG_OBJECT (enc, "upstream tags = %" GST_PTR_FORMAT, enc->tags);
622 GST_DEBUG_OBJECT (enc, "user-set tags = %" GST_PTR_FORMAT, user_tags);
624 /* gst_tag_list_merge() will handle NULL for either or both lists fine */
625 merged_tags = gst_tag_list_merge (user_tags, enc->tags,
626 gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (enc)));
628 if (merged_tags == NULL)
629 merged_tags = gst_tag_list_new ();
631 GST_DEBUG_OBJECT (enc, "merged tags = %" GST_PTR_FORMAT, merged_tags);
632 comments = gst_tag_list_to_vorbiscomment_buffer (merged_tags, NULL,
633 0, "Encoded with GStreamer Speexenc");
634 gst_tag_list_free (merged_tags);
636 GST_BUFFER_OFFSET (comments) = enc->bytes_out;
637 GST_BUFFER_OFFSET_END (comments) = 0;
643 gst_speex_enc_set_last_msg (GstSpeexEnc * enc, const gchar * msg)
645 g_free (enc->last_message);
646 enc->last_message = g_strdup (msg);
647 GST_WARNING_OBJECT (enc, "%s", msg);
648 g_object_notify (G_OBJECT (enc), "last-message");
652 gst_speex_enc_setup (GstSpeexEnc * enc)
657 case GST_SPEEX_ENC_MODE_UWB:
658 GST_LOG_OBJECT (enc, "configuring for requested UWB mode");
659 enc->speex_mode = speex_lib_get_mode (SPEEX_MODEID_UWB);
661 case GST_SPEEX_ENC_MODE_WB:
662 GST_LOG_OBJECT (enc, "configuring for requested WB mode");
663 enc->speex_mode = speex_lib_get_mode (SPEEX_MODEID_WB);
665 case GST_SPEEX_ENC_MODE_NB:
666 GST_LOG_OBJECT (enc, "configuring for requested NB mode");
667 enc->speex_mode = speex_lib_get_mode (SPEEX_MODEID_NB);
669 case GST_SPEEX_ENC_MODE_AUTO:
671 GST_LOG_OBJECT (enc, "finding best mode");
676 if (enc->rate > 25000) {
677 if (enc->mode == GST_SPEEX_ENC_MODE_AUTO) {
678 GST_LOG_OBJECT (enc, "selected UWB mode for samplerate %d", enc->rate);
679 enc->speex_mode = speex_lib_get_mode (SPEEX_MODEID_UWB);
681 if (enc->speex_mode != speex_lib_get_mode (SPEEX_MODEID_UWB)) {
682 gst_speex_enc_set_last_msg (enc,
683 "Warning: suggest to use ultra wide band mode for this rate");
686 } else if (enc->rate > 12500) {
687 if (enc->mode == GST_SPEEX_ENC_MODE_AUTO) {
688 GST_LOG_OBJECT (enc, "selected WB mode for samplerate %d", enc->rate);
689 enc->speex_mode = speex_lib_get_mode (SPEEX_MODEID_WB);
691 if (enc->speex_mode != speex_lib_get_mode (SPEEX_MODEID_WB)) {
692 gst_speex_enc_set_last_msg (enc,
693 "Warning: suggest to use wide band mode for this rate");
697 if (enc->mode == GST_SPEEX_ENC_MODE_AUTO) {
698 GST_LOG_OBJECT (enc, "selected NB mode for samplerate %d", enc->rate);
699 enc->speex_mode = speex_lib_get_mode (SPEEX_MODEID_NB);
701 if (enc->speex_mode != speex_lib_get_mode (SPEEX_MODEID_NB)) {
702 gst_speex_enc_set_last_msg (enc,
703 "Warning: suggest to use narrow band mode for this rate");
708 if (enc->rate != 8000 && enc->rate != 16000 && enc->rate != 32000) {
709 gst_speex_enc_set_last_msg (enc,
710 "Warning: speex is optimized for 8, 16 and 32 KHz");
713 speex_init_header (&enc->header, enc->rate, 1, enc->speex_mode);
714 enc->header.frames_per_packet = enc->nframes;
715 enc->header.vbr = enc->vbr;
716 enc->header.nb_channels = enc->channels;
718 /*Initialize Speex encoder */
719 enc->state = speex_encoder_init (enc->speex_mode);
721 speex_encoder_ctl (enc->state, SPEEX_GET_FRAME_SIZE, &enc->frame_size);
722 speex_encoder_ctl (enc->state, SPEEX_SET_COMPLEXITY, &enc->complexity);
723 speex_encoder_ctl (enc->state, SPEEX_SET_SAMPLING_RATE, &enc->rate);
726 speex_encoder_ctl (enc->state, SPEEX_SET_VBR_QUALITY, &enc->quality);
728 gint tmp = floor (enc->quality);
730 speex_encoder_ctl (enc->state, SPEEX_SET_QUALITY, &tmp);
733 if (enc->quality >= 0.0 && enc->vbr) {
734 gst_speex_enc_set_last_msg (enc,
735 "Warning: bitrate option is overriding quality");
737 speex_encoder_ctl (enc->state, SPEEX_SET_BITRATE, &enc->bitrate);
742 speex_encoder_ctl (enc->state, SPEEX_SET_VBR, &tmp);
743 } else if (enc->vad) {
746 speex_encoder_ctl (enc->state, SPEEX_SET_VAD, &tmp);
752 speex_encoder_ctl (enc->state, SPEEX_SET_DTX, &tmp);
755 if (enc->dtx && !(enc->vbr || enc->abr || enc->vad)) {
756 gst_speex_enc_set_last_msg (enc,
757 "Warning: dtx is useless without vad, vbr or abr");
758 } else if ((enc->vbr || enc->abr) && (enc->vad)) {
759 gst_speex_enc_set_last_msg (enc,
760 "Warning: vad is already implied by vbr or abr");
764 speex_encoder_ctl (enc->state, SPEEX_SET_ABR, &enc->abr);
767 speex_encoder_ctl (enc->state, SPEEX_GET_LOOKAHEAD, &enc->lookahead);
769 GST_LOG_OBJECT (enc, "we have frame size %d, lookahead %d", enc->frame_size,
777 /* prepare a buffer for transmission */
779 gst_speex_enc_buffer_from_data (GstSpeexEnc * enc, guchar * data,
780 gint data_len, guint64 granulepos)
784 outbuf = gst_buffer_new_and_alloc (data_len);
785 memcpy (GST_BUFFER_DATA (outbuf), data, data_len);
786 GST_BUFFER_OFFSET (outbuf) = enc->bytes_out;
787 GST_BUFFER_OFFSET_END (outbuf) = granulepos;
789 GST_LOG_OBJECT (enc, "encoded buffer of %d bytes", GST_BUFFER_SIZE (outbuf));
794 /* push out the buffer and do internal bookkeeping */
796 gst_speex_enc_push_buffer (GstSpeexEnc * enc, GstBuffer * buffer)
800 size = GST_BUFFER_SIZE (buffer);
802 enc->bytes_out += size;
804 GST_DEBUG_OBJECT (enc, "pushing output buffer of size %u", size);
806 return gst_pad_push (enc->srcpad, buffer);
810 gst_speex_enc_set_header_on_caps (GstCaps * caps, GstBuffer * buf1,
813 GstStructure *structure = NULL;
815 GValue array = { 0 };
816 GValue value = { 0 };
818 caps = gst_caps_make_writable (caps);
819 structure = gst_caps_get_structure (caps, 0);
821 g_assert (gst_buffer_is_metadata_writable (buf1));
822 g_assert (gst_buffer_is_metadata_writable (buf2));
825 GST_BUFFER_FLAG_SET (buf1, GST_BUFFER_FLAG_IN_CAPS);
826 GST_BUFFER_FLAG_SET (buf2, GST_BUFFER_FLAG_IN_CAPS);
828 /* put buffers in a fixed list */
829 g_value_init (&array, GST_TYPE_ARRAY);
830 g_value_init (&value, GST_TYPE_BUFFER);
831 buf = gst_buffer_copy (buf1);
832 gst_value_set_buffer (&value, buf);
833 gst_buffer_unref (buf);
834 gst_value_array_append_value (&array, &value);
835 g_value_unset (&value);
836 g_value_init (&value, GST_TYPE_BUFFER);
837 buf = gst_buffer_copy (buf2);
838 gst_value_set_buffer (&value, buf);
839 gst_buffer_unref (buf);
840 gst_value_array_append_value (&array, &value);
841 gst_structure_set_value (structure, "streamheader", &array);
842 g_value_unset (&value);
843 g_value_unset (&array);
850 gst_speex_enc_sinkevent (GstPad * pad, GstEvent * event)
855 enc = GST_SPEEX_ENC (gst_pad_get_parent (pad));
857 switch (GST_EVENT_TYPE (event)) {
860 gst_speex_enc_encode (enc, TRUE);
861 res = gst_pad_event_default (pad, event);
868 gst_event_parse_tag (event, &list);
869 gst_tag_list_insert (enc->tags, list,
870 gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (enc)));
872 g_assert_not_reached ();
874 res = gst_pad_event_default (pad, event);
878 res = gst_pad_event_default (pad, event);
882 gst_object_unref (enc);
888 gst_speex_enc_encode (GstSpeexEnc * enc, gboolean flush)
890 gint frame_size = enc->frame_size;
891 gint bytes = frame_size * 2 * enc->channels;
892 GstFlowReturn ret = GST_FLOW_OK;
894 if (flush && gst_adapter_available (enc->adapter) % bytes != 0) {
895 guint diff = gst_adapter_available (enc->adapter) % bytes;
896 GstBuffer *buf = gst_buffer_new_and_alloc (diff);
898 memset (GST_BUFFER_DATA (buf), 0, diff);
899 gst_adapter_push (enc->adapter, buf);
902 while (gst_adapter_available (enc->adapter) >= bytes) {
904 gint outsize, written, dtx_ret;
907 data = (gint16 *) gst_adapter_take (enc->adapter, bytes);
909 enc->samples_in += frame_size;
911 GST_DEBUG_OBJECT (enc, "encoding %d samples (%d bytes)", frame_size, bytes);
913 if (enc->channels == 2) {
914 speex_encode_stereo_int (data, frame_size, &enc->bits);
916 dtx_ret = speex_encode_int (enc->state, data, &enc->bits);
923 if ((enc->frameno % enc->nframes) != 0)
926 speex_bits_insert_terminator (&enc->bits);
927 outsize = speex_bits_nbytes (&enc->bits);
929 ret = gst_pad_alloc_buffer_and_set_caps (enc->srcpad,
930 GST_BUFFER_OFFSET_NONE, outsize, GST_PAD_CAPS (enc->srcpad), &outbuf);
932 if ((GST_FLOW_OK != ret))
935 written = speex_bits_write (&enc->bits,
936 (gchar *) GST_BUFFER_DATA (outbuf), outsize);
938 if (G_UNLIKELY (written != outsize)) {
939 GST_ERROR_OBJECT (enc, "short write: %d < %d bytes", written, outsize);
940 GST_BUFFER_SIZE (outbuf) = written;
943 speex_bits_reset (&enc->bits);
946 GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_GAP);
948 GST_BUFFER_TIMESTAMP (outbuf) = enc->start_ts +
949 gst_util_uint64_scale_int ((enc->frameno_out -
950 enc->nframes) * frame_size - enc->lookahead, GST_SECOND, enc->rate);
951 GST_BUFFER_DURATION (outbuf) =
952 gst_util_uint64_scale_int (frame_size * enc->nframes, GST_SECOND,
954 /* set gp time and granulepos; see gst-plugins-base/ext/ogg/README */
955 GST_BUFFER_OFFSET_END (outbuf) = enc->granulepos_offset +
956 ((enc->frameno_out) * frame_size - enc->lookahead);
957 GST_BUFFER_OFFSET (outbuf) =
958 gst_util_uint64_scale_int (GST_BUFFER_OFFSET_END (outbuf), GST_SECOND,
961 ret = gst_speex_enc_push_buffer (enc, outbuf);
963 if ((GST_FLOW_OK != ret) && (GST_FLOW_NOT_LINKED != ret))
973 gst_speex_enc_chain (GstPad * pad, GstBuffer * buf)
976 GstFlowReturn ret = GST_FLOW_OK;
978 enc = GST_SPEEX_ENC (GST_PAD_PARENT (pad));
983 if (!enc->header_sent) {
984 /* Speex streams begin with two headers; the initial header (with
985 most of the codec setup parameters) which is mandated by the Ogg
986 bitstream spec. The second header holds any comment fields.
987 We merely need to make the headers, then pass them to libspeex
988 one at a time; libspeex handles the additional Ogg bitstream
990 GstBuffer *buf1, *buf2;
995 /* create header buffer */
996 data = (guint8 *) speex_header_to_packet (&enc->header, &data_len);
997 buf1 = gst_speex_enc_buffer_from_data (enc, data, data_len, 0);
1000 /* create comment buffer */
1001 buf2 = gst_speex_enc_create_metadata_buffer (enc);
1003 /* mark and put on caps */
1004 caps = gst_pad_get_caps (enc->srcpad);
1005 caps = gst_speex_enc_set_header_on_caps (caps, buf1, buf2);
1007 gst_caps_set_simple (caps,
1008 "rate", G_TYPE_INT, enc->rate,
1009 "channels", G_TYPE_INT, enc->channels, NULL);
1011 /* negotiate with these caps */
1012 GST_DEBUG_OBJECT (enc, "here are the caps: %" GST_PTR_FORMAT, caps);
1013 gst_pad_set_caps (enc->srcpad, caps);
1015 gst_buffer_set_caps (buf1, caps);
1016 gst_buffer_set_caps (buf2, caps);
1017 gst_caps_unref (caps);
1019 /* push out buffers */
1020 ret = gst_speex_enc_push_buffer (enc, buf1);
1022 if (ret != GST_FLOW_OK) {
1023 gst_buffer_unref (buf2);
1027 ret = gst_speex_enc_push_buffer (enc, buf2);
1029 if (ret != GST_FLOW_OK)
1032 speex_bits_reset (&enc->bits);
1034 enc->header_sent = TRUE;
1037 /* Save the timestamp of the first buffer. This will be later
1038 * used as offset for all following buffers */
1039 if (enc->start_ts == GST_CLOCK_TIME_NONE) {
1040 if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)) {
1041 enc->start_ts = GST_BUFFER_TIMESTAMP (buf);
1042 enc->granulepos_offset = gst_util_uint64_scale
1043 (GST_BUFFER_TIMESTAMP (buf), enc->rate, GST_SECOND);
1046 enc->granulepos_offset = 0;
1050 /* Check if we have a continous stream, if not drop some samples or the buffer or
1051 * insert some silence samples */
1052 if (enc->next_ts != GST_CLOCK_TIME_NONE &&
1053 GST_BUFFER_TIMESTAMP (buf) < enc->next_ts) {
1054 guint64 diff = enc->next_ts - GST_BUFFER_TIMESTAMP (buf);
1057 GST_WARNING_OBJECT (enc, "Buffer is older than previous "
1058 "timestamp + duration (%" GST_TIME_FORMAT "< %" GST_TIME_FORMAT
1059 "), cannot handle. Clipping buffer.",
1060 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
1061 GST_TIME_ARGS (enc->next_ts));
1063 diff_bytes = GST_CLOCK_TIME_TO_FRAMES (diff, enc->rate) * enc->channels * 2;
1064 if (diff_bytes >= GST_BUFFER_SIZE (buf)) {
1065 gst_buffer_unref (buf);
1068 buf = gst_buffer_make_metadata_writable (buf);
1069 GST_BUFFER_DATA (buf) += diff_bytes;
1070 GST_BUFFER_SIZE (buf) -= diff_bytes;
1072 GST_BUFFER_TIMESTAMP (buf) += diff;
1073 if (GST_BUFFER_DURATION_IS_VALID (buf))
1074 GST_BUFFER_DURATION (buf) -= diff;
1077 if (enc->next_ts != GST_CLOCK_TIME_NONE
1078 && GST_BUFFER_TIMESTAMP_IS_VALID (buf)) {
1080 gst_util_uint64_scale (enc->frame_size, GST_SECOND, enc->rate);
1082 if (GST_BUFFER_TIMESTAMP (buf) != enc->next_ts &&
1083 GST_BUFFER_TIMESTAMP (buf) - enc->next_ts > max_diff) {
1084 GST_WARNING_OBJECT (enc,
1085 "Discontinuity detected: %" G_GUINT64_FORMAT " > %" G_GUINT64_FORMAT,
1086 GST_BUFFER_TIMESTAMP (buf) - enc->next_ts, max_diff);
1088 gst_speex_enc_encode (enc, TRUE);
1090 enc->frameno_out = 0;
1091 enc->start_ts = GST_BUFFER_TIMESTAMP (buf);
1092 enc->granulepos_offset = gst_util_uint64_scale
1093 (GST_BUFFER_TIMESTAMP (buf), enc->rate, GST_SECOND);
1097 if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)
1098 && GST_BUFFER_DURATION_IS_VALID (buf))
1099 enc->next_ts = GST_BUFFER_TIMESTAMP (buf) + GST_BUFFER_DURATION (buf);
1101 enc->next_ts = GST_CLOCK_TIME_NONE;
1103 GST_DEBUG_OBJECT (enc, "received buffer of %u bytes", GST_BUFFER_SIZE (buf));
1105 /* push buffer to adapter */
1106 gst_adapter_push (enc->adapter, buf);
1109 ret = gst_speex_enc_encode (enc, FALSE);
1114 gst_buffer_unref (buf);
1121 GST_ELEMENT_ERROR (enc, CORE, NEGOTIATION, (NULL),
1122 ("encoder not initialized (input is not audio?)"));
1123 ret = GST_FLOW_NOT_NEGOTIATED;
1131 gst_speex_enc_get_property (GObject * object, guint prop_id, GValue * value,
1136 enc = GST_SPEEX_ENC (object);
1140 g_value_set_float (value, enc->quality);
1143 g_value_set_int (value, enc->bitrate);
1146 g_value_set_enum (value, enc->mode);
1149 g_value_set_boolean (value, enc->vbr);
1152 g_value_set_int (value, enc->abr);
1155 g_value_set_boolean (value, enc->vad);
1158 g_value_set_boolean (value, enc->dtx);
1160 case PROP_COMPLEXITY:
1161 g_value_set_int (value, enc->complexity);
1164 g_value_set_int (value, enc->nframes);
1166 case PROP_LAST_MESSAGE:
1167 g_value_set_string (value, enc->last_message);
1170 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1176 gst_speex_enc_set_property (GObject * object, guint prop_id,
1177 const GValue * value, GParamSpec * pspec)
1181 enc = GST_SPEEX_ENC (object);
1185 enc->quality = g_value_get_float (value);
1188 enc->bitrate = g_value_get_int (value);
1191 enc->mode = g_value_get_enum (value);
1194 enc->vbr = g_value_get_boolean (value);
1197 enc->abr = g_value_get_int (value);
1200 enc->vad = g_value_get_boolean (value);
1203 enc->dtx = g_value_get_boolean (value);
1205 case PROP_COMPLEXITY:
1206 enc->complexity = g_value_get_int (value);
1209 enc->nframes = g_value_get_int (value);
1212 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1217 static GstStateChangeReturn
1218 gst_speex_enc_change_state (GstElement * element, GstStateChange transition)
1220 GstSpeexEnc *enc = GST_SPEEX_ENC (element);
1221 GstStateChangeReturn res;
1223 switch (transition) {
1224 case GST_STATE_CHANGE_NULL_TO_READY:
1225 enc->tags = gst_tag_list_new ();
1227 case GST_STATE_CHANGE_READY_TO_PAUSED:
1228 speex_bits_init (&enc->bits);
1230 enc->frameno_out = 0;
1231 enc->samples_in = 0;
1232 enc->start_ts = GST_CLOCK_TIME_NONE;
1233 enc->next_ts = GST_CLOCK_TIME_NONE;
1234 enc->granulepos_offset = 0;
1236 case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
1242 res = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1243 if (res == GST_STATE_CHANGE_FAILURE)
1246 switch (transition) {
1247 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
1249 case GST_STATE_CHANGE_PAUSED_TO_READY:
1251 enc->header_sent = FALSE;
1253 speex_encoder_destroy (enc->state);
1256 speex_bits_destroy (&enc->bits);
1258 case GST_STATE_CHANGE_READY_TO_NULL:
1259 gst_tag_list_free (enc->tags);