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)) {
851 gst_speex_enc_encode (enc, TRUE);
852 res = gst_pad_event_default (pad, event);
859 gst_event_parse_tag (event, &list);
860 gst_tag_list_insert (enc->tags, list,
861 gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (enc)));
863 g_assert_not_reached ();
865 res = gst_pad_event_default (pad, event);
869 res = gst_pad_event_default (pad, event);
873 gst_object_unref (enc);
879 gst_speex_enc_encode (GstSpeexEnc * enc, gboolean flush)
881 gint frame_size = enc->frame_size;
882 gint bytes = frame_size * 2 * enc->channels;
883 GstFlowReturn ret = GST_FLOW_OK;
885 if (flush && gst_adapter_available (enc->adapter) % bytes != 0) {
886 guint diff = gst_adapter_available (enc->adapter) % bytes;
887 GstBuffer *buf = gst_buffer_new_and_alloc (diff);
889 memset (GST_BUFFER_DATA (buf), 0, diff);
890 gst_adapter_push (enc->adapter, buf);
893 while (gst_adapter_available (enc->adapter) >= bytes) {
895 gint outsize, written;
898 data = (gint16 *) gst_adapter_take (enc->adapter, bytes);
900 enc->samples_in += frame_size;
902 GST_DEBUG_OBJECT (enc, "encoding %d samples (%d bytes)", frame_size, bytes);
904 if (enc->channels == 2) {
905 speex_encode_stereo_int (data, frame_size, &enc->bits);
907 speex_encode_int (enc->state, data, &enc->bits);
914 if ((enc->frameno % enc->nframes) != 0)
917 speex_bits_insert_terminator (&enc->bits);
918 outsize = speex_bits_nbytes (&enc->bits);
920 ret = gst_pad_alloc_buffer_and_set_caps (enc->srcpad,
921 GST_BUFFER_OFFSET_NONE, outsize, GST_PAD_CAPS (enc->srcpad), &outbuf);
923 if ((GST_FLOW_OK != ret))
926 written = speex_bits_write (&enc->bits,
927 (gchar *) GST_BUFFER_DATA (outbuf), outsize);
928 g_assert (written == outsize);
929 speex_bits_reset (&enc->bits);
931 GST_BUFFER_TIMESTAMP (outbuf) = enc->start_ts +
932 gst_util_uint64_scale_int ((enc->frameno_out -
933 enc->nframes) * frame_size - enc->lookahead, GST_SECOND, enc->rate);
934 GST_BUFFER_DURATION (outbuf) =
935 gst_util_uint64_scale_int (frame_size * enc->nframes, GST_SECOND,
937 /* set gp time and granulepos; see gst-plugins-base/ext/ogg/README */
938 GST_BUFFER_OFFSET_END (outbuf) = enc->granulepos_offset +
939 ((enc->frameno_out) * frame_size - enc->lookahead);
940 GST_BUFFER_OFFSET (outbuf) =
941 gst_util_uint64_scale_int (GST_BUFFER_OFFSET_END (outbuf), GST_SECOND,
944 ret = gst_speex_enc_push_buffer (enc, outbuf);
946 if ((GST_FLOW_OK != ret) && (GST_FLOW_NOT_LINKED != ret))
956 gst_speex_enc_chain (GstPad * pad, GstBuffer * buf)
959 GstFlowReturn ret = GST_FLOW_OK;
961 enc = GST_SPEEX_ENC (GST_PAD_PARENT (pad));
966 if (!enc->header_sent) {
967 /* Speex streams begin with two headers; the initial header (with
968 most of the codec setup parameters) which is mandated by the Ogg
969 bitstream spec. The second header holds any comment fields.
970 We merely need to make the headers, then pass them to libspeex
971 one at a time; libspeex handles the additional Ogg bitstream
973 GstBuffer *buf1, *buf2;
978 /* create header buffer */
979 data = (guint8 *) speex_header_to_packet (&enc->header, &data_len);
980 buf1 = gst_speex_enc_buffer_from_data (enc, data, data_len, 0);
983 /* create comment buffer */
984 buf2 = gst_speex_enc_create_metadata_buffer (enc);
986 /* mark and put on caps */
987 caps = gst_pad_get_caps (enc->srcpad);
988 caps = gst_speex_enc_set_header_on_caps (caps, buf1, buf2);
990 gst_caps_set_simple (caps,
991 "rate", G_TYPE_INT, enc->rate,
992 "channels", G_TYPE_INT, enc->channels, NULL);
994 /* negotiate with these caps */
995 GST_DEBUG_OBJECT (enc, "here are the caps: %" GST_PTR_FORMAT, caps);
996 gst_pad_set_caps (enc->srcpad, caps);
998 gst_buffer_set_caps (buf1, caps);
999 gst_buffer_set_caps (buf2, caps);
1000 gst_caps_unref (caps);
1002 /* push out buffers */
1003 ret = gst_speex_enc_push_buffer (enc, buf1);
1005 if (ret != GST_FLOW_OK) {
1006 gst_buffer_unref (buf2);
1010 ret = gst_speex_enc_push_buffer (enc, buf2);
1012 if (ret != GST_FLOW_OK)
1015 speex_bits_reset (&enc->bits);
1017 enc->header_sent = TRUE;
1020 /* Save the timestamp of the first buffer. This will be later
1021 * used as offset for all following buffers */
1022 if (enc->start_ts == GST_CLOCK_TIME_NONE) {
1023 if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)) {
1024 enc->start_ts = GST_BUFFER_TIMESTAMP (buf);
1025 enc->granulepos_offset = gst_util_uint64_scale
1026 (GST_BUFFER_TIMESTAMP (buf), enc->rate, GST_SECOND);
1029 enc->granulepos_offset = 0;
1033 /* Check if we have a continous stream, if not drop some samples or the buffer or
1034 * insert some silence samples */
1035 if (enc->next_ts != GST_CLOCK_TIME_NONE &&
1036 GST_BUFFER_TIMESTAMP (buf) < enc->next_ts) {
1037 guint64 diff = enc->next_ts - GST_BUFFER_TIMESTAMP (buf);
1040 GST_WARNING_OBJECT (enc, "Buffer is older than previous "
1041 "timestamp + duration (%" GST_TIME_FORMAT "< %" GST_TIME_FORMAT
1042 "), cannot handle. Clipping buffer.",
1043 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
1044 GST_TIME_ARGS (enc->next_ts));
1046 diff_bytes = GST_CLOCK_TIME_TO_FRAMES (diff, enc->rate) * enc->channels * 2;
1047 if (diff_bytes >= GST_BUFFER_SIZE (buf)) {
1048 gst_buffer_unref (buf);
1051 buf = gst_buffer_make_metadata_writable (buf);
1052 GST_BUFFER_DATA (buf) += diff_bytes;
1053 GST_BUFFER_SIZE (buf) -= diff_bytes;
1055 GST_BUFFER_TIMESTAMP (buf) += diff;
1056 if (GST_BUFFER_DURATION_IS_VALID (buf))
1057 GST_BUFFER_DURATION (buf) -= diff;
1060 if (enc->next_ts != GST_CLOCK_TIME_NONE
1061 && GST_BUFFER_TIMESTAMP_IS_VALID (buf)) {
1063 gst_util_uint64_scale (enc->frame_size, GST_SECOND, enc->rate);
1065 if (GST_BUFFER_TIMESTAMP (buf) != enc->next_ts &&
1066 GST_BUFFER_TIMESTAMP (buf) - enc->next_ts > max_diff) {
1067 GST_WARNING_OBJECT (enc,
1068 "Discontinuity detected: %" G_GUINT64_FORMAT " > %" G_GUINT64_FORMAT,
1069 GST_BUFFER_TIMESTAMP (buf) - enc->next_ts, max_diff);
1071 gst_speex_enc_encode (enc, TRUE);
1073 enc->frameno_out = 0;
1074 enc->start_ts = GST_BUFFER_TIMESTAMP (buf);
1075 enc->granulepos_offset = gst_util_uint64_scale
1076 (GST_BUFFER_TIMESTAMP (buf), enc->rate, GST_SECOND);
1080 if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)
1081 && GST_BUFFER_DURATION_IS_VALID (buf))
1082 enc->next_ts = GST_BUFFER_TIMESTAMP (buf) + GST_BUFFER_DURATION (buf);
1084 enc->next_ts = GST_CLOCK_TIME_NONE;
1086 GST_DEBUG_OBJECT (enc, "received buffer of %u bytes", GST_BUFFER_SIZE (buf));
1088 /* push buffer to adapter */
1089 gst_adapter_push (enc->adapter, buf);
1092 ret = gst_speex_enc_encode (enc, FALSE);
1097 gst_buffer_unref (buf);
1104 GST_ELEMENT_ERROR (enc, CORE, NEGOTIATION, (NULL),
1105 ("encoder not initialized (input is not audio?)"));
1106 ret = GST_FLOW_NOT_NEGOTIATED;
1114 gst_speex_enc_get_property (GObject * object, guint prop_id, GValue * value,
1119 enc = GST_SPEEX_ENC (object);
1123 g_value_set_float (value, enc->quality);
1126 g_value_set_int (value, enc->bitrate);
1129 g_value_set_enum (value, enc->mode);
1132 g_value_set_boolean (value, enc->vbr);
1135 g_value_set_int (value, enc->abr);
1138 g_value_set_boolean (value, enc->vad);
1141 g_value_set_boolean (value, enc->dtx);
1143 case PROP_COMPLEXITY:
1144 g_value_set_int (value, enc->complexity);
1147 g_value_set_int (value, enc->nframes);
1149 case PROP_LAST_MESSAGE:
1150 g_value_set_string (value, enc->last_message);
1153 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1159 gst_speex_enc_set_property (GObject * object, guint prop_id,
1160 const GValue * value, GParamSpec * pspec)
1164 enc = GST_SPEEX_ENC (object);
1168 enc->quality = g_value_get_float (value);
1171 enc->bitrate = g_value_get_int (value);
1174 enc->mode = g_value_get_enum (value);
1177 enc->vbr = g_value_get_boolean (value);
1180 enc->abr = g_value_get_int (value);
1183 enc->vad = g_value_get_boolean (value);
1186 enc->dtx = g_value_get_boolean (value);
1188 case PROP_COMPLEXITY:
1189 enc->complexity = g_value_get_int (value);
1192 enc->nframes = g_value_get_int (value);
1195 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1200 static GstStateChangeReturn
1201 gst_speex_enc_change_state (GstElement * element, GstStateChange transition)
1203 GstSpeexEnc *enc = GST_SPEEX_ENC (element);
1204 GstStateChangeReturn res;
1206 switch (transition) {
1207 case GST_STATE_CHANGE_NULL_TO_READY:
1208 enc->tags = gst_tag_list_new ();
1210 case GST_STATE_CHANGE_READY_TO_PAUSED:
1211 speex_bits_init (&enc->bits);
1213 enc->frameno_out = 0;
1214 enc->samples_in = 0;
1215 enc->start_ts = GST_CLOCK_TIME_NONE;
1216 enc->next_ts = GST_CLOCK_TIME_NONE;
1217 enc->granulepos_offset = 0;
1219 case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
1225 res = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1226 if (res == GST_STATE_CHANGE_FAILURE)
1229 switch (transition) {
1230 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
1232 case GST_STATE_CHANGE_PAUSED_TO_READY:
1234 enc->header_sent = FALSE;
1236 speex_encoder_destroy (enc->state);
1239 speex_bits_destroy (&enc->bits);
1241 case GST_STATE_CHANGE_READY_TO_NULL:
1242 gst_tag_list_free (enc->tags);