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 };
162 g_type_add_interface_static (speexenc_type, GST_TYPE_TAG_SETTER,
165 GST_DEBUG_CATEGORY_INIT (speexenc_debug, "speexenc", 0, "Speex encoder");
168 GST_BOILERPLATE_FULL (GstSpeexEnc, gst_speex_enc, GstElement, GST_TYPE_ELEMENT,
169 gst_speex_enc_setup_interfaces);
172 gst_speex_enc_base_init (gpointer g_class)
174 GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
176 gst_element_class_add_pad_template (element_class,
177 gst_static_pad_template_get (&src_factory));
178 gst_element_class_add_pad_template (element_class,
179 gst_static_pad_template_get (&sink_factory));
180 gst_element_class_set_details (element_class, &speexenc_details);
184 gst_speex_enc_class_init (GstSpeexEncClass * klass)
186 GObjectClass *gobject_class;
187 GstElementClass *gstelement_class;
189 gobject_class = (GObjectClass *) klass;
190 gstelement_class = (GstElementClass *) klass;
192 gobject_class->set_property = gst_speex_enc_set_property;
193 gobject_class->get_property = gst_speex_enc_get_property;
195 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_QUALITY,
196 g_param_spec_float ("quality", "Quality", "Encoding quality",
197 0.0, 10.0, DEFAULT_QUALITY, G_PARAM_READWRITE));
198 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_BITRATE,
199 g_param_spec_int ("bitrate", "Encoding Bit-rate",
200 "Specify an encoding bit-rate (in bps). (0 = automatic)",
201 0, G_MAXINT, DEFAULT_BITRATE, G_PARAM_READWRITE));
202 g_object_class_install_property (gobject_class, PROP_MODE,
203 g_param_spec_enum ("mode", "Mode", "The encoding mode",
204 GST_TYPE_SPEEX_ENC_MODE, GST_SPEEX_ENC_MODE_AUTO,
205 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
206 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_VBR,
207 g_param_spec_boolean ("vbr", "VBR",
208 "Enable variable bit-rate", DEFAULT_VBR, G_PARAM_READWRITE));
209 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_ABR,
210 g_param_spec_int ("abr", "ABR",
211 "Enable average bit-rate (0 = disabled)",
212 0, G_MAXINT, DEFAULT_ABR, G_PARAM_READWRITE));
213 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_VAD,
214 g_param_spec_boolean ("vad", "VAD",
215 "Enable voice activity detection", DEFAULT_VAD, G_PARAM_READWRITE));
216 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_DTX,
217 g_param_spec_boolean ("dtx", "DTX",
218 "Enable discontinuous transmission", DEFAULT_DTX, G_PARAM_READWRITE));
219 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_COMPLEXITY,
220 g_param_spec_int ("complexity", "Complexity",
221 "Set encoding complexity",
222 0, G_MAXINT, DEFAULT_COMPLEXITY, G_PARAM_READWRITE));
223 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_NFRAMES,
224 g_param_spec_int ("nframes", "NFrames",
225 "Number of frames per buffer",
226 0, G_MAXINT, DEFAULT_NFRAMES, G_PARAM_READWRITE));
227 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_LAST_MESSAGE,
228 g_param_spec_string ("last-message", "last-message",
229 "The last status message", NULL, G_PARAM_READABLE));
231 gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_speex_enc_finalize);
233 gstelement_class->change_state =
234 GST_DEBUG_FUNCPTR (gst_speex_enc_change_state);
238 gst_speex_enc_finalize (GObject * object)
242 enc = GST_SPEEX_ENC (object);
244 g_free (enc->last_message);
245 g_object_unref (enc->adapter);
247 G_OBJECT_CLASS (parent_class)->finalize (object);
251 gst_speex_enc_sink_setcaps (GstPad * pad, GstCaps * caps)
254 GstStructure *structure;
256 enc = GST_SPEEX_ENC (GST_PAD_PARENT (pad));
259 structure = gst_caps_get_structure (caps, 0);
260 gst_structure_get_int (structure, "channels", &enc->channels);
261 gst_structure_get_int (structure, "rate", &enc->rate);
263 gst_speex_enc_setup (enc);
270 gst_speex_enc_sink_getcaps (GstPad * pad)
272 GstCaps *caps = gst_caps_copy (gst_pad_get_pad_template_caps (pad));
273 GstCaps *peercaps = NULL;
274 GstSpeexEnc *enc = GST_SPEEX_ENC (gst_pad_get_parent_element (pad));
276 peercaps = gst_pad_peer_get_caps (enc->srcpad);
279 if (!gst_caps_is_empty (peercaps) && !gst_caps_is_any (peercaps)) {
280 GstStructure *ps = gst_caps_get_structure (peercaps, 0);
281 GstStructure *s = gst_caps_get_structure (caps, 0);
284 if (gst_structure_get_int (ps, "rate", &rate)) {
285 gst_structure_fixate_field_nearest_int (s, "rate", rate);
288 if (gst_structure_get_int (ps, "channels", &channels)) {
289 gst_structure_fixate_field_nearest_int (s, "channels", channels);
292 gst_caps_unref (peercaps);
295 gst_object_unref (enc);
302 gst_speex_enc_convert_src (GstPad * pad, GstFormat src_format, gint64 src_value,
303 GstFormat * dest_format, gint64 * dest_value)
309 enc = GST_SPEEX_ENC (GST_PAD_PARENT (pad));
311 if (enc->samples_in == 0 || enc->bytes_out == 0 || enc->rate == 0)
314 avg = (enc->bytes_out * enc->rate) / (enc->samples_in);
316 switch (src_format) {
317 case GST_FORMAT_BYTES:
318 switch (*dest_format) {
319 case GST_FORMAT_TIME:
320 *dest_value = src_value * GST_SECOND / avg;
326 case GST_FORMAT_TIME:
327 switch (*dest_format) {
328 case GST_FORMAT_BYTES:
329 *dest_value = src_value * avg / GST_SECOND;
342 gst_speex_enc_convert_sink (GstPad * pad, GstFormat src_format,
343 gint64 src_value, GstFormat * dest_format, gint64 * dest_value)
347 gint bytes_per_sample;
350 enc = GST_SPEEX_ENC (GST_PAD_PARENT (pad));
352 bytes_per_sample = enc->channels * 2;
354 switch (src_format) {
355 case GST_FORMAT_BYTES:
356 switch (*dest_format) {
357 case GST_FORMAT_DEFAULT:
358 if (bytes_per_sample == 0)
360 *dest_value = src_value / bytes_per_sample;
362 case GST_FORMAT_TIME:
364 gint byterate = bytes_per_sample * enc->rate;
368 *dest_value = src_value * GST_SECOND / byterate;
375 case GST_FORMAT_DEFAULT:
376 switch (*dest_format) {
377 case GST_FORMAT_BYTES:
378 *dest_value = src_value * bytes_per_sample;
380 case GST_FORMAT_TIME:
383 *dest_value = src_value * GST_SECOND / enc->rate;
389 case GST_FORMAT_TIME:
390 switch (*dest_format) {
391 case GST_FORMAT_BYTES:
392 scale = bytes_per_sample;
394 case GST_FORMAT_DEFAULT:
395 *dest_value = src_value * scale * enc->rate / GST_SECOND;
408 gst_speex_enc_get_latency (GstSpeexEnc * enc)
410 return 30 * GST_MSECOND;
413 static const GstQueryType *
414 gst_speex_enc_get_query_types (GstPad * pad)
416 static const GstQueryType gst_speex_enc_src_query_types[] = {
424 return gst_speex_enc_src_query_types;
428 gst_speex_enc_src_query (GstPad * pad, GstQuery * query)
433 enc = GST_SPEEX_ENC (gst_pad_get_parent (pad));
435 switch (GST_QUERY_TYPE (query)) {
436 case GST_QUERY_POSITION:
438 GstFormat fmt, req_fmt;
441 gst_query_parse_position (query, &req_fmt, NULL);
442 if ((res = gst_pad_query_peer_position (enc->sinkpad, &req_fmt, &val))) {
443 gst_query_set_position (query, req_fmt, val);
447 fmt = GST_FORMAT_TIME;
448 if (!(res = gst_pad_query_peer_position (enc->sinkpad, &fmt, &pos)))
452 gst_pad_query_peer_convert (enc->sinkpad, fmt, pos, &req_fmt,
454 gst_query_set_position (query, req_fmt, val);
458 case GST_QUERY_DURATION:
460 GstFormat fmt, req_fmt;
463 gst_query_parse_duration (query, &req_fmt, NULL);
464 if ((res = gst_pad_query_peer_duration (enc->sinkpad, &req_fmt, &val))) {
465 gst_query_set_duration (query, req_fmt, val);
469 fmt = GST_FORMAT_TIME;
470 if (!(res = gst_pad_query_peer_duration (enc->sinkpad, &fmt, &dur)))
474 gst_pad_query_peer_convert (enc->sinkpad, fmt, dur, &req_fmt,
476 gst_query_set_duration (query, req_fmt, val);
480 case GST_QUERY_CONVERT:
482 GstFormat src_fmt, dest_fmt;
483 gint64 src_val, dest_val;
485 gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, &dest_val);
486 if (!(res = gst_speex_enc_convert_src (pad, src_fmt, src_val, &dest_fmt,
489 gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val);
492 case GST_QUERY_LATENCY:
495 GstClockTime min_latency, max_latency;
498 if ((res = gst_pad_peer_query (enc->sinkpad, query))) {
499 gst_query_parse_latency (query, &live, &min_latency, &max_latency);
500 GST_LOG_OBJECT (pad, "Upstream latency: %" GST_PTR_FORMAT, query);
502 latency = gst_speex_enc_get_latency (enc);
504 /* add our latency */
505 min_latency += latency;
506 if (max_latency != -1)
507 max_latency += latency;
509 gst_query_set_latency (query, live, min_latency, max_latency);
510 GST_LOG_OBJECT (pad, "Adjusted latency: %" GST_PTR_FORMAT, query);
515 res = gst_pad_peer_query (enc->sinkpad, query);
521 gst_object_unref (enc);
527 gst_speex_enc_sink_query (GstPad * pad, GstQuery * query)
531 switch (GST_QUERY_TYPE (query)) {
532 case GST_QUERY_CONVERT:
534 GstFormat src_fmt, dest_fmt;
535 gint64 src_val, dest_val;
537 gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, &dest_val);
539 gst_speex_enc_convert_sink (pad, src_fmt, src_val, &dest_fmt,
542 gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val);
546 res = gst_pad_query_default (pad, query);
555 gst_speex_enc_init (GstSpeexEnc * enc, GstSpeexEncClass * klass)
557 enc->sinkpad = gst_pad_new_from_static_template (&sink_factory, "sink");
558 gst_element_add_pad (GST_ELEMENT (enc), enc->sinkpad);
559 gst_pad_set_event_function (enc->sinkpad,
560 GST_DEBUG_FUNCPTR (gst_speex_enc_sinkevent));
561 gst_pad_set_chain_function (enc->sinkpad,
562 GST_DEBUG_FUNCPTR (gst_speex_enc_chain));
563 gst_pad_set_setcaps_function (enc->sinkpad,
564 GST_DEBUG_FUNCPTR (gst_speex_enc_sink_setcaps));
565 gst_pad_set_getcaps_function (enc->sinkpad,
566 GST_DEBUG_FUNCPTR (gst_speex_enc_sink_getcaps));
567 gst_pad_set_query_function (enc->sinkpad,
568 GST_DEBUG_FUNCPTR (gst_speex_enc_sink_query));
570 enc->srcpad = gst_pad_new_from_static_template (&src_factory, "src");
571 gst_pad_set_query_function (enc->srcpad,
572 GST_DEBUG_FUNCPTR (gst_speex_enc_src_query));
573 gst_pad_set_query_type_function (enc->srcpad,
574 GST_DEBUG_FUNCPTR (gst_speex_enc_get_query_types));
575 gst_element_add_pad (GST_ELEMENT (enc), enc->srcpad);
580 enc->quality = DEFAULT_QUALITY;
581 enc->bitrate = DEFAULT_BITRATE;
582 enc->mode = DEFAULT_MODE;
583 enc->vbr = DEFAULT_VBR;
584 enc->abr = DEFAULT_ABR;
585 enc->vad = DEFAULT_VAD;
586 enc->dtx = DEFAULT_DTX;
587 enc->complexity = DEFAULT_COMPLEXITY;
588 enc->nframes = DEFAULT_NFRAMES;
591 enc->header_sent = FALSE;
593 enc->adapter = gst_adapter_new ();
597 gst_speex_enc_create_metadata_buffer (GstSpeexEnc * enc)
599 const GstTagList *user_tags;
600 GstTagList *merged_tags;
601 GstBuffer *comments = NULL;
603 user_tags = gst_tag_setter_get_tag_list (GST_TAG_SETTER (enc));
605 GST_DEBUG_OBJECT (enc, "upstream tags = %" GST_PTR_FORMAT, enc->tags);
606 GST_DEBUG_OBJECT (enc, "user-set tags = %" GST_PTR_FORMAT, user_tags);
608 /* gst_tag_list_merge() will handle NULL for either or both lists fine */
609 merged_tags = gst_tag_list_merge (user_tags, enc->tags,
610 gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (enc)));
612 if (merged_tags == NULL)
613 merged_tags = gst_tag_list_new ();
615 GST_DEBUG_OBJECT (enc, "merged tags = %" GST_PTR_FORMAT, merged_tags);
616 comments = gst_tag_list_to_vorbiscomment_buffer (merged_tags, NULL,
617 0, "Encoded with GStreamer Speexenc");
618 gst_tag_list_free (merged_tags);
620 GST_BUFFER_OFFSET (comments) = enc->bytes_out;
621 GST_BUFFER_OFFSET_END (comments) = 0;
627 gst_speex_enc_set_last_msg (GstSpeexEnc * enc, const gchar * msg)
629 g_free (enc->last_message);
630 enc->last_message = g_strdup (msg);
631 GST_WARNING_OBJECT (enc, "%s", msg);
632 g_object_notify (G_OBJECT (enc), "last-message");
636 gst_speex_enc_setup (GstSpeexEnc * enc)
641 case GST_SPEEX_ENC_MODE_UWB:
642 GST_LOG_OBJECT (enc, "configuring for requested UWB mode");
643 enc->speex_mode = (SpeexMode *) & speex_uwb_mode;
645 case GST_SPEEX_ENC_MODE_WB:
646 GST_LOG_OBJECT (enc, "configuring for requested WB mode");
647 enc->speex_mode = (SpeexMode *) & speex_wb_mode;
649 case GST_SPEEX_ENC_MODE_NB:
650 GST_LOG_OBJECT (enc, "configuring for requested NB mode");
651 enc->speex_mode = (SpeexMode *) & speex_nb_mode;
653 case GST_SPEEX_ENC_MODE_AUTO:
655 GST_LOG_OBJECT (enc, "finding best mode");
660 if (enc->rate > 25000) {
661 if (enc->mode == GST_SPEEX_ENC_MODE_AUTO) {
662 GST_LOG_OBJECT (enc, "selected UWB mode for samplerate %d", enc->rate);
663 enc->speex_mode = (SpeexMode *) & speex_uwb_mode;
665 if (enc->speex_mode != &speex_uwb_mode) {
666 gst_speex_enc_set_last_msg (enc,
667 "Warning: suggest to use ultra wide band mode for this rate");
670 } else if (enc->rate > 12500) {
671 if (enc->mode == GST_SPEEX_ENC_MODE_AUTO) {
672 GST_LOG_OBJECT (enc, "selected WB mode for samplerate %d", enc->rate);
673 enc->speex_mode = (SpeexMode *) & speex_wb_mode;
675 if (enc->speex_mode != &speex_wb_mode) {
676 gst_speex_enc_set_last_msg (enc,
677 "Warning: suggest to use wide band mode for this rate");
681 if (enc->mode == GST_SPEEX_ENC_MODE_AUTO) {
682 GST_LOG_OBJECT (enc, "selected NB mode for samplerate %d", enc->rate);
683 enc->speex_mode = (SpeexMode *) & speex_nb_mode;
685 if (enc->speex_mode != &speex_nb_mode) {
686 gst_speex_enc_set_last_msg (enc,
687 "Warning: suggest to use narrow band mode for this rate");
692 if (enc->rate != 8000 && enc->rate != 16000 && enc->rate != 32000) {
693 gst_speex_enc_set_last_msg (enc,
694 "Warning: speex is optimized for 8, 16 and 32 KHz");
697 speex_init_header (&enc->header, enc->rate, 1, enc->speex_mode);
698 enc->header.frames_per_packet = enc->nframes;
699 enc->header.vbr = enc->vbr;
700 enc->header.nb_channels = enc->channels;
702 /*Initialize Speex encoder */
703 enc->state = speex_encoder_init (enc->speex_mode);
705 speex_encoder_ctl (enc->state, SPEEX_GET_FRAME_SIZE, &enc->frame_size);
706 speex_encoder_ctl (enc->state, SPEEX_SET_COMPLEXITY, &enc->complexity);
707 speex_encoder_ctl (enc->state, SPEEX_SET_SAMPLING_RATE, &enc->rate);
710 speex_encoder_ctl (enc->state, SPEEX_SET_VBR_QUALITY, &enc->quality);
712 gint tmp = floor (enc->quality);
714 speex_encoder_ctl (enc->state, SPEEX_SET_QUALITY, &tmp);
717 if (enc->quality >= 0.0 && enc->vbr) {
718 gst_speex_enc_set_last_msg (enc,
719 "Warning: bitrate option is overriding quality");
721 speex_encoder_ctl (enc->state, SPEEX_SET_BITRATE, &enc->bitrate);
726 speex_encoder_ctl (enc->state, SPEEX_SET_VBR, &tmp);
727 } else if (enc->vad) {
730 speex_encoder_ctl (enc->state, SPEEX_SET_VAD, &tmp);
736 speex_encoder_ctl (enc->state, SPEEX_SET_DTX, &tmp);
739 if (enc->dtx && !(enc->vbr || enc->abr || enc->vad)) {
740 gst_speex_enc_set_last_msg (enc,
741 "Warning: dtx is useless without vad, vbr or abr");
742 } else if ((enc->vbr || enc->abr) && (enc->vad)) {
743 gst_speex_enc_set_last_msg (enc,
744 "Warning: vad is already implied by vbr or abr");
748 speex_encoder_ctl (enc->state, SPEEX_SET_ABR, &enc->abr);
751 speex_encoder_ctl (enc->state, SPEEX_GET_LOOKAHEAD, &enc->lookahead);
753 GST_LOG_OBJECT (enc, "we have frame size %d, lookahead %d", enc->frame_size,
761 /* prepare a buffer for transmission */
763 gst_speex_enc_buffer_from_data (GstSpeexEnc * enc, guchar * data,
764 gint data_len, guint64 granulepos)
768 outbuf = gst_buffer_new_and_alloc (data_len);
769 memcpy (GST_BUFFER_DATA (outbuf), data, data_len);
770 GST_BUFFER_OFFSET (outbuf) = enc->bytes_out;
771 GST_BUFFER_OFFSET_END (outbuf) = granulepos;
773 GST_LOG_OBJECT (enc, "encoded buffer of %d bytes", GST_BUFFER_SIZE (outbuf));
778 /* push out the buffer and do internal bookkeeping */
780 gst_speex_enc_push_buffer (GstSpeexEnc * enc, GstBuffer * buffer)
784 size = GST_BUFFER_SIZE (buffer);
786 enc->bytes_out += size;
788 GST_DEBUG_OBJECT (enc, "pushing output buffer of size %u", size);
790 return gst_pad_push (enc->srcpad, buffer);
794 gst_speex_enc_set_header_on_caps (GstCaps * caps, GstBuffer * buf1,
797 GstStructure *structure = NULL;
799 GValue array = { 0 };
800 GValue value = { 0 };
802 caps = gst_caps_make_writable (caps);
803 structure = gst_caps_get_structure (caps, 0);
805 g_assert (gst_buffer_is_metadata_writable (buf1));
806 g_assert (gst_buffer_is_metadata_writable (buf2));
809 GST_BUFFER_FLAG_SET (buf1, GST_BUFFER_FLAG_IN_CAPS);
810 GST_BUFFER_FLAG_SET (buf2, GST_BUFFER_FLAG_IN_CAPS);
812 /* put buffers in a fixed list */
813 g_value_init (&array, GST_TYPE_ARRAY);
814 g_value_init (&value, GST_TYPE_BUFFER);
815 buf = gst_buffer_copy (buf1);
816 gst_value_set_buffer (&value, buf);
817 gst_buffer_unref (buf);
818 gst_value_array_append_value (&array, &value);
819 g_value_unset (&value);
820 g_value_init (&value, GST_TYPE_BUFFER);
821 buf = gst_buffer_copy (buf2);
822 gst_value_set_buffer (&value, buf);
823 gst_buffer_unref (buf);
824 gst_value_array_append_value (&array, &value);
825 gst_structure_set_value (structure, "streamheader", &array);
826 g_value_unset (&value);
827 g_value_unset (&array);
834 gst_speex_enc_sinkevent (GstPad * pad, GstEvent * event)
839 enc = GST_SPEEX_ENC (gst_pad_get_parent (pad));
841 switch (GST_EVENT_TYPE (event)) {
843 gst_speex_enc_encode (enc, TRUE);
844 res = gst_pad_event_default (pad, event);
850 gst_event_parse_tag (event, &list);
852 gst_tag_list_insert (enc->tags, list,
853 gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (enc)));
855 res = gst_pad_event_default (pad, event);
859 res = gst_pad_event_default (pad, event);
863 gst_object_unref (enc);
869 gst_speex_enc_encode (GstSpeexEnc * enc, gboolean flush)
871 gint frame_size = enc->frame_size;
872 gint bytes = frame_size * 2 * enc->channels;
873 GstFlowReturn ret = GST_FLOW_OK;
875 if (flush && gst_adapter_available (enc->adapter) % bytes != 0) {
876 guint diff = gst_adapter_available (enc->adapter) % bytes;
877 GstBuffer *buf = gst_buffer_new_and_alloc (diff);
879 memset (GST_BUFFER_DATA (buf), 0, diff);
880 gst_adapter_push (enc->adapter, buf);
883 while (gst_adapter_available (enc->adapter) >= bytes) {
885 gint outsize, written;
888 data = (gint16 *) gst_adapter_take (enc->adapter, bytes);
890 enc->samples_in += frame_size;
892 GST_DEBUG_OBJECT (enc, "encoding %d samples (%d bytes)", frame_size, bytes);
894 if (enc->channels == 2) {
895 speex_encode_stereo_int (data, frame_size, &enc->bits);
897 speex_encode_int (enc->state, data, &enc->bits);
904 if ((enc->frameno % enc->nframes) != 0)
907 speex_bits_insert_terminator (&enc->bits);
908 outsize = speex_bits_nbytes (&enc->bits);
910 ret = gst_pad_alloc_buffer_and_set_caps (enc->srcpad,
911 GST_BUFFER_OFFSET_NONE, outsize, GST_PAD_CAPS (enc->srcpad), &outbuf);
913 if ((GST_FLOW_OK != ret))
916 written = speex_bits_write (&enc->bits,
917 (gchar *) GST_BUFFER_DATA (outbuf), outsize);
918 g_assert (written == outsize);
919 speex_bits_reset (&enc->bits);
921 GST_BUFFER_TIMESTAMP (outbuf) = enc->start_ts +
922 gst_util_uint64_scale_int ((enc->frameno_out - 1) * frame_size -
923 enc->lookahead, GST_SECOND, enc->rate);
924 GST_BUFFER_DURATION (outbuf) = gst_util_uint64_scale_int (frame_size,
925 GST_SECOND, enc->rate);
926 /* set gp time and granulepos; see gst-plugins-base/ext/ogg/README */
927 GST_BUFFER_OFFSET_END (outbuf) = enc->granulepos_offset +
928 ((enc->frameno_out) * frame_size - enc->lookahead);
929 GST_BUFFER_OFFSET (outbuf) =
930 gst_util_uint64_scale_int (GST_BUFFER_OFFSET_END (outbuf), GST_SECOND,
933 ret = gst_speex_enc_push_buffer (enc, outbuf);
935 if ((GST_FLOW_OK != ret) && (GST_FLOW_NOT_LINKED != ret))
945 gst_speex_enc_chain (GstPad * pad, GstBuffer * buf)
948 GstFlowReturn ret = GST_FLOW_OK;
950 enc = GST_SPEEX_ENC (GST_PAD_PARENT (pad));
955 if (!enc->header_sent) {
956 /* Speex streams begin with two headers; the initial header (with
957 most of the codec setup parameters) which is mandated by the Ogg
958 bitstream spec. The second header holds any comment fields.
959 We merely need to make the headers, then pass them to libspeex
960 one at a time; libspeex handles the additional Ogg bitstream
962 GstBuffer *buf1, *buf2;
967 /* create header buffer */
968 data = (guint8 *) speex_header_to_packet (&enc->header, &data_len);
969 buf1 = gst_speex_enc_buffer_from_data (enc, data, data_len, 0);
972 /* create comment buffer */
973 buf2 = gst_speex_enc_create_metadata_buffer (enc);
975 /* mark and put on caps */
976 caps = gst_pad_get_caps (enc->srcpad);
977 caps = gst_speex_enc_set_header_on_caps (caps, buf1, buf2);
979 gst_caps_set_simple (caps,
980 "rate", G_TYPE_INT, enc->rate,
981 "channels", G_TYPE_INT, enc->channels, NULL);
983 /* negotiate with these caps */
984 GST_DEBUG_OBJECT (enc, "here are the caps: %" GST_PTR_FORMAT, caps);
985 gst_pad_set_caps (enc->srcpad, caps);
987 gst_buffer_set_caps (buf1, caps);
988 gst_buffer_set_caps (buf2, caps);
989 gst_caps_unref (caps);
991 /* push out buffers */
992 ret = gst_speex_enc_push_buffer (enc, buf1);
994 if (ret != GST_FLOW_OK) {
995 gst_buffer_unref (buf2);
999 ret = gst_speex_enc_push_buffer (enc, buf2);
1001 if (ret != GST_FLOW_OK)
1004 speex_bits_reset (&enc->bits);
1006 enc->header_sent = TRUE;
1009 /* Save the timestamp of the first buffer. This will be later
1010 * used as offset for all following buffers */
1011 if (enc->start_ts == GST_CLOCK_TIME_NONE) {
1012 if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)) {
1013 enc->start_ts = GST_BUFFER_TIMESTAMP (buf);
1014 enc->granulepos_offset = gst_util_uint64_scale
1015 (GST_BUFFER_TIMESTAMP (buf), enc->rate, GST_SECOND);
1018 enc->granulepos_offset = 0;
1022 /* Check if we have a continous stream, if not drop some samples or the buffer or
1023 * insert some silence samples */
1024 if (enc->next_ts != GST_CLOCK_TIME_NONE &&
1025 GST_BUFFER_TIMESTAMP (buf) < enc->next_ts) {
1026 guint64 diff = enc->next_ts - GST_BUFFER_TIMESTAMP (buf);
1029 GST_WARNING_OBJECT (enc, "Buffer is older than previous "
1030 "timestamp + duration (%" GST_TIME_FORMAT "< %" GST_TIME_FORMAT
1031 "), cannot handle. Clipping buffer.",
1032 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
1033 GST_TIME_ARGS (enc->next_ts));
1035 diff_bytes = GST_CLOCK_TIME_TO_FRAMES (diff, enc->rate) * enc->channels * 2;
1036 if (diff_bytes >= GST_BUFFER_SIZE (buf)) {
1037 gst_buffer_unref (buf);
1040 buf = gst_buffer_make_metadata_writable (buf);
1041 GST_BUFFER_DATA (buf) += diff_bytes;
1042 GST_BUFFER_SIZE (buf) -= diff_bytes;
1044 GST_BUFFER_TIMESTAMP (buf) += diff;
1045 if (GST_BUFFER_DURATION_IS_VALID (buf))
1046 GST_BUFFER_DURATION (buf) -= diff;
1049 if (enc->next_ts != GST_CLOCK_TIME_NONE
1050 && GST_BUFFER_TIMESTAMP_IS_VALID (buf)) {
1052 gst_util_uint64_scale (enc->frame_size, GST_SECOND, enc->rate);
1054 if (GST_BUFFER_TIMESTAMP (buf) != enc->next_ts &&
1055 GST_BUFFER_TIMESTAMP (buf) - enc->next_ts > max_diff) {
1056 GST_WARNING_OBJECT (enc,
1057 "Discontinuity detected: %" G_GUINT64_FORMAT " > %" G_GUINT64_FORMAT,
1058 GST_BUFFER_TIMESTAMP (buf) - enc->next_ts, max_diff);
1060 gst_speex_enc_encode (enc, TRUE);
1062 enc->frameno_out = 0;
1063 enc->start_ts = GST_BUFFER_TIMESTAMP (buf);
1064 enc->granulepos_offset = gst_util_uint64_scale
1065 (GST_BUFFER_TIMESTAMP (buf), enc->rate, GST_SECOND);
1069 if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)
1070 && GST_BUFFER_DURATION_IS_VALID (buf))
1071 enc->next_ts = GST_BUFFER_TIMESTAMP (buf) + GST_BUFFER_DURATION (buf);
1073 enc->next_ts = GST_CLOCK_TIME_NONE;
1075 GST_DEBUG_OBJECT (enc, "received buffer of %u bytes", GST_BUFFER_SIZE (buf));
1077 /* push buffer to adapter */
1078 gst_adapter_push (enc->adapter, buf);
1081 ret = gst_speex_enc_encode (enc, FALSE);
1086 gst_buffer_unref (buf);
1093 GST_ELEMENT_ERROR (enc, CORE, NEGOTIATION, (NULL),
1094 ("encoder not initialized (input is not audio?)"));
1095 ret = GST_FLOW_NOT_NEGOTIATED;
1103 gst_speex_enc_get_property (GObject * object, guint prop_id, GValue * value,
1108 enc = GST_SPEEX_ENC (object);
1112 g_value_set_float (value, enc->quality);
1115 g_value_set_int (value, enc->bitrate);
1118 g_value_set_enum (value, enc->mode);
1121 g_value_set_boolean (value, enc->vbr);
1124 g_value_set_int (value, enc->abr);
1127 g_value_set_boolean (value, enc->vad);
1130 g_value_set_boolean (value, enc->dtx);
1132 case PROP_COMPLEXITY:
1133 g_value_set_int (value, enc->complexity);
1136 g_value_set_int (value, enc->nframes);
1138 case PROP_LAST_MESSAGE:
1139 g_value_set_string (value, enc->last_message);
1142 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1148 gst_speex_enc_set_property (GObject * object, guint prop_id,
1149 const GValue * value, GParamSpec * pspec)
1153 enc = GST_SPEEX_ENC (object);
1157 enc->quality = g_value_get_float (value);
1160 enc->bitrate = g_value_get_int (value);
1163 enc->mode = g_value_get_enum (value);
1166 enc->vbr = g_value_get_boolean (value);
1169 enc->abr = g_value_get_int (value);
1172 enc->vad = g_value_get_boolean (value);
1175 enc->dtx = g_value_get_boolean (value);
1177 case PROP_COMPLEXITY:
1178 enc->complexity = g_value_get_int (value);
1181 enc->nframes = g_value_get_int (value);
1184 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1189 static GstStateChangeReturn
1190 gst_speex_enc_change_state (GstElement * element, GstStateChange transition)
1192 GstSpeexEnc *enc = GST_SPEEX_ENC (element);
1193 GstStateChangeReturn res;
1195 switch (transition) {
1196 case GST_STATE_CHANGE_NULL_TO_READY:
1197 enc->tags = gst_tag_list_new ();
1199 case GST_STATE_CHANGE_READY_TO_PAUSED:
1200 speex_bits_init (&enc->bits);
1202 enc->frameno_out = 0;
1203 enc->samples_in = 0;
1204 enc->start_ts = GST_CLOCK_TIME_NONE;
1205 enc->next_ts = GST_CLOCK_TIME_NONE;
1206 enc->granulepos_offset = 0;
1208 case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
1214 res = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1215 if (res == GST_STATE_CHANGE_FAILURE)
1218 switch (transition) {
1219 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
1221 case GST_STATE_CHANGE_PAUSED_TO_READY:
1223 enc->header_sent = FALSE;
1225 speex_encoder_destroy (enc->state);
1228 speex_bits_destroy (&enc->bits);
1230 case GST_STATE_CHANGE_READY_TO_NULL:
1231 gst_tag_list_free (enc->tags);