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, G_PARAM_READWRITE));
201 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_BITRATE,
202 g_param_spec_int ("bitrate", "Encoding Bit-rate",
203 "Specify an encoding bit-rate (in bps). (0 = automatic)",
204 0, G_MAXINT, DEFAULT_BITRATE, G_PARAM_READWRITE));
205 g_object_class_install_property (gobject_class, PROP_MODE,
206 g_param_spec_enum ("mode", "Mode", "The encoding mode",
207 GST_TYPE_SPEEX_ENC_MODE, GST_SPEEX_ENC_MODE_AUTO,
208 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
209 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_VBR,
210 g_param_spec_boolean ("vbr", "VBR",
211 "Enable variable bit-rate", DEFAULT_VBR, G_PARAM_READWRITE));
212 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_ABR,
213 g_param_spec_int ("abr", "ABR",
214 "Enable average bit-rate (0 = disabled)",
215 0, G_MAXINT, DEFAULT_ABR, G_PARAM_READWRITE));
216 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_VAD,
217 g_param_spec_boolean ("vad", "VAD",
218 "Enable voice activity detection", DEFAULT_VAD, G_PARAM_READWRITE));
219 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_DTX,
220 g_param_spec_boolean ("dtx", "DTX",
221 "Enable discontinuous transmission", DEFAULT_DTX, G_PARAM_READWRITE));
222 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_COMPLEXITY,
223 g_param_spec_int ("complexity", "Complexity",
224 "Set encoding complexity",
225 0, G_MAXINT, DEFAULT_COMPLEXITY, G_PARAM_READWRITE));
226 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_NFRAMES,
227 g_param_spec_int ("nframes", "NFrames",
228 "Number of frames per buffer",
229 0, G_MAXINT, DEFAULT_NFRAMES, G_PARAM_READWRITE));
230 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_LAST_MESSAGE,
231 g_param_spec_string ("last-message", "last-message",
232 "The last status message", NULL, G_PARAM_READABLE));
234 gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_speex_enc_finalize);
236 gstelement_class->change_state =
237 GST_DEBUG_FUNCPTR (gst_speex_enc_change_state);
241 gst_speex_enc_finalize (GObject * object)
245 enc = GST_SPEEX_ENC (object);
247 g_free (enc->last_message);
248 g_object_unref (enc->adapter);
250 G_OBJECT_CLASS (parent_class)->finalize (object);
254 gst_speex_enc_sink_setcaps (GstPad * pad, GstCaps * caps)
257 GstStructure *structure;
259 enc = GST_SPEEX_ENC (GST_PAD_PARENT (pad));
262 structure = gst_caps_get_structure (caps, 0);
263 gst_structure_get_int (structure, "channels", &enc->channels);
264 gst_structure_get_int (structure, "rate", &enc->rate);
266 gst_speex_enc_setup (enc);
273 gst_speex_enc_sink_getcaps (GstPad * pad)
275 GstCaps *caps = gst_caps_copy (gst_pad_get_pad_template_caps (pad));
276 GstCaps *peercaps = NULL;
277 GstSpeexEnc *enc = GST_SPEEX_ENC (gst_pad_get_parent_element (pad));
279 peercaps = gst_pad_peer_get_caps (enc->srcpad);
282 if (!gst_caps_is_empty (peercaps) && !gst_caps_is_any (peercaps)) {
283 GstStructure *ps = gst_caps_get_structure (peercaps, 0);
284 GstStructure *s = gst_caps_get_structure (caps, 0);
287 if (gst_structure_get_int (ps, "rate", &rate)) {
288 gst_structure_fixate_field_nearest_int (s, "rate", rate);
291 if (gst_structure_get_int (ps, "channels", &channels)) {
292 gst_structure_fixate_field_nearest_int (s, "channels", channels);
295 gst_caps_unref (peercaps);
298 gst_object_unref (enc);
305 gst_speex_enc_convert_src (GstPad * pad, GstFormat src_format, gint64 src_value,
306 GstFormat * dest_format, gint64 * dest_value)
312 enc = GST_SPEEX_ENC (GST_PAD_PARENT (pad));
314 if (enc->samples_in == 0 || enc->bytes_out == 0 || enc->rate == 0)
317 avg = (enc->bytes_out * enc->rate) / (enc->samples_in);
319 switch (src_format) {
320 case GST_FORMAT_BYTES:
321 switch (*dest_format) {
322 case GST_FORMAT_TIME:
323 *dest_value = src_value * GST_SECOND / avg;
329 case GST_FORMAT_TIME:
330 switch (*dest_format) {
331 case GST_FORMAT_BYTES:
332 *dest_value = src_value * avg / GST_SECOND;
345 gst_speex_enc_convert_sink (GstPad * pad, GstFormat src_format,
346 gint64 src_value, GstFormat * dest_format, gint64 * dest_value)
350 gint bytes_per_sample;
353 enc = GST_SPEEX_ENC (GST_PAD_PARENT (pad));
355 bytes_per_sample = enc->channels * 2;
357 switch (src_format) {
358 case GST_FORMAT_BYTES:
359 switch (*dest_format) {
360 case GST_FORMAT_DEFAULT:
361 if (bytes_per_sample == 0)
363 *dest_value = src_value / bytes_per_sample;
365 case GST_FORMAT_TIME:
367 gint byterate = bytes_per_sample * enc->rate;
371 *dest_value = src_value * GST_SECOND / byterate;
378 case GST_FORMAT_DEFAULT:
379 switch (*dest_format) {
380 case GST_FORMAT_BYTES:
381 *dest_value = src_value * bytes_per_sample;
383 case GST_FORMAT_TIME:
386 *dest_value = src_value * GST_SECOND / enc->rate;
392 case GST_FORMAT_TIME:
393 switch (*dest_format) {
394 case GST_FORMAT_BYTES:
395 scale = bytes_per_sample;
397 case GST_FORMAT_DEFAULT:
398 *dest_value = src_value * scale * enc->rate / GST_SECOND;
411 gst_speex_enc_get_latency (GstSpeexEnc * enc)
413 return 30 * GST_MSECOND;
416 static const GstQueryType *
417 gst_speex_enc_get_query_types (GstPad * pad)
419 static const GstQueryType gst_speex_enc_src_query_types[] = {
427 return gst_speex_enc_src_query_types;
431 gst_speex_enc_src_query (GstPad * pad, GstQuery * query)
436 enc = GST_SPEEX_ENC (gst_pad_get_parent (pad));
438 switch (GST_QUERY_TYPE (query)) {
439 case GST_QUERY_POSITION:
441 GstFormat fmt, req_fmt;
444 gst_query_parse_position (query, &req_fmt, NULL);
445 if ((res = gst_pad_query_peer_position (enc->sinkpad, &req_fmt, &val))) {
446 gst_query_set_position (query, req_fmt, val);
450 fmt = GST_FORMAT_TIME;
451 if (!(res = gst_pad_query_peer_position (enc->sinkpad, &fmt, &pos)))
455 gst_pad_query_peer_convert (enc->sinkpad, fmt, pos, &req_fmt,
457 gst_query_set_position (query, req_fmt, val);
461 case GST_QUERY_DURATION:
463 GstFormat fmt, req_fmt;
466 gst_query_parse_duration (query, &req_fmt, NULL);
467 if ((res = gst_pad_query_peer_duration (enc->sinkpad, &req_fmt, &val))) {
468 gst_query_set_duration (query, req_fmt, val);
472 fmt = GST_FORMAT_TIME;
473 if (!(res = gst_pad_query_peer_duration (enc->sinkpad, &fmt, &dur)))
477 gst_pad_query_peer_convert (enc->sinkpad, fmt, dur, &req_fmt,
479 gst_query_set_duration (query, req_fmt, val);
483 case GST_QUERY_CONVERT:
485 GstFormat src_fmt, dest_fmt;
486 gint64 src_val, dest_val;
488 gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, &dest_val);
489 if (!(res = gst_speex_enc_convert_src (pad, src_fmt, src_val, &dest_fmt,
492 gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val);
495 case GST_QUERY_LATENCY:
498 GstClockTime min_latency, max_latency;
501 if ((res = gst_pad_peer_query (enc->sinkpad, query))) {
502 gst_query_parse_latency (query, &live, &min_latency, &max_latency);
503 GST_LOG_OBJECT (pad, "Upstream latency: %" GST_PTR_FORMAT, query);
505 latency = gst_speex_enc_get_latency (enc);
507 /* add our latency */
508 min_latency += latency;
509 if (max_latency != -1)
510 max_latency += latency;
512 gst_query_set_latency (query, live, min_latency, max_latency);
513 GST_LOG_OBJECT (pad, "Adjusted latency: %" GST_PTR_FORMAT, query);
518 res = gst_pad_peer_query (enc->sinkpad, query);
524 gst_object_unref (enc);
530 gst_speex_enc_sink_query (GstPad * pad, GstQuery * query)
534 switch (GST_QUERY_TYPE (query)) {
535 case GST_QUERY_CONVERT:
537 GstFormat src_fmt, dest_fmt;
538 gint64 src_val, dest_val;
540 gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, &dest_val);
542 gst_speex_enc_convert_sink (pad, src_fmt, src_val, &dest_fmt,
545 gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val);
549 res = gst_pad_query_default (pad, query);
558 gst_speex_enc_init (GstSpeexEnc * enc, GstSpeexEncClass * klass)
560 enc->sinkpad = gst_pad_new_from_static_template (&sink_factory, "sink");
561 gst_element_add_pad (GST_ELEMENT (enc), enc->sinkpad);
562 gst_pad_set_event_function (enc->sinkpad,
563 GST_DEBUG_FUNCPTR (gst_speex_enc_sinkevent));
564 gst_pad_set_chain_function (enc->sinkpad,
565 GST_DEBUG_FUNCPTR (gst_speex_enc_chain));
566 gst_pad_set_setcaps_function (enc->sinkpad,
567 GST_DEBUG_FUNCPTR (gst_speex_enc_sink_setcaps));
568 gst_pad_set_getcaps_function (enc->sinkpad,
569 GST_DEBUG_FUNCPTR (gst_speex_enc_sink_getcaps));
570 gst_pad_set_query_function (enc->sinkpad,
571 GST_DEBUG_FUNCPTR (gst_speex_enc_sink_query));
573 enc->srcpad = gst_pad_new_from_static_template (&src_factory, "src");
574 gst_pad_set_query_function (enc->srcpad,
575 GST_DEBUG_FUNCPTR (gst_speex_enc_src_query));
576 gst_pad_set_query_type_function (enc->srcpad,
577 GST_DEBUG_FUNCPTR (gst_speex_enc_get_query_types));
578 gst_element_add_pad (GST_ELEMENT (enc), enc->srcpad);
583 enc->quality = DEFAULT_QUALITY;
584 enc->bitrate = DEFAULT_BITRATE;
585 enc->mode = DEFAULT_MODE;
586 enc->vbr = DEFAULT_VBR;
587 enc->abr = DEFAULT_ABR;
588 enc->vad = DEFAULT_VAD;
589 enc->dtx = DEFAULT_DTX;
590 enc->complexity = DEFAULT_COMPLEXITY;
591 enc->nframes = DEFAULT_NFRAMES;
594 enc->header_sent = FALSE;
596 enc->adapter = gst_adapter_new ();
600 gst_speex_enc_create_metadata_buffer (GstSpeexEnc * enc)
602 const GstTagList *user_tags;
603 GstTagList *merged_tags;
604 GstBuffer *comments = NULL;
606 user_tags = gst_tag_setter_get_tag_list (GST_TAG_SETTER (enc));
608 GST_DEBUG_OBJECT (enc, "upstream tags = %" GST_PTR_FORMAT, enc->tags);
609 GST_DEBUG_OBJECT (enc, "user-set tags = %" GST_PTR_FORMAT, user_tags);
611 /* gst_tag_list_merge() will handle NULL for either or both lists fine */
612 merged_tags = gst_tag_list_merge (user_tags, enc->tags,
613 gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (enc)));
615 if (merged_tags == NULL)
616 merged_tags = gst_tag_list_new ();
618 GST_DEBUG_OBJECT (enc, "merged tags = %" GST_PTR_FORMAT, merged_tags);
619 comments = gst_tag_list_to_vorbiscomment_buffer (merged_tags, NULL,
620 0, "Encoded with GStreamer Speexenc");
621 gst_tag_list_free (merged_tags);
623 GST_BUFFER_OFFSET (comments) = enc->bytes_out;
624 GST_BUFFER_OFFSET_END (comments) = 0;
630 gst_speex_enc_set_last_msg (GstSpeexEnc * enc, const gchar * msg)
632 g_free (enc->last_message);
633 enc->last_message = g_strdup (msg);
634 GST_WARNING_OBJECT (enc, "%s", msg);
635 g_object_notify (G_OBJECT (enc), "last-message");
639 gst_speex_enc_setup (GstSpeexEnc * enc)
644 case GST_SPEEX_ENC_MODE_UWB:
645 GST_LOG_OBJECT (enc, "configuring for requested UWB mode");
646 enc->speex_mode = (SpeexMode *) & speex_uwb_mode;
648 case GST_SPEEX_ENC_MODE_WB:
649 GST_LOG_OBJECT (enc, "configuring for requested WB mode");
650 enc->speex_mode = (SpeexMode *) & speex_wb_mode;
652 case GST_SPEEX_ENC_MODE_NB:
653 GST_LOG_OBJECT (enc, "configuring for requested NB mode");
654 enc->speex_mode = (SpeexMode *) & speex_nb_mode;
656 case GST_SPEEX_ENC_MODE_AUTO:
658 GST_LOG_OBJECT (enc, "finding best mode");
663 if (enc->rate > 25000) {
664 if (enc->mode == GST_SPEEX_ENC_MODE_AUTO) {
665 GST_LOG_OBJECT (enc, "selected UWB mode for samplerate %d", enc->rate);
666 enc->speex_mode = (SpeexMode *) & speex_uwb_mode;
668 if (enc->speex_mode != &speex_uwb_mode) {
669 gst_speex_enc_set_last_msg (enc,
670 "Warning: suggest to use ultra wide band mode for this rate");
673 } else if (enc->rate > 12500) {
674 if (enc->mode == GST_SPEEX_ENC_MODE_AUTO) {
675 GST_LOG_OBJECT (enc, "selected WB mode for samplerate %d", enc->rate);
676 enc->speex_mode = (SpeexMode *) & speex_wb_mode;
678 if (enc->speex_mode != &speex_wb_mode) {
679 gst_speex_enc_set_last_msg (enc,
680 "Warning: suggest to use wide band mode for this rate");
684 if (enc->mode == GST_SPEEX_ENC_MODE_AUTO) {
685 GST_LOG_OBJECT (enc, "selected NB mode for samplerate %d", enc->rate);
686 enc->speex_mode = (SpeexMode *) & speex_nb_mode;
688 if (enc->speex_mode != &speex_nb_mode) {
689 gst_speex_enc_set_last_msg (enc,
690 "Warning: suggest to use narrow band mode for this rate");
695 if (enc->rate != 8000 && enc->rate != 16000 && enc->rate != 32000) {
696 gst_speex_enc_set_last_msg (enc,
697 "Warning: speex is optimized for 8, 16 and 32 KHz");
700 speex_init_header (&enc->header, enc->rate, 1, enc->speex_mode);
701 enc->header.frames_per_packet = enc->nframes;
702 enc->header.vbr = enc->vbr;
703 enc->header.nb_channels = enc->channels;
705 /*Initialize Speex encoder */
706 enc->state = speex_encoder_init (enc->speex_mode);
708 speex_encoder_ctl (enc->state, SPEEX_GET_FRAME_SIZE, &enc->frame_size);
709 speex_encoder_ctl (enc->state, SPEEX_SET_COMPLEXITY, &enc->complexity);
710 speex_encoder_ctl (enc->state, SPEEX_SET_SAMPLING_RATE, &enc->rate);
713 speex_encoder_ctl (enc->state, SPEEX_SET_VBR_QUALITY, &enc->quality);
715 gint tmp = floor (enc->quality);
717 speex_encoder_ctl (enc->state, SPEEX_SET_QUALITY, &tmp);
720 if (enc->quality >= 0.0 && enc->vbr) {
721 gst_speex_enc_set_last_msg (enc,
722 "Warning: bitrate option is overriding quality");
724 speex_encoder_ctl (enc->state, SPEEX_SET_BITRATE, &enc->bitrate);
729 speex_encoder_ctl (enc->state, SPEEX_SET_VBR, &tmp);
730 } else if (enc->vad) {
733 speex_encoder_ctl (enc->state, SPEEX_SET_VAD, &tmp);
739 speex_encoder_ctl (enc->state, SPEEX_SET_DTX, &tmp);
742 if (enc->dtx && !(enc->vbr || enc->abr || enc->vad)) {
743 gst_speex_enc_set_last_msg (enc,
744 "Warning: dtx is useless without vad, vbr or abr");
745 } else if ((enc->vbr || enc->abr) && (enc->vad)) {
746 gst_speex_enc_set_last_msg (enc,
747 "Warning: vad is already implied by vbr or abr");
751 speex_encoder_ctl (enc->state, SPEEX_SET_ABR, &enc->abr);
754 speex_encoder_ctl (enc->state, SPEEX_GET_LOOKAHEAD, &enc->lookahead);
756 GST_LOG_OBJECT (enc, "we have frame size %d, lookahead %d", enc->frame_size,
764 /* prepare a buffer for transmission */
766 gst_speex_enc_buffer_from_data (GstSpeexEnc * enc, guchar * data,
767 gint data_len, guint64 granulepos)
771 outbuf = gst_buffer_new_and_alloc (data_len);
772 memcpy (GST_BUFFER_DATA (outbuf), data, data_len);
773 GST_BUFFER_OFFSET (outbuf) = enc->bytes_out;
774 GST_BUFFER_OFFSET_END (outbuf) = granulepos;
776 GST_LOG_OBJECT (enc, "encoded buffer of %d bytes", GST_BUFFER_SIZE (outbuf));
781 /* push out the buffer and do internal bookkeeping */
783 gst_speex_enc_push_buffer (GstSpeexEnc * enc, GstBuffer * buffer)
787 size = GST_BUFFER_SIZE (buffer);
789 enc->bytes_out += size;
791 GST_DEBUG_OBJECT (enc, "pushing output buffer of size %u", size);
793 return gst_pad_push (enc->srcpad, buffer);
797 gst_speex_enc_set_header_on_caps (GstCaps * caps, GstBuffer * buf1,
800 GstStructure *structure = NULL;
802 GValue array = { 0 };
803 GValue value = { 0 };
805 caps = gst_caps_make_writable (caps);
806 structure = gst_caps_get_structure (caps, 0);
808 g_assert (gst_buffer_is_metadata_writable (buf1));
809 g_assert (gst_buffer_is_metadata_writable (buf2));
812 GST_BUFFER_FLAG_SET (buf1, GST_BUFFER_FLAG_IN_CAPS);
813 GST_BUFFER_FLAG_SET (buf2, GST_BUFFER_FLAG_IN_CAPS);
815 /* put buffers in a fixed list */
816 g_value_init (&array, GST_TYPE_ARRAY);
817 g_value_init (&value, GST_TYPE_BUFFER);
818 buf = gst_buffer_copy (buf1);
819 gst_value_set_buffer (&value, buf);
820 gst_buffer_unref (buf);
821 gst_value_array_append_value (&array, &value);
822 g_value_unset (&value);
823 g_value_init (&value, GST_TYPE_BUFFER);
824 buf = gst_buffer_copy (buf2);
825 gst_value_set_buffer (&value, buf);
826 gst_buffer_unref (buf);
827 gst_value_array_append_value (&array, &value);
828 gst_structure_set_value (structure, "streamheader", &array);
829 g_value_unset (&value);
830 g_value_unset (&array);
837 gst_speex_enc_sinkevent (GstPad * pad, GstEvent * event)
842 enc = GST_SPEEX_ENC (gst_pad_get_parent (pad));
844 switch (GST_EVENT_TYPE (event)) {
847 gst_speex_enc_encode (enc, TRUE);
848 res = gst_pad_event_default (pad, event);
855 gst_event_parse_tag (event, &list);
856 gst_tag_list_insert (enc->tags, list,
857 gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (enc)));
859 g_assert_not_reached ();
861 res = gst_pad_event_default (pad, event);
865 res = gst_pad_event_default (pad, event);
869 gst_object_unref (enc);
875 gst_speex_enc_encode (GstSpeexEnc * enc, gboolean flush)
877 gint frame_size = enc->frame_size;
878 gint bytes = frame_size * 2 * enc->channels;
879 GstFlowReturn ret = GST_FLOW_OK;
881 if (flush && gst_adapter_available (enc->adapter) % bytes != 0) {
882 guint diff = gst_adapter_available (enc->adapter) % bytes;
883 GstBuffer *buf = gst_buffer_new_and_alloc (diff);
885 memset (GST_BUFFER_DATA (buf), 0, diff);
886 gst_adapter_push (enc->adapter, buf);
889 while (gst_adapter_available (enc->adapter) >= bytes) {
891 gint outsize, written;
894 data = (gint16 *) gst_adapter_take (enc->adapter, bytes);
896 enc->samples_in += frame_size;
898 GST_DEBUG_OBJECT (enc, "encoding %d samples (%d bytes)", frame_size, bytes);
900 if (enc->channels == 2) {
901 speex_encode_stereo_int (data, frame_size, &enc->bits);
903 speex_encode_int (enc->state, data, &enc->bits);
910 if ((enc->frameno % enc->nframes) != 0)
913 speex_bits_insert_terminator (&enc->bits);
914 outsize = speex_bits_nbytes (&enc->bits);
916 ret = gst_pad_alloc_buffer_and_set_caps (enc->srcpad,
917 GST_BUFFER_OFFSET_NONE, outsize, GST_PAD_CAPS (enc->srcpad), &outbuf);
919 if ((GST_FLOW_OK != ret))
922 written = speex_bits_write (&enc->bits,
923 (gchar *) GST_BUFFER_DATA (outbuf), outsize);
924 g_assert (written == outsize);
925 speex_bits_reset (&enc->bits);
927 GST_BUFFER_TIMESTAMP (outbuf) = enc->start_ts +
928 gst_util_uint64_scale_int ((enc->frameno_out -
929 enc->nframes) * frame_size - enc->lookahead, GST_SECOND, enc->rate);
930 GST_BUFFER_DURATION (outbuf) =
931 gst_util_uint64_scale_int (frame_size * enc->nframes, GST_SECOND,
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);