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);
858 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 g_assert_not_reached ();
864 res = gst_pad_event_default (pad, event);
868 res = gst_pad_event_default (pad, event);
872 gst_object_unref (enc);
878 gst_speex_enc_encode (GstSpeexEnc * enc, gboolean flush)
880 gint frame_size = enc->frame_size;
881 gint bytes = frame_size * 2 * enc->channels;
882 GstFlowReturn ret = GST_FLOW_OK;
884 if (flush && gst_adapter_available (enc->adapter) % bytes != 0) {
885 guint diff = gst_adapter_available (enc->adapter) % bytes;
886 GstBuffer *buf = gst_buffer_new_and_alloc (diff);
888 memset (GST_BUFFER_DATA (buf), 0, diff);
889 gst_adapter_push (enc->adapter, buf);
892 while (gst_adapter_available (enc->adapter) >= bytes) {
894 gint outsize, written;
897 data = (gint16 *) gst_adapter_take (enc->adapter, bytes);
899 enc->samples_in += frame_size;
901 GST_DEBUG_OBJECT (enc, "encoding %d samples (%d bytes)", frame_size, bytes);
903 if (enc->channels == 2) {
904 speex_encode_stereo_int (data, frame_size, &enc->bits);
906 speex_encode_int (enc->state, data, &enc->bits);
913 if ((enc->frameno % enc->nframes) != 0)
916 speex_bits_insert_terminator (&enc->bits);
917 outsize = speex_bits_nbytes (&enc->bits);
919 ret = gst_pad_alloc_buffer_and_set_caps (enc->srcpad,
920 GST_BUFFER_OFFSET_NONE, outsize, GST_PAD_CAPS (enc->srcpad), &outbuf);
922 if ((GST_FLOW_OK != ret))
925 written = speex_bits_write (&enc->bits,
926 (gchar *) GST_BUFFER_DATA (outbuf), outsize);
927 g_assert (written == outsize);
928 speex_bits_reset (&enc->bits);
930 GST_BUFFER_TIMESTAMP (outbuf) = enc->start_ts +
931 gst_util_uint64_scale_int ((enc->frameno_out -
932 enc->nframes) * frame_size - enc->lookahead, GST_SECOND, enc->rate);
933 GST_BUFFER_DURATION (outbuf) =
934 gst_util_uint64_scale_int (frame_size * enc->nframes, GST_SECOND,
936 /* set gp time and granulepos; see gst-plugins-base/ext/ogg/README */
937 GST_BUFFER_OFFSET_END (outbuf) = enc->granulepos_offset +
938 ((enc->frameno_out) * frame_size - enc->lookahead);
939 GST_BUFFER_OFFSET (outbuf) =
940 gst_util_uint64_scale_int (GST_BUFFER_OFFSET_END (outbuf), GST_SECOND,
943 ret = gst_speex_enc_push_buffer (enc, outbuf);
945 if ((GST_FLOW_OK != ret) && (GST_FLOW_NOT_LINKED != ret))
955 gst_speex_enc_chain (GstPad * pad, GstBuffer * buf)
958 GstFlowReturn ret = GST_FLOW_OK;
960 enc = GST_SPEEX_ENC (GST_PAD_PARENT (pad));
965 if (!enc->header_sent) {
966 /* Speex streams begin with two headers; the initial header (with
967 most of the codec setup parameters) which is mandated by the Ogg
968 bitstream spec. The second header holds any comment fields.
969 We merely need to make the headers, then pass them to libspeex
970 one at a time; libspeex handles the additional Ogg bitstream
972 GstBuffer *buf1, *buf2;
977 /* create header buffer */
978 data = (guint8 *) speex_header_to_packet (&enc->header, &data_len);
979 buf1 = gst_speex_enc_buffer_from_data (enc, data, data_len, 0);
982 /* create comment buffer */
983 buf2 = gst_speex_enc_create_metadata_buffer (enc);
985 /* mark and put on caps */
986 caps = gst_pad_get_caps (enc->srcpad);
987 caps = gst_speex_enc_set_header_on_caps (caps, buf1, buf2);
989 gst_caps_set_simple (caps,
990 "rate", G_TYPE_INT, enc->rate,
991 "channels", G_TYPE_INT, enc->channels, NULL);
993 /* negotiate with these caps */
994 GST_DEBUG_OBJECT (enc, "here are the caps: %" GST_PTR_FORMAT, caps);
995 gst_pad_set_caps (enc->srcpad, caps);
997 gst_buffer_set_caps (buf1, caps);
998 gst_buffer_set_caps (buf2, caps);
999 gst_caps_unref (caps);
1001 /* push out buffers */
1002 ret = gst_speex_enc_push_buffer (enc, buf1);
1004 if (ret != GST_FLOW_OK) {
1005 gst_buffer_unref (buf2);
1009 ret = gst_speex_enc_push_buffer (enc, buf2);
1011 if (ret != GST_FLOW_OK)
1014 speex_bits_reset (&enc->bits);
1016 enc->header_sent = TRUE;
1019 /* Save the timestamp of the first buffer. This will be later
1020 * used as offset for all following buffers */
1021 if (enc->start_ts == GST_CLOCK_TIME_NONE) {
1022 if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)) {
1023 enc->start_ts = GST_BUFFER_TIMESTAMP (buf);
1024 enc->granulepos_offset = gst_util_uint64_scale
1025 (GST_BUFFER_TIMESTAMP (buf), enc->rate, GST_SECOND);
1028 enc->granulepos_offset = 0;
1032 /* Check if we have a continous stream, if not drop some samples or the buffer or
1033 * insert some silence samples */
1034 if (enc->next_ts != GST_CLOCK_TIME_NONE &&
1035 GST_BUFFER_TIMESTAMP (buf) < enc->next_ts) {
1036 guint64 diff = enc->next_ts - GST_BUFFER_TIMESTAMP (buf);
1039 GST_WARNING_OBJECT (enc, "Buffer is older than previous "
1040 "timestamp + duration (%" GST_TIME_FORMAT "< %" GST_TIME_FORMAT
1041 "), cannot handle. Clipping buffer.",
1042 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
1043 GST_TIME_ARGS (enc->next_ts));
1045 diff_bytes = GST_CLOCK_TIME_TO_FRAMES (diff, enc->rate) * enc->channels * 2;
1046 if (diff_bytes >= GST_BUFFER_SIZE (buf)) {
1047 gst_buffer_unref (buf);
1050 buf = gst_buffer_make_metadata_writable (buf);
1051 GST_BUFFER_DATA (buf) += diff_bytes;
1052 GST_BUFFER_SIZE (buf) -= diff_bytes;
1054 GST_BUFFER_TIMESTAMP (buf) += diff;
1055 if (GST_BUFFER_DURATION_IS_VALID (buf))
1056 GST_BUFFER_DURATION (buf) -= diff;
1059 if (enc->next_ts != GST_CLOCK_TIME_NONE
1060 && GST_BUFFER_TIMESTAMP_IS_VALID (buf)) {
1062 gst_util_uint64_scale (enc->frame_size, GST_SECOND, enc->rate);
1064 if (GST_BUFFER_TIMESTAMP (buf) != enc->next_ts &&
1065 GST_BUFFER_TIMESTAMP (buf) - enc->next_ts > max_diff) {
1066 GST_WARNING_OBJECT (enc,
1067 "Discontinuity detected: %" G_GUINT64_FORMAT " > %" G_GUINT64_FORMAT,
1068 GST_BUFFER_TIMESTAMP (buf) - enc->next_ts, max_diff);
1070 gst_speex_enc_encode (enc, TRUE);
1072 enc->frameno_out = 0;
1073 enc->start_ts = GST_BUFFER_TIMESTAMP (buf);
1074 enc->granulepos_offset = gst_util_uint64_scale
1075 (GST_BUFFER_TIMESTAMP (buf), enc->rate, GST_SECOND);
1079 if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)
1080 && GST_BUFFER_DURATION_IS_VALID (buf))
1081 enc->next_ts = GST_BUFFER_TIMESTAMP (buf) + GST_BUFFER_DURATION (buf);
1083 enc->next_ts = GST_CLOCK_TIME_NONE;
1085 GST_DEBUG_OBJECT (enc, "received buffer of %u bytes", GST_BUFFER_SIZE (buf));
1087 /* push buffer to adapter */
1088 gst_adapter_push (enc->adapter, buf);
1091 ret = gst_speex_enc_encode (enc, FALSE);
1096 gst_buffer_unref (buf);
1103 GST_ELEMENT_ERROR (enc, CORE, NEGOTIATION, (NULL),
1104 ("encoder not initialized (input is not audio?)"));
1105 ret = GST_FLOW_NOT_NEGOTIATED;
1113 gst_speex_enc_get_property (GObject * object, guint prop_id, GValue * value,
1118 enc = GST_SPEEX_ENC (object);
1122 g_value_set_float (value, enc->quality);
1125 g_value_set_int (value, enc->bitrate);
1128 g_value_set_enum (value, enc->mode);
1131 g_value_set_boolean (value, enc->vbr);
1134 g_value_set_int (value, enc->abr);
1137 g_value_set_boolean (value, enc->vad);
1140 g_value_set_boolean (value, enc->dtx);
1142 case PROP_COMPLEXITY:
1143 g_value_set_int (value, enc->complexity);
1146 g_value_set_int (value, enc->nframes);
1148 case PROP_LAST_MESSAGE:
1149 g_value_set_string (value, enc->last_message);
1152 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1158 gst_speex_enc_set_property (GObject * object, guint prop_id,
1159 const GValue * value, GParamSpec * pspec)
1163 enc = GST_SPEEX_ENC (object);
1167 enc->quality = g_value_get_float (value);
1170 enc->bitrate = g_value_get_int (value);
1173 enc->mode = g_value_get_enum (value);
1176 enc->vbr = g_value_get_boolean (value);
1179 enc->abr = g_value_get_int (value);
1182 enc->vad = g_value_get_boolean (value);
1185 enc->dtx = g_value_get_boolean (value);
1187 case PROP_COMPLEXITY:
1188 enc->complexity = g_value_get_int (value);
1191 enc->nframes = g_value_get_int (value);
1194 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1199 static GstStateChangeReturn
1200 gst_speex_enc_change_state (GstElement * element, GstStateChange transition)
1202 GstSpeexEnc *enc = GST_SPEEX_ENC (element);
1203 GstStateChangeReturn res;
1205 switch (transition) {
1206 case GST_STATE_CHANGE_NULL_TO_READY:
1207 enc->tags = gst_tag_list_new ();
1209 case GST_STATE_CHANGE_READY_TO_PAUSED:
1210 speex_bits_init (&enc->bits);
1212 enc->frameno_out = 0;
1213 enc->samples_in = 0;
1214 enc->start_ts = GST_CLOCK_TIME_NONE;
1215 enc->next_ts = GST_CLOCK_TIME_NONE;
1216 enc->granulepos_offset = 0;
1218 case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
1224 res = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1225 if (res == GST_STATE_CHANGE_FAILURE)
1228 switch (transition) {
1229 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
1231 case GST_STATE_CHANGE_PAUSED_TO_READY:
1233 enc->header_sent = FALSE;
1235 speex_encoder_destroy (enc->state);
1238 speex_bits_destroy (&enc->bits);
1240 case GST_STATE_CHANGE_READY_TO_NULL:
1241 gst_tag_list_free (enc->tags);