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 (pad, query))) {
499 gst_query_parse_latency (query, &live, &min_latency, &max_latency);
501 latency = gst_speex_enc_get_latency (enc);
503 /* add our latency */
504 min_latency += latency;
505 if (max_latency != -1)
506 max_latency += latency;
508 gst_query_set_latency (query, live, min_latency, max_latency);
513 res = gst_pad_peer_query (pad, query);
519 gst_object_unref (enc);
525 gst_speex_enc_sink_query (GstPad * pad, GstQuery * query)
530 enc = GST_SPEEX_ENC (GST_PAD_PARENT (pad));
532 switch (GST_QUERY_TYPE (query)) {
533 case GST_QUERY_CONVERT:
535 GstFormat src_fmt, dest_fmt;
536 gint64 src_val, dest_val;
538 gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, &dest_val);
540 gst_speex_enc_convert_sink (pad, src_fmt, src_val, &dest_fmt,
543 gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val);
547 res = gst_pad_query_default (pad, query);
556 gst_speex_enc_init (GstSpeexEnc * enc, GstSpeexEncClass * klass)
558 enc->sinkpad = gst_pad_new_from_static_template (&sink_factory, "sink");
559 gst_element_add_pad (GST_ELEMENT (enc), enc->sinkpad);
560 gst_pad_set_event_function (enc->sinkpad,
561 GST_DEBUG_FUNCPTR (gst_speex_enc_sinkevent));
562 gst_pad_set_chain_function (enc->sinkpad,
563 GST_DEBUG_FUNCPTR (gst_speex_enc_chain));
564 gst_pad_set_setcaps_function (enc->sinkpad,
565 GST_DEBUG_FUNCPTR (gst_speex_enc_sink_setcaps));
566 gst_pad_set_getcaps_function (enc->sinkpad,
567 GST_DEBUG_FUNCPTR (gst_speex_enc_sink_getcaps));
568 gst_pad_set_query_function (enc->sinkpad,
569 GST_DEBUG_FUNCPTR (gst_speex_enc_sink_query));
571 enc->srcpad = gst_pad_new_from_static_template (&src_factory, "src");
572 gst_pad_set_query_function (enc->srcpad,
573 GST_DEBUG_FUNCPTR (gst_speex_enc_src_query));
574 gst_pad_set_query_type_function (enc->srcpad,
575 GST_DEBUG_FUNCPTR (gst_speex_enc_get_query_types));
576 gst_element_add_pad (GST_ELEMENT (enc), enc->srcpad);
581 enc->quality = DEFAULT_QUALITY;
582 enc->bitrate = DEFAULT_BITRATE;
583 enc->mode = DEFAULT_MODE;
584 enc->vbr = DEFAULT_VBR;
585 enc->abr = DEFAULT_ABR;
586 enc->vad = DEFAULT_VAD;
587 enc->dtx = DEFAULT_DTX;
588 enc->complexity = DEFAULT_COMPLEXITY;
589 enc->nframes = DEFAULT_NFRAMES;
592 enc->header_sent = FALSE;
594 enc->adapter = gst_adapter_new ();
598 gst_speex_enc_create_metadata_buffer (GstSpeexEnc * enc)
600 const GstTagList *user_tags;
601 GstTagList *merged_tags;
602 GstBuffer *comments = NULL;
604 user_tags = gst_tag_setter_get_tag_list (GST_TAG_SETTER (enc));
606 GST_DEBUG_OBJECT (enc, "upstream tags = %" GST_PTR_FORMAT, enc->tags);
607 GST_DEBUG_OBJECT (enc, "user-set tags = %" GST_PTR_FORMAT, user_tags);
609 /* gst_tag_list_merge() will handle NULL for either or both lists fine */
610 merged_tags = gst_tag_list_merge (user_tags, enc->tags,
611 gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (enc)));
613 if (merged_tags == NULL)
614 merged_tags = gst_tag_list_new ();
616 GST_DEBUG_OBJECT (enc, "merged tags = %" GST_PTR_FORMAT, merged_tags);
617 comments = gst_tag_list_to_vorbiscomment_buffer (merged_tags, NULL,
618 0, "Encoded with GStreamer Speexenc");
619 gst_tag_list_free (merged_tags);
621 GST_BUFFER_OFFSET (comments) = enc->bytes_out;
622 GST_BUFFER_OFFSET_END (comments) = 0;
628 gst_speex_enc_set_last_msg (GstSpeexEnc * enc, const gchar * msg)
630 g_free (enc->last_message);
631 enc->last_message = g_strdup (msg);
632 GST_WARNING_OBJECT (enc, "%s", msg);
633 g_object_notify (G_OBJECT (enc), "last-message");
637 gst_speex_enc_setup (GstSpeexEnc * enc)
642 case GST_SPEEX_ENC_MODE_UWB:
643 GST_LOG_OBJECT (enc, "configuring for requested UWB mode");
644 enc->speex_mode = (SpeexMode *) & speex_uwb_mode;
646 case GST_SPEEX_ENC_MODE_WB:
647 GST_LOG_OBJECT (enc, "configuring for requested WB mode");
648 enc->speex_mode = (SpeexMode *) & speex_wb_mode;
650 case GST_SPEEX_ENC_MODE_NB:
651 GST_LOG_OBJECT (enc, "configuring for requested NB mode");
652 enc->speex_mode = (SpeexMode *) & speex_nb_mode;
654 case GST_SPEEX_ENC_MODE_AUTO:
656 GST_LOG_OBJECT (enc, "finding best mode");
661 if (enc->rate > 25000) {
662 if (enc->mode == GST_SPEEX_ENC_MODE_AUTO) {
663 GST_LOG_OBJECT (enc, "selected UWB mode for samplerate %d", enc->rate);
664 enc->speex_mode = (SpeexMode *) & speex_uwb_mode;
666 if (enc->speex_mode != &speex_uwb_mode) {
667 gst_speex_enc_set_last_msg (enc,
668 "Warning: suggest to use ultra wide band mode for this rate");
671 } else if (enc->rate > 12500) {
672 if (enc->mode == GST_SPEEX_ENC_MODE_AUTO) {
673 GST_LOG_OBJECT (enc, "selected WB mode for samplerate %d", enc->rate);
674 enc->speex_mode = (SpeexMode *) & speex_wb_mode;
676 if (enc->speex_mode != &speex_wb_mode) {
677 gst_speex_enc_set_last_msg (enc,
678 "Warning: suggest to use wide band mode for this rate");
682 if (enc->mode == GST_SPEEX_ENC_MODE_AUTO) {
683 GST_LOG_OBJECT (enc, "selected NB mode for samplerate %d", enc->rate);
684 enc->speex_mode = (SpeexMode *) & speex_nb_mode;
686 if (enc->speex_mode != &speex_nb_mode) {
687 gst_speex_enc_set_last_msg (enc,
688 "Warning: suggest to use narrow band mode for this rate");
693 if (enc->rate != 8000 && enc->rate != 16000 && enc->rate != 32000) {
694 gst_speex_enc_set_last_msg (enc,
695 "Warning: speex is optimized for 8, 16 and 32 KHz");
698 speex_init_header (&enc->header, enc->rate, 1, enc->speex_mode);
699 enc->header.frames_per_packet = enc->nframes;
700 enc->header.vbr = enc->vbr;
701 enc->header.nb_channels = enc->channels;
703 /*Initialize Speex encoder */
704 enc->state = speex_encoder_init (enc->speex_mode);
706 speex_encoder_ctl (enc->state, SPEEX_GET_FRAME_SIZE, &enc->frame_size);
707 speex_encoder_ctl (enc->state, SPEEX_SET_COMPLEXITY, &enc->complexity);
708 speex_encoder_ctl (enc->state, SPEEX_SET_SAMPLING_RATE, &enc->rate);
711 speex_encoder_ctl (enc->state, SPEEX_SET_VBR_QUALITY, &enc->quality);
713 gint tmp = floor (enc->quality);
715 speex_encoder_ctl (enc->state, SPEEX_SET_QUALITY, &tmp);
718 if (enc->quality >= 0.0 && enc->vbr) {
719 gst_speex_enc_set_last_msg (enc,
720 "Warning: bitrate option is overriding quality");
722 speex_encoder_ctl (enc->state, SPEEX_SET_BITRATE, &enc->bitrate);
727 speex_encoder_ctl (enc->state, SPEEX_SET_VBR, &tmp);
728 } else if (enc->vad) {
731 speex_encoder_ctl (enc->state, SPEEX_SET_VAD, &tmp);
737 speex_encoder_ctl (enc->state, SPEEX_SET_DTX, &tmp);
740 if (enc->dtx && !(enc->vbr || enc->abr || enc->vad)) {
741 gst_speex_enc_set_last_msg (enc,
742 "Warning: dtx is useless without vad, vbr or abr");
743 } else if ((enc->vbr || enc->abr) && (enc->vad)) {
744 gst_speex_enc_set_last_msg (enc,
745 "Warning: vad is already implied by vbr or abr");
749 speex_encoder_ctl (enc->state, SPEEX_SET_ABR, &enc->abr);
752 speex_encoder_ctl (enc->state, SPEEX_GET_LOOKAHEAD, &enc->lookahead);
754 GST_LOG_OBJECT (enc, "we have frame size %d, lookahead %d", enc->frame_size,
762 /* prepare a buffer for transmission */
764 gst_speex_enc_buffer_from_data (GstSpeexEnc * enc, guchar * data,
765 gint data_len, guint64 granulepos)
769 outbuf = gst_buffer_new_and_alloc (data_len);
770 memcpy (GST_BUFFER_DATA (outbuf), data, data_len);
771 GST_BUFFER_OFFSET (outbuf) = enc->bytes_out;
772 GST_BUFFER_OFFSET_END (outbuf) = granulepos;
774 GST_LOG_OBJECT (enc, "encoded buffer of %d bytes", GST_BUFFER_SIZE (outbuf));
779 /* push out the buffer and do internal bookkeeping */
781 gst_speex_enc_push_buffer (GstSpeexEnc * enc, GstBuffer * buffer)
785 size = GST_BUFFER_SIZE (buffer);
787 enc->bytes_out += size;
789 GST_DEBUG_OBJECT (enc, "pushing output buffer of size %u", size);
791 return gst_pad_push (enc->srcpad, buffer);
795 gst_speex_enc_set_header_on_caps (GstCaps * caps, GstBuffer * buf1,
798 GstStructure *structure = NULL;
800 GValue array = { 0 };
801 GValue value = { 0 };
803 caps = gst_caps_make_writable (caps);
804 structure = gst_caps_get_structure (caps, 0);
806 g_assert (gst_buffer_is_metadata_writable (buf1));
807 g_assert (gst_buffer_is_metadata_writable (buf2));
810 GST_BUFFER_FLAG_SET (buf1, GST_BUFFER_FLAG_IN_CAPS);
811 GST_BUFFER_FLAG_SET (buf2, GST_BUFFER_FLAG_IN_CAPS);
813 /* put buffers in a fixed list */
814 g_value_init (&array, GST_TYPE_ARRAY);
815 g_value_init (&value, GST_TYPE_BUFFER);
816 buf = gst_buffer_copy (buf1);
817 gst_value_set_buffer (&value, buf);
818 gst_buffer_unref (buf);
819 gst_value_array_append_value (&array, &value);
820 g_value_unset (&value);
821 g_value_init (&value, GST_TYPE_BUFFER);
822 buf = gst_buffer_copy (buf2);
823 gst_value_set_buffer (&value, buf);
824 gst_buffer_unref (buf);
825 gst_value_array_append_value (&array, &value);
826 gst_structure_set_value (structure, "streamheader", &array);
827 g_value_unset (&value);
828 g_value_unset (&array);
835 gst_speex_enc_sinkevent (GstPad * pad, GstEvent * event)
840 enc = GST_SPEEX_ENC (gst_pad_get_parent (pad));
842 switch (GST_EVENT_TYPE (event)) {
844 gst_speex_enc_encode (enc, TRUE);
845 res = gst_pad_event_default (pad, event);
851 gst_event_parse_tag (event, &list);
853 gst_tag_list_insert (enc->tags, list,
854 gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (enc)));
856 res = gst_pad_event_default (pad, event);
860 res = gst_pad_event_default (pad, event);
864 gst_object_unref (enc);
870 gst_speex_enc_encode (GstSpeexEnc * enc, gboolean flush)
872 gint frame_size = enc->frame_size;
873 gint bytes = frame_size * 2 * enc->channels;
874 GstFlowReturn ret = GST_FLOW_OK;
876 if (flush && gst_adapter_available (enc->adapter) % bytes != 0) {
877 guint diff = gst_adapter_available (enc->adapter) % bytes;
878 GstBuffer *buf = gst_buffer_new_and_alloc (diff);
880 memset (GST_BUFFER_DATA (buf), 0, diff);
881 gst_adapter_push (enc->adapter, buf);
884 while (gst_adapter_available (enc->adapter) >= bytes) {
886 gint outsize, written;
889 data = (gint16 *) gst_adapter_take (enc->adapter, bytes);
891 enc->samples_in += frame_size;
893 GST_DEBUG_OBJECT (enc, "encoding %d samples (%d bytes)", frame_size, bytes);
895 if (enc->channels == 2) {
896 speex_encode_stereo_int (data, frame_size, &enc->bits);
898 speex_encode_int (enc->state, data, &enc->bits);
905 if ((enc->frameno % enc->nframes) != 0)
908 speex_bits_insert_terminator (&enc->bits);
909 outsize = speex_bits_nbytes (&enc->bits);
911 ret = gst_pad_alloc_buffer_and_set_caps (enc->srcpad,
912 GST_BUFFER_OFFSET_NONE, outsize, GST_PAD_CAPS (enc->srcpad), &outbuf);
914 if ((GST_FLOW_OK != ret))
917 written = speex_bits_write (&enc->bits,
918 (gchar *) GST_BUFFER_DATA (outbuf), outsize);
919 g_assert (written == outsize);
920 speex_bits_reset (&enc->bits);
922 GST_BUFFER_TIMESTAMP (outbuf) = enc->start_ts +
923 gst_util_uint64_scale_int ((enc->frameno_out - 1) * frame_size -
924 enc->lookahead, GST_SECOND, enc->rate);
925 GST_BUFFER_DURATION (outbuf) = gst_util_uint64_scale_int (frame_size,
926 GST_SECOND, enc->rate);
927 /* set gp time and granulepos; see gst-plugins-base/ext/ogg/README */
928 GST_BUFFER_OFFSET_END (outbuf) = enc->granulepos_offset +
929 ((enc->frameno_out) * frame_size - enc->lookahead);
930 GST_BUFFER_OFFSET (outbuf) =
931 gst_util_uint64_scale_int (GST_BUFFER_OFFSET_END (outbuf), GST_SECOND,
934 ret = gst_speex_enc_push_buffer (enc, outbuf);
936 if ((GST_FLOW_OK != ret) && (GST_FLOW_NOT_LINKED != ret))
946 gst_speex_enc_chain (GstPad * pad, GstBuffer * buf)
949 GstFlowReturn ret = GST_FLOW_OK;
951 enc = GST_SPEEX_ENC (GST_PAD_PARENT (pad));
956 if (!enc->header_sent) {
957 /* Speex streams begin with two headers; the initial header (with
958 most of the codec setup parameters) which is mandated by the Ogg
959 bitstream spec. The second header holds any comment fields.
960 We merely need to make the headers, then pass them to libspeex
961 one at a time; libspeex handles the additional Ogg bitstream
963 GstBuffer *buf1, *buf2;
968 /* create header buffer */
969 data = (guint8 *) speex_header_to_packet (&enc->header, &data_len);
970 buf1 = gst_speex_enc_buffer_from_data (enc, data, data_len, 0);
973 /* create comment buffer */
974 buf2 = gst_speex_enc_create_metadata_buffer (enc);
976 /* mark and put on caps */
977 caps = gst_pad_get_caps (enc->srcpad);
978 caps = gst_speex_enc_set_header_on_caps (caps, buf1, buf2);
980 gst_caps_set_simple (caps,
981 "rate", G_TYPE_INT, enc->rate,
982 "channels", G_TYPE_INT, enc->channels, NULL);
984 /* negotiate with these caps */
985 GST_DEBUG_OBJECT (enc, "here are the caps: %" GST_PTR_FORMAT, caps);
986 gst_pad_set_caps (enc->srcpad, caps);
988 gst_buffer_set_caps (buf1, caps);
989 gst_buffer_set_caps (buf2, caps);
990 gst_caps_unref (caps);
992 /* push out buffers */
993 ret = gst_speex_enc_push_buffer (enc, buf1);
995 if (ret != GST_FLOW_OK) {
996 gst_buffer_unref (buf2);
1000 ret = gst_speex_enc_push_buffer (enc, buf2);
1002 if (ret != GST_FLOW_OK)
1005 speex_bits_reset (&enc->bits);
1007 enc->header_sent = TRUE;
1010 /* Save the timestamp of the first buffer. This will be later
1011 * used as offset for all following buffers */
1012 if (enc->start_ts == GST_CLOCK_TIME_NONE) {
1013 if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)) {
1014 enc->start_ts = GST_BUFFER_TIMESTAMP (buf);
1015 enc->granulepos_offset = gst_util_uint64_scale
1016 (GST_BUFFER_TIMESTAMP (buf), enc->rate, GST_SECOND);
1019 enc->granulepos_offset = 0;
1023 /* Check if we have a continous stream, if not drop some samples or the buffer or
1024 * insert some silence samples */
1025 if (enc->next_ts != GST_CLOCK_TIME_NONE &&
1026 GST_BUFFER_TIMESTAMP (buf) < enc->next_ts) {
1027 guint64 diff = enc->next_ts - GST_BUFFER_TIMESTAMP (buf);
1030 GST_WARNING_OBJECT (enc, "Buffer is older than previous "
1031 "timestamp + duration (%" GST_TIME_FORMAT "< %" GST_TIME_FORMAT
1032 "), cannot handle. Clipping buffer.",
1033 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
1034 GST_TIME_ARGS (enc->next_ts));
1036 diff_bytes = GST_CLOCK_TIME_TO_FRAMES (diff, enc->rate) * enc->channels * 2;
1037 if (diff_bytes >= GST_BUFFER_SIZE (buf)) {
1038 gst_buffer_unref (buf);
1041 buf = gst_buffer_make_metadata_writable (buf);
1042 GST_BUFFER_DATA (buf) += diff_bytes;
1043 GST_BUFFER_SIZE (buf) -= diff_bytes;
1045 GST_BUFFER_TIMESTAMP (buf) += diff;
1046 if (GST_BUFFER_DURATION_IS_VALID (buf))
1047 GST_BUFFER_DURATION (buf) -= diff;
1050 if (enc->next_ts != GST_CLOCK_TIME_NONE
1051 && GST_BUFFER_TIMESTAMP_IS_VALID (buf)) {
1053 gst_util_uint64_scale (enc->frame_size, GST_SECOND, enc->rate);
1055 if (GST_BUFFER_TIMESTAMP (buf) != enc->next_ts &&
1056 GST_BUFFER_TIMESTAMP (buf) - enc->next_ts > max_diff) {
1057 GST_WARNING_OBJECT (enc,
1058 "Discontinuity detected: %" G_GUINT64_FORMAT " > %" G_GUINT64_FORMAT,
1059 GST_BUFFER_TIMESTAMP (buf) - enc->next_ts, max_diff);
1061 gst_speex_enc_encode (enc, TRUE);
1063 enc->frameno_out = 0;
1064 enc->start_ts = GST_BUFFER_TIMESTAMP (buf);
1065 enc->granulepos_offset = gst_util_uint64_scale
1066 (GST_BUFFER_TIMESTAMP (buf), enc->rate, GST_SECOND);
1070 if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)
1071 && GST_BUFFER_DURATION_IS_VALID (buf))
1072 enc->next_ts = GST_BUFFER_TIMESTAMP (buf) + GST_BUFFER_DURATION (buf);
1074 enc->next_ts = GST_CLOCK_TIME_NONE;
1076 GST_DEBUG_OBJECT (enc, "received buffer of %u bytes", GST_BUFFER_SIZE (buf));
1078 /* push buffer to adapter */
1079 gst_adapter_push (enc->adapter, buf);
1082 ret = gst_speex_enc_encode (enc, FALSE);
1087 gst_buffer_unref (buf);
1094 GST_ELEMENT_ERROR (enc, CORE, NEGOTIATION, (NULL),
1095 ("encoder not initialized (input is not audio?)"));
1096 ret = GST_FLOW_NOT_NEGOTIATED;
1104 gst_speex_enc_get_property (GObject * object, guint prop_id, GValue * value,
1109 enc = GST_SPEEX_ENC (object);
1113 g_value_set_float (value, enc->quality);
1116 g_value_set_int (value, enc->bitrate);
1119 g_value_set_enum (value, enc->mode);
1122 g_value_set_boolean (value, enc->vbr);
1125 g_value_set_int (value, enc->abr);
1128 g_value_set_boolean (value, enc->vad);
1131 g_value_set_boolean (value, enc->dtx);
1133 case PROP_COMPLEXITY:
1134 g_value_set_int (value, enc->complexity);
1137 g_value_set_int (value, enc->nframes);
1139 case PROP_LAST_MESSAGE:
1140 g_value_set_string (value, enc->last_message);
1143 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1149 gst_speex_enc_set_property (GObject * object, guint prop_id,
1150 const GValue * value, GParamSpec * pspec)
1154 enc = GST_SPEEX_ENC (object);
1158 enc->quality = g_value_get_float (value);
1161 enc->bitrate = g_value_get_int (value);
1164 enc->mode = g_value_get_enum (value);
1167 enc->vbr = g_value_get_boolean (value);
1170 enc->abr = g_value_get_int (value);
1173 enc->vad = g_value_get_boolean (value);
1176 enc->dtx = g_value_get_boolean (value);
1178 case PROP_COMPLEXITY:
1179 enc->complexity = g_value_get_int (value);
1182 enc->nframes = g_value_get_int (value);
1185 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1190 static GstStateChangeReturn
1191 gst_speex_enc_change_state (GstElement * element, GstStateChange transition)
1193 GstSpeexEnc *enc = GST_SPEEX_ENC (element);
1194 GstStateChangeReturn res;
1196 switch (transition) {
1197 case GST_STATE_CHANGE_NULL_TO_READY:
1198 enc->tags = gst_tag_list_new ();
1200 case GST_STATE_CHANGE_READY_TO_PAUSED:
1201 speex_bits_init (&enc->bits);
1203 enc->frameno_out = 0;
1204 enc->samples_in = 0;
1205 enc->start_ts = GST_CLOCK_TIME_NONE;
1206 enc->next_ts = GST_CLOCK_TIME_NONE;
1207 enc->granulepos_offset = 0;
1209 case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
1215 res = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1216 if (res == GST_STATE_CHANGE_FAILURE)
1219 switch (transition) {
1220 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
1222 case GST_STATE_CHANGE_PAUSED_TO_READY:
1224 enc->header_sent = FALSE;
1226 speex_encoder_destroy (enc->state);
1229 speex_bits_destroy (&enc->bits);
1231 case GST_STATE_CHANGE_READY_TO_NULL:
1232 gst_tag_list_free (enc->tags);