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 static const GstElementDetails speexenc_details =
73 GST_ELEMENT_DETAILS ("Speex audio encoder",
74 "Codec/Encoder/Audio",
75 "Encodes audio in Speex format",
76 "Wim Taymans <wim@fluendo.com>");
78 #define DEFAULT_QUALITY 8.0
79 #define DEFAULT_BITRATE 0
80 #define DEFAULT_MODE GST_SPEEX_ENC_MODE_AUTO
81 #define DEFAULT_VBR FALSE
83 #define DEFAULT_VAD FALSE
84 #define DEFAULT_DTX FALSE
85 #define DEFAULT_COMPLEXITY 3
86 #define DEFAULT_NFRAMES 1
103 #define GST_TYPE_SPEEX_ENC_MODE (gst_speex_enc_mode_get_type())
105 gst_speex_enc_mode_get_type (void)
107 static GType speex_enc_mode_type = 0;
108 static const GEnumValue speex_enc_modes[] = {
109 {GST_SPEEX_ENC_MODE_AUTO, "Auto", "auto"},
110 {GST_SPEEX_ENC_MODE_UWB, "Ultra Wide Band", "uwb"},
111 {GST_SPEEX_ENC_MODE_WB, "Wide Band", "wb"},
112 {GST_SPEEX_ENC_MODE_NB, "Narrow Band", "nb"},
115 if (G_UNLIKELY (speex_enc_mode_type == 0)) {
116 speex_enc_mode_type = g_enum_register_static ("GstSpeexEncMode",
119 return speex_enc_mode_type;
123 static const GstFormat *
124 gst_speex_enc_get_formats (GstPad * pad)
126 static const GstFormat src_formats[] = {
131 static const GstFormat sink_formats[] = {
138 return (GST_PAD_IS_SRC (pad) ? src_formats : sink_formats);
142 static void gst_speex_enc_finalize (GObject * object);
144 static gboolean gst_speex_enc_sinkevent (GstPad * pad, GstEvent * event);
145 static GstFlowReturn gst_speex_enc_chain (GstPad * pad, GstBuffer * buf);
146 static gboolean gst_speex_enc_setup (GstSpeexEnc * enc);
148 static void gst_speex_enc_get_property (GObject * object, guint prop_id,
149 GValue * value, GParamSpec * pspec);
150 static void gst_speex_enc_set_property (GObject * object, guint prop_id,
151 const GValue * value, GParamSpec * pspec);
152 static GstStateChangeReturn gst_speex_enc_change_state (GstElement * element,
153 GstStateChange transition);
155 static GstFlowReturn gst_speex_enc_encode (GstSpeexEnc * enc, gboolean flush);
158 gst_speex_enc_setup_interfaces (GType speexenc_type)
160 static const GInterfaceInfo tag_setter_info = { NULL, NULL, NULL };
161 const GInterfaceInfo preset_interface_info = {
162 NULL, /* interface_init */
163 NULL, /* interface_finalize */
164 NULL /* interface_data */
167 g_type_add_interface_static (speexenc_type, GST_TYPE_TAG_SETTER,
169 g_type_add_interface_static (speexenc_type, GST_TYPE_PRESET,
170 &preset_interface_info);
172 GST_DEBUG_CATEGORY_INIT (speexenc_debug, "speexenc", 0, "Speex encoder");
175 GST_BOILERPLATE_FULL (GstSpeexEnc, gst_speex_enc, GstElement, GST_TYPE_ELEMENT,
176 gst_speex_enc_setup_interfaces);
179 gst_speex_enc_base_init (gpointer g_class)
181 GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
183 gst_element_class_add_pad_template (element_class,
184 gst_static_pad_template_get (&src_factory));
185 gst_element_class_add_pad_template (element_class,
186 gst_static_pad_template_get (&sink_factory));
187 gst_element_class_set_details (element_class, &speexenc_details);
191 gst_speex_enc_class_init (GstSpeexEncClass * klass)
193 GObjectClass *gobject_class;
194 GstElementClass *gstelement_class;
196 gobject_class = (GObjectClass *) klass;
197 gstelement_class = (GstElementClass *) klass;
199 gobject_class->set_property = gst_speex_enc_set_property;
200 gobject_class->get_property = gst_speex_enc_get_property;
202 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_QUALITY,
203 g_param_spec_float ("quality", "Quality", "Encoding quality",
204 0.0, 10.0, DEFAULT_QUALITY, G_PARAM_READWRITE));
205 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_BITRATE,
206 g_param_spec_int ("bitrate", "Encoding Bit-rate",
207 "Specify an encoding bit-rate (in bps). (0 = automatic)",
208 0, G_MAXINT, DEFAULT_BITRATE, G_PARAM_READWRITE));
209 g_object_class_install_property (gobject_class, PROP_MODE,
210 g_param_spec_enum ("mode", "Mode", "The encoding mode",
211 GST_TYPE_SPEEX_ENC_MODE, GST_SPEEX_ENC_MODE_AUTO,
212 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
213 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_VBR,
214 g_param_spec_boolean ("vbr", "VBR",
215 "Enable variable bit-rate", DEFAULT_VBR, G_PARAM_READWRITE));
216 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_ABR,
217 g_param_spec_int ("abr", "ABR",
218 "Enable average bit-rate (0 = disabled)",
219 0, G_MAXINT, DEFAULT_ABR, G_PARAM_READWRITE));
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, G_PARAM_READWRITE));
223 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_DTX,
224 g_param_spec_boolean ("dtx", "DTX",
225 "Enable discontinuous transmission", DEFAULT_DTX, G_PARAM_READWRITE));
226 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_COMPLEXITY,
227 g_param_spec_int ("complexity", "Complexity",
228 "Set encoding complexity",
229 0, G_MAXINT, DEFAULT_COMPLEXITY, G_PARAM_READWRITE));
230 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_NFRAMES,
231 g_param_spec_int ("nframes", "NFrames",
232 "Number of frames per buffer",
233 0, G_MAXINT, DEFAULT_NFRAMES, G_PARAM_READWRITE));
234 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_LAST_MESSAGE,
235 g_param_spec_string ("last-message", "last-message",
236 "The last status message", NULL, G_PARAM_READABLE));
238 gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_speex_enc_finalize);
240 gstelement_class->change_state =
241 GST_DEBUG_FUNCPTR (gst_speex_enc_change_state);
245 gst_speex_enc_finalize (GObject * object)
249 enc = GST_SPEEX_ENC (object);
251 g_free (enc->last_message);
252 g_object_unref (enc->adapter);
254 G_OBJECT_CLASS (parent_class)->finalize (object);
258 gst_speex_enc_sink_setcaps (GstPad * pad, GstCaps * caps)
261 GstStructure *structure;
263 enc = GST_SPEEX_ENC (GST_PAD_PARENT (pad));
266 structure = gst_caps_get_structure (caps, 0);
267 gst_structure_get_int (structure, "channels", &enc->channels);
268 gst_structure_get_int (structure, "rate", &enc->rate);
270 gst_speex_enc_setup (enc);
277 gst_speex_enc_sink_getcaps (GstPad * pad)
279 GstCaps *caps = gst_caps_copy (gst_pad_get_pad_template_caps (pad));
280 GstCaps *peercaps = NULL;
281 GstSpeexEnc *enc = GST_SPEEX_ENC (gst_pad_get_parent_element (pad));
283 peercaps = gst_pad_peer_get_caps (enc->srcpad);
286 if (!gst_caps_is_empty (peercaps) && !gst_caps_is_any (peercaps)) {
287 GstStructure *ps = gst_caps_get_structure (peercaps, 0);
288 GstStructure *s = gst_caps_get_structure (caps, 0);
291 if (gst_structure_get_int (ps, "rate", &rate)) {
292 gst_structure_fixate_field_nearest_int (s, "rate", rate);
295 if (gst_structure_get_int (ps, "channels", &channels)) {
296 gst_structure_fixate_field_nearest_int (s, "channels", channels);
299 gst_caps_unref (peercaps);
302 gst_object_unref (enc);
309 gst_speex_enc_convert_src (GstPad * pad, GstFormat src_format, gint64 src_value,
310 GstFormat * dest_format, gint64 * dest_value)
316 enc = GST_SPEEX_ENC (GST_PAD_PARENT (pad));
318 if (enc->samples_in == 0 || enc->bytes_out == 0 || enc->rate == 0)
321 avg = (enc->bytes_out * enc->rate) / (enc->samples_in);
323 switch (src_format) {
324 case GST_FORMAT_BYTES:
325 switch (*dest_format) {
326 case GST_FORMAT_TIME:
327 *dest_value = src_value * GST_SECOND / avg;
333 case GST_FORMAT_TIME:
334 switch (*dest_format) {
335 case GST_FORMAT_BYTES:
336 *dest_value = src_value * avg / GST_SECOND;
349 gst_speex_enc_convert_sink (GstPad * pad, GstFormat src_format,
350 gint64 src_value, GstFormat * dest_format, gint64 * dest_value)
354 gint bytes_per_sample;
357 enc = GST_SPEEX_ENC (GST_PAD_PARENT (pad));
359 bytes_per_sample = enc->channels * 2;
361 switch (src_format) {
362 case GST_FORMAT_BYTES:
363 switch (*dest_format) {
364 case GST_FORMAT_DEFAULT:
365 if (bytes_per_sample == 0)
367 *dest_value = src_value / bytes_per_sample;
369 case GST_FORMAT_TIME:
371 gint byterate = bytes_per_sample * enc->rate;
375 *dest_value = src_value * GST_SECOND / byterate;
382 case GST_FORMAT_DEFAULT:
383 switch (*dest_format) {
384 case GST_FORMAT_BYTES:
385 *dest_value = src_value * bytes_per_sample;
387 case GST_FORMAT_TIME:
390 *dest_value = src_value * GST_SECOND / enc->rate;
396 case GST_FORMAT_TIME:
397 switch (*dest_format) {
398 case GST_FORMAT_BYTES:
399 scale = bytes_per_sample;
401 case GST_FORMAT_DEFAULT:
402 *dest_value = src_value * scale * enc->rate / GST_SECOND;
415 gst_speex_enc_get_latency (GstSpeexEnc * enc)
417 return 30 * GST_MSECOND;
420 static const GstQueryType *
421 gst_speex_enc_get_query_types (GstPad * pad)
423 static const GstQueryType gst_speex_enc_src_query_types[] = {
431 return gst_speex_enc_src_query_types;
435 gst_speex_enc_src_query (GstPad * pad, GstQuery * query)
440 enc = GST_SPEEX_ENC (gst_pad_get_parent (pad));
442 switch (GST_QUERY_TYPE (query)) {
443 case GST_QUERY_POSITION:
445 GstFormat fmt, req_fmt;
448 gst_query_parse_position (query, &req_fmt, NULL);
449 if ((res = gst_pad_query_peer_position (enc->sinkpad, &req_fmt, &val))) {
450 gst_query_set_position (query, req_fmt, val);
454 fmt = GST_FORMAT_TIME;
455 if (!(res = gst_pad_query_peer_position (enc->sinkpad, &fmt, &pos)))
459 gst_pad_query_peer_convert (enc->sinkpad, fmt, pos, &req_fmt,
461 gst_query_set_position (query, req_fmt, val);
465 case GST_QUERY_DURATION:
467 GstFormat fmt, req_fmt;
470 gst_query_parse_duration (query, &req_fmt, NULL);
471 if ((res = gst_pad_query_peer_duration (enc->sinkpad, &req_fmt, &val))) {
472 gst_query_set_duration (query, req_fmt, val);
476 fmt = GST_FORMAT_TIME;
477 if (!(res = gst_pad_query_peer_duration (enc->sinkpad, &fmt, &dur)))
481 gst_pad_query_peer_convert (enc->sinkpad, fmt, dur, &req_fmt,
483 gst_query_set_duration (query, req_fmt, val);
487 case GST_QUERY_CONVERT:
489 GstFormat src_fmt, dest_fmt;
490 gint64 src_val, dest_val;
492 gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, &dest_val);
493 if (!(res = gst_speex_enc_convert_src (pad, src_fmt, src_val, &dest_fmt,
496 gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val);
499 case GST_QUERY_LATENCY:
502 GstClockTime min_latency, max_latency;
505 if ((res = gst_pad_peer_query (enc->sinkpad, query))) {
506 gst_query_parse_latency (query, &live, &min_latency, &max_latency);
507 GST_LOG_OBJECT (pad, "Upstream latency: %" GST_PTR_FORMAT, query);
509 latency = gst_speex_enc_get_latency (enc);
511 /* add our latency */
512 min_latency += latency;
513 if (max_latency != -1)
514 max_latency += latency;
516 gst_query_set_latency (query, live, min_latency, max_latency);
517 GST_LOG_OBJECT (pad, "Adjusted latency: %" GST_PTR_FORMAT, query);
522 res = gst_pad_peer_query (enc->sinkpad, query);
528 gst_object_unref (enc);
534 gst_speex_enc_sink_query (GstPad * pad, GstQuery * query)
538 switch (GST_QUERY_TYPE (query)) {
539 case GST_QUERY_CONVERT:
541 GstFormat src_fmt, dest_fmt;
542 gint64 src_val, dest_val;
544 gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, &dest_val);
546 gst_speex_enc_convert_sink (pad, src_fmt, src_val, &dest_fmt,
549 gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val);
553 res = gst_pad_query_default (pad, query);
562 gst_speex_enc_init (GstSpeexEnc * enc, GstSpeexEncClass * klass)
564 enc->sinkpad = gst_pad_new_from_static_template (&sink_factory, "sink");
565 gst_element_add_pad (GST_ELEMENT (enc), enc->sinkpad);
566 gst_pad_set_event_function (enc->sinkpad,
567 GST_DEBUG_FUNCPTR (gst_speex_enc_sinkevent));
568 gst_pad_set_chain_function (enc->sinkpad,
569 GST_DEBUG_FUNCPTR (gst_speex_enc_chain));
570 gst_pad_set_setcaps_function (enc->sinkpad,
571 GST_DEBUG_FUNCPTR (gst_speex_enc_sink_setcaps));
572 gst_pad_set_getcaps_function (enc->sinkpad,
573 GST_DEBUG_FUNCPTR (gst_speex_enc_sink_getcaps));
574 gst_pad_set_query_function (enc->sinkpad,
575 GST_DEBUG_FUNCPTR (gst_speex_enc_sink_query));
577 enc->srcpad = gst_pad_new_from_static_template (&src_factory, "src");
578 gst_pad_set_query_function (enc->srcpad,
579 GST_DEBUG_FUNCPTR (gst_speex_enc_src_query));
580 gst_pad_set_query_type_function (enc->srcpad,
581 GST_DEBUG_FUNCPTR (gst_speex_enc_get_query_types));
582 gst_element_add_pad (GST_ELEMENT (enc), enc->srcpad);
587 enc->quality = DEFAULT_QUALITY;
588 enc->bitrate = DEFAULT_BITRATE;
589 enc->mode = DEFAULT_MODE;
590 enc->vbr = DEFAULT_VBR;
591 enc->abr = DEFAULT_ABR;
592 enc->vad = DEFAULT_VAD;
593 enc->dtx = DEFAULT_DTX;
594 enc->complexity = DEFAULT_COMPLEXITY;
595 enc->nframes = DEFAULT_NFRAMES;
598 enc->header_sent = FALSE;
600 enc->adapter = gst_adapter_new ();
604 gst_speex_enc_create_metadata_buffer (GstSpeexEnc * enc)
606 const GstTagList *user_tags;
607 GstTagList *merged_tags;
608 GstBuffer *comments = NULL;
610 user_tags = gst_tag_setter_get_tag_list (GST_TAG_SETTER (enc));
612 GST_DEBUG_OBJECT (enc, "upstream tags = %" GST_PTR_FORMAT, enc->tags);
613 GST_DEBUG_OBJECT (enc, "user-set tags = %" GST_PTR_FORMAT, user_tags);
615 /* gst_tag_list_merge() will handle NULL for either or both lists fine */
616 merged_tags = gst_tag_list_merge (user_tags, enc->tags,
617 gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (enc)));
619 if (merged_tags == NULL)
620 merged_tags = gst_tag_list_new ();
622 GST_DEBUG_OBJECT (enc, "merged tags = %" GST_PTR_FORMAT, merged_tags);
623 comments = gst_tag_list_to_vorbiscomment_buffer (merged_tags, NULL,
624 0, "Encoded with GStreamer Speexenc");
625 gst_tag_list_free (merged_tags);
627 GST_BUFFER_OFFSET (comments) = enc->bytes_out;
628 GST_BUFFER_OFFSET_END (comments) = 0;
634 gst_speex_enc_set_last_msg (GstSpeexEnc * enc, const gchar * msg)
636 g_free (enc->last_message);
637 enc->last_message = g_strdup (msg);
638 GST_WARNING_OBJECT (enc, "%s", msg);
639 g_object_notify (G_OBJECT (enc), "last-message");
643 gst_speex_enc_setup (GstSpeexEnc * enc)
648 case GST_SPEEX_ENC_MODE_UWB:
649 GST_LOG_OBJECT (enc, "configuring for requested UWB mode");
650 enc->speex_mode = (SpeexMode *) & speex_uwb_mode;
652 case GST_SPEEX_ENC_MODE_WB:
653 GST_LOG_OBJECT (enc, "configuring for requested WB mode");
654 enc->speex_mode = (SpeexMode *) & speex_wb_mode;
656 case GST_SPEEX_ENC_MODE_NB:
657 GST_LOG_OBJECT (enc, "configuring for requested NB mode");
658 enc->speex_mode = (SpeexMode *) & speex_nb_mode;
660 case GST_SPEEX_ENC_MODE_AUTO:
662 GST_LOG_OBJECT (enc, "finding best mode");
667 if (enc->rate > 25000) {
668 if (enc->mode == GST_SPEEX_ENC_MODE_AUTO) {
669 GST_LOG_OBJECT (enc, "selected UWB mode for samplerate %d", enc->rate);
670 enc->speex_mode = (SpeexMode *) & speex_uwb_mode;
672 if (enc->speex_mode != &speex_uwb_mode) {
673 gst_speex_enc_set_last_msg (enc,
674 "Warning: suggest to use ultra wide band mode for this rate");
677 } else if (enc->rate > 12500) {
678 if (enc->mode == GST_SPEEX_ENC_MODE_AUTO) {
679 GST_LOG_OBJECT (enc, "selected WB mode for samplerate %d", enc->rate);
680 enc->speex_mode = (SpeexMode *) & speex_wb_mode;
682 if (enc->speex_mode != &speex_wb_mode) {
683 gst_speex_enc_set_last_msg (enc,
684 "Warning: suggest to use wide band mode for this rate");
688 if (enc->mode == GST_SPEEX_ENC_MODE_AUTO) {
689 GST_LOG_OBJECT (enc, "selected NB mode for samplerate %d", enc->rate);
690 enc->speex_mode = (SpeexMode *) & speex_nb_mode;
692 if (enc->speex_mode != &speex_nb_mode) {
693 gst_speex_enc_set_last_msg (enc,
694 "Warning: suggest to use narrow band mode for this rate");
699 if (enc->rate != 8000 && enc->rate != 16000 && enc->rate != 32000) {
700 gst_speex_enc_set_last_msg (enc,
701 "Warning: speex is optimized for 8, 16 and 32 KHz");
704 speex_init_header (&enc->header, enc->rate, 1, enc->speex_mode);
705 enc->header.frames_per_packet = enc->nframes;
706 enc->header.vbr = enc->vbr;
707 enc->header.nb_channels = enc->channels;
709 /*Initialize Speex encoder */
710 enc->state = speex_encoder_init (enc->speex_mode);
712 speex_encoder_ctl (enc->state, SPEEX_GET_FRAME_SIZE, &enc->frame_size);
713 speex_encoder_ctl (enc->state, SPEEX_SET_COMPLEXITY, &enc->complexity);
714 speex_encoder_ctl (enc->state, SPEEX_SET_SAMPLING_RATE, &enc->rate);
717 speex_encoder_ctl (enc->state, SPEEX_SET_VBR_QUALITY, &enc->quality);
719 gint tmp = floor (enc->quality);
721 speex_encoder_ctl (enc->state, SPEEX_SET_QUALITY, &tmp);
724 if (enc->quality >= 0.0 && enc->vbr) {
725 gst_speex_enc_set_last_msg (enc,
726 "Warning: bitrate option is overriding quality");
728 speex_encoder_ctl (enc->state, SPEEX_SET_BITRATE, &enc->bitrate);
733 speex_encoder_ctl (enc->state, SPEEX_SET_VBR, &tmp);
734 } else if (enc->vad) {
737 speex_encoder_ctl (enc->state, SPEEX_SET_VAD, &tmp);
743 speex_encoder_ctl (enc->state, SPEEX_SET_DTX, &tmp);
746 if (enc->dtx && !(enc->vbr || enc->abr || enc->vad)) {
747 gst_speex_enc_set_last_msg (enc,
748 "Warning: dtx is useless without vad, vbr or abr");
749 } else if ((enc->vbr || enc->abr) && (enc->vad)) {
750 gst_speex_enc_set_last_msg (enc,
751 "Warning: vad is already implied by vbr or abr");
755 speex_encoder_ctl (enc->state, SPEEX_SET_ABR, &enc->abr);
758 speex_encoder_ctl (enc->state, SPEEX_GET_LOOKAHEAD, &enc->lookahead);
760 GST_LOG_OBJECT (enc, "we have frame size %d, lookahead %d", enc->frame_size,
768 /* prepare a buffer for transmission */
770 gst_speex_enc_buffer_from_data (GstSpeexEnc * enc, guchar * data,
771 gint data_len, guint64 granulepos)
775 outbuf = gst_buffer_new_and_alloc (data_len);
776 memcpy (GST_BUFFER_DATA (outbuf), data, data_len);
777 GST_BUFFER_OFFSET (outbuf) = enc->bytes_out;
778 GST_BUFFER_OFFSET_END (outbuf) = granulepos;
780 GST_LOG_OBJECT (enc, "encoded buffer of %d bytes", GST_BUFFER_SIZE (outbuf));
785 /* push out the buffer and do internal bookkeeping */
787 gst_speex_enc_push_buffer (GstSpeexEnc * enc, GstBuffer * buffer)
791 size = GST_BUFFER_SIZE (buffer);
793 enc->bytes_out += size;
795 GST_DEBUG_OBJECT (enc, "pushing output buffer of size %u", size);
797 return gst_pad_push (enc->srcpad, buffer);
801 gst_speex_enc_set_header_on_caps (GstCaps * caps, GstBuffer * buf1,
804 GstStructure *structure = NULL;
806 GValue array = { 0 };
807 GValue value = { 0 };
809 caps = gst_caps_make_writable (caps);
810 structure = gst_caps_get_structure (caps, 0);
812 g_assert (gst_buffer_is_metadata_writable (buf1));
813 g_assert (gst_buffer_is_metadata_writable (buf2));
816 GST_BUFFER_FLAG_SET (buf1, GST_BUFFER_FLAG_IN_CAPS);
817 GST_BUFFER_FLAG_SET (buf2, GST_BUFFER_FLAG_IN_CAPS);
819 /* put buffers in a fixed list */
820 g_value_init (&array, GST_TYPE_ARRAY);
821 g_value_init (&value, GST_TYPE_BUFFER);
822 buf = gst_buffer_copy (buf1);
823 gst_value_set_buffer (&value, buf);
824 gst_buffer_unref (buf);
825 gst_value_array_append_value (&array, &value);
826 g_value_unset (&value);
827 g_value_init (&value, GST_TYPE_BUFFER);
828 buf = gst_buffer_copy (buf2);
829 gst_value_set_buffer (&value, buf);
830 gst_buffer_unref (buf);
831 gst_value_array_append_value (&array, &value);
832 gst_structure_set_value (structure, "streamheader", &array);
833 g_value_unset (&value);
834 g_value_unset (&array);
841 gst_speex_enc_sinkevent (GstPad * pad, GstEvent * event)
846 enc = GST_SPEEX_ENC (gst_pad_get_parent (pad));
848 switch (GST_EVENT_TYPE (event)) {
850 gst_speex_enc_encode (enc, TRUE);
851 res = gst_pad_event_default (pad, event);
857 gst_event_parse_tag (event, &list);
859 gst_tag_list_insert (enc->tags, list,
860 gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (enc)));
862 res = gst_pad_event_default (pad, event);
866 res = gst_pad_event_default (pad, event);
870 gst_object_unref (enc);
876 gst_speex_enc_encode (GstSpeexEnc * enc, gboolean flush)
878 gint frame_size = enc->frame_size;
879 gint bytes = frame_size * 2 * enc->channels;
880 GstFlowReturn ret = GST_FLOW_OK;
882 if (flush && gst_adapter_available (enc->adapter) % bytes != 0) {
883 guint diff = gst_adapter_available (enc->adapter) % bytes;
884 GstBuffer *buf = gst_buffer_new_and_alloc (diff);
886 memset (GST_BUFFER_DATA (buf), 0, diff);
887 gst_adapter_push (enc->adapter, buf);
890 while (gst_adapter_available (enc->adapter) >= bytes) {
892 gint outsize, written;
895 data = (gint16 *) gst_adapter_take (enc->adapter, bytes);
897 enc->samples_in += frame_size;
899 GST_DEBUG_OBJECT (enc, "encoding %d samples (%d bytes)", frame_size, bytes);
901 if (enc->channels == 2) {
902 speex_encode_stereo_int (data, frame_size, &enc->bits);
904 speex_encode_int (enc->state, data, &enc->bits);
911 if ((enc->frameno % enc->nframes) != 0)
914 speex_bits_insert_terminator (&enc->bits);
915 outsize = speex_bits_nbytes (&enc->bits);
917 ret = gst_pad_alloc_buffer_and_set_caps (enc->srcpad,
918 GST_BUFFER_OFFSET_NONE, outsize, GST_PAD_CAPS (enc->srcpad), &outbuf);
920 if ((GST_FLOW_OK != ret))
923 written = speex_bits_write (&enc->bits,
924 (gchar *) GST_BUFFER_DATA (outbuf), outsize);
925 g_assert (written == outsize);
926 speex_bits_reset (&enc->bits);
928 GST_BUFFER_TIMESTAMP (outbuf) = enc->start_ts +
929 gst_util_uint64_scale_int ((enc->frameno_out - 1) * frame_size -
930 enc->lookahead, GST_SECOND, enc->rate);
931 GST_BUFFER_DURATION (outbuf) = gst_util_uint64_scale_int (frame_size,
932 GST_SECOND, enc->rate);
933 /* set gp time and granulepos; see gst-plugins-base/ext/ogg/README */
934 GST_BUFFER_OFFSET_END (outbuf) = enc->granulepos_offset +
935 ((enc->frameno_out) * frame_size - enc->lookahead);
936 GST_BUFFER_OFFSET (outbuf) =
937 gst_util_uint64_scale_int (GST_BUFFER_OFFSET_END (outbuf), GST_SECOND,
940 ret = gst_speex_enc_push_buffer (enc, outbuf);
942 if ((GST_FLOW_OK != ret) && (GST_FLOW_NOT_LINKED != ret))
952 gst_speex_enc_chain (GstPad * pad, GstBuffer * buf)
955 GstFlowReturn ret = GST_FLOW_OK;
957 enc = GST_SPEEX_ENC (GST_PAD_PARENT (pad));
962 if (!enc->header_sent) {
963 /* Speex streams begin with two headers; the initial header (with
964 most of the codec setup parameters) which is mandated by the Ogg
965 bitstream spec. The second header holds any comment fields.
966 We merely need to make the headers, then pass them to libspeex
967 one at a time; libspeex handles the additional Ogg bitstream
969 GstBuffer *buf1, *buf2;
974 /* create header buffer */
975 data = (guint8 *) speex_header_to_packet (&enc->header, &data_len);
976 buf1 = gst_speex_enc_buffer_from_data (enc, data, data_len, 0);
979 /* create comment buffer */
980 buf2 = gst_speex_enc_create_metadata_buffer (enc);
982 /* mark and put on caps */
983 caps = gst_pad_get_caps (enc->srcpad);
984 caps = gst_speex_enc_set_header_on_caps (caps, buf1, buf2);
986 gst_caps_set_simple (caps,
987 "rate", G_TYPE_INT, enc->rate,
988 "channels", G_TYPE_INT, enc->channels, NULL);
990 /* negotiate with these caps */
991 GST_DEBUG_OBJECT (enc, "here are the caps: %" GST_PTR_FORMAT, caps);
992 gst_pad_set_caps (enc->srcpad, caps);
994 gst_buffer_set_caps (buf1, caps);
995 gst_buffer_set_caps (buf2, caps);
996 gst_caps_unref (caps);
998 /* push out buffers */
999 ret = gst_speex_enc_push_buffer (enc, buf1);
1001 if (ret != GST_FLOW_OK) {
1002 gst_buffer_unref (buf2);
1006 ret = gst_speex_enc_push_buffer (enc, buf2);
1008 if (ret != GST_FLOW_OK)
1011 speex_bits_reset (&enc->bits);
1013 enc->header_sent = TRUE;
1016 /* Save the timestamp of the first buffer. This will be later
1017 * used as offset for all following buffers */
1018 if (enc->start_ts == GST_CLOCK_TIME_NONE) {
1019 if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)) {
1020 enc->start_ts = GST_BUFFER_TIMESTAMP (buf);
1021 enc->granulepos_offset = gst_util_uint64_scale
1022 (GST_BUFFER_TIMESTAMP (buf), enc->rate, GST_SECOND);
1025 enc->granulepos_offset = 0;
1029 /* Check if we have a continous stream, if not drop some samples or the buffer or
1030 * insert some silence samples */
1031 if (enc->next_ts != GST_CLOCK_TIME_NONE &&
1032 GST_BUFFER_TIMESTAMP (buf) < enc->next_ts) {
1033 guint64 diff = enc->next_ts - GST_BUFFER_TIMESTAMP (buf);
1036 GST_WARNING_OBJECT (enc, "Buffer is older than previous "
1037 "timestamp + duration (%" GST_TIME_FORMAT "< %" GST_TIME_FORMAT
1038 "), cannot handle. Clipping buffer.",
1039 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
1040 GST_TIME_ARGS (enc->next_ts));
1042 diff_bytes = GST_CLOCK_TIME_TO_FRAMES (diff, enc->rate) * enc->channels * 2;
1043 if (diff_bytes >= GST_BUFFER_SIZE (buf)) {
1044 gst_buffer_unref (buf);
1047 buf = gst_buffer_make_metadata_writable (buf);
1048 GST_BUFFER_DATA (buf) += diff_bytes;
1049 GST_BUFFER_SIZE (buf) -= diff_bytes;
1051 GST_BUFFER_TIMESTAMP (buf) += diff;
1052 if (GST_BUFFER_DURATION_IS_VALID (buf))
1053 GST_BUFFER_DURATION (buf) -= diff;
1056 if (enc->next_ts != GST_CLOCK_TIME_NONE
1057 && GST_BUFFER_TIMESTAMP_IS_VALID (buf)) {
1059 gst_util_uint64_scale (enc->frame_size, GST_SECOND, enc->rate);
1061 if (GST_BUFFER_TIMESTAMP (buf) != enc->next_ts &&
1062 GST_BUFFER_TIMESTAMP (buf) - enc->next_ts > max_diff) {
1063 GST_WARNING_OBJECT (enc,
1064 "Discontinuity detected: %" G_GUINT64_FORMAT " > %" G_GUINT64_FORMAT,
1065 GST_BUFFER_TIMESTAMP (buf) - enc->next_ts, max_diff);
1067 gst_speex_enc_encode (enc, TRUE);
1069 enc->frameno_out = 0;
1070 enc->start_ts = GST_BUFFER_TIMESTAMP (buf);
1071 enc->granulepos_offset = gst_util_uint64_scale
1072 (GST_BUFFER_TIMESTAMP (buf), enc->rate, GST_SECOND);
1076 if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)
1077 && GST_BUFFER_DURATION_IS_VALID (buf))
1078 enc->next_ts = GST_BUFFER_TIMESTAMP (buf) + GST_BUFFER_DURATION (buf);
1080 enc->next_ts = GST_CLOCK_TIME_NONE;
1082 GST_DEBUG_OBJECT (enc, "received buffer of %u bytes", GST_BUFFER_SIZE (buf));
1084 /* push buffer to adapter */
1085 gst_adapter_push (enc->adapter, buf);
1088 ret = gst_speex_enc_encode (enc, FALSE);
1093 gst_buffer_unref (buf);
1100 GST_ELEMENT_ERROR (enc, CORE, NEGOTIATION, (NULL),
1101 ("encoder not initialized (input is not audio?)"));
1102 ret = GST_FLOW_NOT_NEGOTIATED;
1110 gst_speex_enc_get_property (GObject * object, guint prop_id, GValue * value,
1115 enc = GST_SPEEX_ENC (object);
1119 g_value_set_float (value, enc->quality);
1122 g_value_set_int (value, enc->bitrate);
1125 g_value_set_enum (value, enc->mode);
1128 g_value_set_boolean (value, enc->vbr);
1131 g_value_set_int (value, enc->abr);
1134 g_value_set_boolean (value, enc->vad);
1137 g_value_set_boolean (value, enc->dtx);
1139 case PROP_COMPLEXITY:
1140 g_value_set_int (value, enc->complexity);
1143 g_value_set_int (value, enc->nframes);
1145 case PROP_LAST_MESSAGE:
1146 g_value_set_string (value, enc->last_message);
1149 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1155 gst_speex_enc_set_property (GObject * object, guint prop_id,
1156 const GValue * value, GParamSpec * pspec)
1160 enc = GST_SPEEX_ENC (object);
1164 enc->quality = g_value_get_float (value);
1167 enc->bitrate = g_value_get_int (value);
1170 enc->mode = g_value_get_enum (value);
1173 enc->vbr = g_value_get_boolean (value);
1176 enc->abr = g_value_get_int (value);
1179 enc->vad = g_value_get_boolean (value);
1182 enc->dtx = g_value_get_boolean (value);
1184 case PROP_COMPLEXITY:
1185 enc->complexity = g_value_get_int (value);
1188 enc->nframes = g_value_get_int (value);
1191 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1196 static GstStateChangeReturn
1197 gst_speex_enc_change_state (GstElement * element, GstStateChange transition)
1199 GstSpeexEnc *enc = GST_SPEEX_ENC (element);
1200 GstStateChangeReturn res;
1202 switch (transition) {
1203 case GST_STATE_CHANGE_NULL_TO_READY:
1204 enc->tags = gst_tag_list_new ();
1206 case GST_STATE_CHANGE_READY_TO_PAUSED:
1207 speex_bits_init (&enc->bits);
1209 enc->frameno_out = 0;
1210 enc->samples_in = 0;
1211 enc->start_ts = GST_CLOCK_TIME_NONE;
1212 enc->next_ts = GST_CLOCK_TIME_NONE;
1213 enc->granulepos_offset = 0;
1215 case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
1221 res = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1222 if (res == GST_STATE_CHANGE_FAILURE)
1225 switch (transition) {
1226 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
1228 case GST_STATE_CHANGE_PAUSED_TO_READY:
1230 enc->header_sent = FALSE;
1232 speex_encoder_destroy (enc->state);
1235 speex_bits_destroy (&enc->bits);
1237 case GST_STATE_CHANGE_READY_TO_NULL:
1238 gst_tag_list_free (enc->tags);