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.
28 #include <speex/speex.h>
29 #include <speex/speex_stereo.h>
31 #include <gst/gsttagsetter.h>
32 #include <gst/tag/tag.h>
33 #include "gstspeexenc.h"
35 GST_DEBUG_CATEGORY_STATIC (speexenc_debug);
36 #define GST_CAT_DEFAULT speexenc_debug
38 static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
41 GST_STATIC_CAPS ("audio/x-raw-int, "
42 "rate = (int) [ 6000, 48000 ], "
43 "channels = (int) [ 1, 2 ], "
44 "endianness = (int) BYTE_ORDER, "
45 "signed = (boolean) TRUE, " "width = (int) 16, " "depth = (int) 16")
48 static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
51 GST_STATIC_CAPS ("audio/x-speex, "
52 "rate = (int) [ 6000, 48000 ], " "channels = (int) [ 1, 2]")
55 static const GstElementDetails speexenc_details =
56 GST_ELEMENT_DETAILS ("Speex audio encoder",
57 "Codec/Encoder/Audio",
58 "Encodes audio in Speex format",
59 "Wim Taymans <wim@fluendo.com>");
61 #define DEFAULT_QUALITY 8.0
62 #define DEFAULT_BITRATE 0
63 #define DEFAULT_MODE GST_SPEEX_ENC_MODE_AUTO
64 #define DEFAULT_VBR FALSE
66 #define DEFAULT_VAD FALSE
67 #define DEFAULT_DTX FALSE
68 #define DEFAULT_COMPLEXITY 3
69 #define DEFAULT_NFRAMES 1
86 #define GST_TYPE_SPEEX_ENC_MODE (gst_speex_enc_mode_get_type())
88 gst_speex_enc_mode_get_type (void)
90 static GType speex_enc_mode_type = 0;
91 static const GEnumValue speex_enc_modes[] = {
92 {GST_SPEEX_ENC_MODE_AUTO, "Auto", "auto"},
93 {GST_SPEEX_ENC_MODE_UWB, "Ultra Wide Band", "uwb"},
94 {GST_SPEEX_ENC_MODE_WB, "Wide Band", "wb"},
95 {GST_SPEEX_ENC_MODE_NB, "Narrow Band", "nb"},
98 if (G_UNLIKELY (speex_enc_mode_type == 0)) {
99 speex_enc_mode_type = g_enum_register_static ("GstSpeexEncMode",
102 return speex_enc_mode_type;
106 static const GstFormat *
107 gst_speex_enc_get_formats (GstPad * pad)
109 static const GstFormat src_formats[] = {
114 static const GstFormat sink_formats[] = {
121 return (GST_PAD_IS_SRC (pad) ? src_formats : sink_formats);
125 static void gst_speex_enc_finalize (GObject * object);
127 static gboolean gst_speex_enc_sinkevent (GstPad * pad, GstEvent * event);
128 static GstFlowReturn gst_speex_enc_chain (GstPad * pad, GstBuffer * buf);
129 static gboolean gst_speex_enc_setup (GstSpeexEnc * enc);
131 static void gst_speex_enc_get_property (GObject * object, guint prop_id,
132 GValue * value, GParamSpec * pspec);
133 static void gst_speex_enc_set_property (GObject * object, guint prop_id,
134 const GValue * value, GParamSpec * pspec);
135 static GstStateChangeReturn gst_speex_enc_change_state (GstElement * element,
136 GstStateChange transition);
139 gst_speex_enc_setup_interfaces (GType speexenc_type)
141 static const GInterfaceInfo tag_setter_info = { NULL, NULL, NULL };
143 g_type_add_interface_static (speexenc_type, GST_TYPE_TAG_SETTER,
146 GST_DEBUG_CATEGORY_INIT (speexenc_debug, "speexenc", 0, "Speex encoder");
149 GST_BOILERPLATE_FULL (GstSpeexEnc, gst_speex_enc, GstElement, GST_TYPE_ELEMENT,
150 gst_speex_enc_setup_interfaces);
153 gst_speex_enc_base_init (gpointer g_class)
155 GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
157 gst_element_class_add_pad_template (element_class,
158 gst_static_pad_template_get (&src_factory));
159 gst_element_class_add_pad_template (element_class,
160 gst_static_pad_template_get (&sink_factory));
161 gst_element_class_set_details (element_class, &speexenc_details);
165 gst_speex_enc_class_init (GstSpeexEncClass * klass)
167 GObjectClass *gobject_class;
168 GstElementClass *gstelement_class;
170 gobject_class = (GObjectClass *) klass;
171 gstelement_class = (GstElementClass *) klass;
173 gobject_class->set_property = gst_speex_enc_set_property;
174 gobject_class->get_property = gst_speex_enc_get_property;
176 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_QUALITY,
177 g_param_spec_float ("quality", "Quality", "Encoding quality",
178 0.0, 10.0, DEFAULT_QUALITY, G_PARAM_READWRITE));
179 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_BITRATE,
180 g_param_spec_int ("bitrate", "Encoding Bit-rate",
181 "Specify an encoding bit-rate (in bps). (0 = automatic)",
182 0, G_MAXINT, DEFAULT_BITRATE, G_PARAM_READWRITE));
183 g_object_class_install_property (gobject_class, PROP_MODE,
184 g_param_spec_enum ("mode", "Mode", "The encoding mode",
185 GST_TYPE_SPEEX_ENC_MODE, GST_SPEEX_ENC_MODE_AUTO,
186 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
187 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_VBR,
188 g_param_spec_boolean ("vbr", "VBR",
189 "Enable variable bit-rate", DEFAULT_VBR, G_PARAM_READWRITE));
190 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_ABR,
191 g_param_spec_int ("abr", "ABR",
192 "Enable average bit-rate (0 = disabled)",
193 0, G_MAXINT, DEFAULT_ABR, G_PARAM_READWRITE));
194 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_VAD,
195 g_param_spec_boolean ("vad", "VAD",
196 "Enable voice activity detection", DEFAULT_VAD, G_PARAM_READWRITE));
197 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_DTX,
198 g_param_spec_boolean ("dtx", "DTX",
199 "Enable discontinuous transmission", DEFAULT_DTX, G_PARAM_READWRITE));
200 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_COMPLEXITY,
201 g_param_spec_int ("complexity", "Complexity",
202 "Set encoding complexity",
203 0, G_MAXINT, DEFAULT_COMPLEXITY, G_PARAM_READWRITE));
204 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_NFRAMES,
205 g_param_spec_int ("nframes", "NFrames",
206 "Number of frames per buffer",
207 0, G_MAXINT, DEFAULT_NFRAMES, G_PARAM_READWRITE));
208 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_LAST_MESSAGE,
209 g_param_spec_string ("last-message", "last-message",
210 "The last status message", NULL, G_PARAM_READABLE));
212 gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_speex_enc_finalize);
214 gstelement_class->change_state =
215 GST_DEBUG_FUNCPTR (gst_speex_enc_change_state);
219 gst_speex_enc_finalize (GObject * object)
223 enc = GST_SPEEX_ENC (object);
225 g_free (enc->last_message);
226 g_object_unref (enc->adapter);
228 G_OBJECT_CLASS (parent_class)->finalize (object);
232 gst_speex_enc_sink_setcaps (GstPad * pad, GstCaps * caps)
235 GstStructure *structure;
237 enc = GST_SPEEX_ENC (GST_PAD_PARENT (pad));
240 structure = gst_caps_get_structure (caps, 0);
241 gst_structure_get_int (structure, "channels", &enc->channels);
242 gst_structure_get_int (structure, "rate", &enc->rate);
244 gst_speex_enc_setup (enc);
251 gst_speex_enc_sink_getcaps (GstPad * pad)
253 GstCaps *caps = gst_caps_copy (gst_pad_get_pad_template_caps (pad));
254 GstCaps *peercaps = NULL;
255 GstSpeexEnc *enc = GST_SPEEX_ENC (gst_pad_get_parent_element (pad));
257 peercaps = gst_pad_peer_get_caps (enc->srcpad);
260 if (!gst_caps_is_empty (peercaps) && !gst_caps_is_any (peercaps)) {
261 GstStructure *ps = gst_caps_get_structure (peercaps, 0);
262 GstStructure *s = gst_caps_get_structure (caps, 0);
265 if (gst_structure_get_int (ps, "rate", &rate)) {
266 gst_structure_fixate_field_nearest_int (s, "rate", rate);
269 if (gst_structure_get_int (ps, "channels", &channels)) {
270 gst_structure_fixate_field_nearest_int (s, "channels", channels);
273 gst_caps_unref (peercaps);
276 gst_object_unref (enc);
283 gst_speex_enc_convert_src (GstPad * pad, GstFormat src_format, gint64 src_value,
284 GstFormat * dest_format, gint64 * dest_value)
290 enc = GST_SPEEX_ENC (GST_PAD_PARENT (pad));
292 if (enc->samples_in == 0 || enc->bytes_out == 0 || enc->rate == 0)
295 avg = (enc->bytes_out * enc->rate) / (enc->samples_in);
297 switch (src_format) {
298 case GST_FORMAT_BYTES:
299 switch (*dest_format) {
300 case GST_FORMAT_TIME:
301 *dest_value = src_value * GST_SECOND / avg;
307 case GST_FORMAT_TIME:
308 switch (*dest_format) {
309 case GST_FORMAT_BYTES:
310 *dest_value = src_value * avg / GST_SECOND;
323 gst_speex_enc_convert_sink (GstPad * pad, GstFormat src_format,
324 gint64 src_value, GstFormat * dest_format, gint64 * dest_value)
328 gint bytes_per_sample;
331 enc = GST_SPEEX_ENC (GST_PAD_PARENT (pad));
333 bytes_per_sample = enc->channels * 2;
335 switch (src_format) {
336 case GST_FORMAT_BYTES:
337 switch (*dest_format) {
338 case GST_FORMAT_DEFAULT:
339 if (bytes_per_sample == 0)
341 *dest_value = src_value / bytes_per_sample;
343 case GST_FORMAT_TIME:
345 gint byterate = bytes_per_sample * enc->rate;
349 *dest_value = src_value * GST_SECOND / byterate;
356 case GST_FORMAT_DEFAULT:
357 switch (*dest_format) {
358 case GST_FORMAT_BYTES:
359 *dest_value = src_value * bytes_per_sample;
361 case GST_FORMAT_TIME:
364 *dest_value = src_value * GST_SECOND / enc->rate;
370 case GST_FORMAT_TIME:
371 switch (*dest_format) {
372 case GST_FORMAT_BYTES:
373 scale = bytes_per_sample;
375 case GST_FORMAT_DEFAULT:
376 *dest_value = src_value * scale * enc->rate / GST_SECOND;
389 gst_speex_enc_get_latency (GstSpeexEnc * enc)
391 return 30 * GST_MSECOND;
394 static const GstQueryType *
395 gst_speex_enc_get_query_types (GstPad * pad)
397 static const GstQueryType gst_speex_enc_src_query_types[] = {
405 return gst_speex_enc_src_query_types;
409 gst_speex_enc_src_query (GstPad * pad, GstQuery * query)
414 enc = GST_SPEEX_ENC (gst_pad_get_parent (pad));
416 switch (GST_QUERY_TYPE (query)) {
417 case GST_QUERY_POSITION:
419 GstFormat fmt, req_fmt;
422 gst_query_parse_position (query, &req_fmt, NULL);
423 if ((res = gst_pad_query_peer_position (enc->sinkpad, &req_fmt, &val))) {
424 gst_query_set_position (query, req_fmt, val);
428 fmt = GST_FORMAT_TIME;
429 if (!(res = gst_pad_query_peer_position (enc->sinkpad, &fmt, &pos)))
433 gst_pad_query_peer_convert (enc->sinkpad, fmt, pos, &req_fmt,
435 gst_query_set_position (query, req_fmt, val);
439 case GST_QUERY_DURATION:
441 GstFormat fmt, req_fmt;
444 gst_query_parse_duration (query, &req_fmt, NULL);
445 if ((res = gst_pad_query_peer_duration (enc->sinkpad, &req_fmt, &val))) {
446 gst_query_set_duration (query, req_fmt, val);
450 fmt = GST_FORMAT_TIME;
451 if (!(res = gst_pad_query_peer_duration (enc->sinkpad, &fmt, &dur)))
455 gst_pad_query_peer_convert (enc->sinkpad, fmt, dur, &req_fmt,
457 gst_query_set_duration (query, req_fmt, val);
461 case GST_QUERY_CONVERT:
463 GstFormat src_fmt, dest_fmt;
464 gint64 src_val, dest_val;
466 gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, &dest_val);
467 if (!(res = gst_speex_enc_convert_src (pad, src_fmt, src_val, &dest_fmt,
470 gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val);
473 case GST_QUERY_LATENCY:
476 GstClockTime min_latency, max_latency;
479 if ((res = gst_pad_peer_query (pad, query))) {
480 gst_query_parse_latency (query, &live, &min_latency, &max_latency);
482 latency = gst_speex_enc_get_latency (enc);
484 /* add our latency */
485 min_latency += latency;
486 if (max_latency != -1)
487 max_latency += latency;
489 gst_query_set_latency (query, live, min_latency, max_latency);
494 res = gst_pad_peer_query (pad, query);
500 gst_object_unref (enc);
506 gst_speex_enc_sink_query (GstPad * pad, GstQuery * query)
511 enc = GST_SPEEX_ENC (GST_PAD_PARENT (pad));
513 switch (GST_QUERY_TYPE (query)) {
514 case GST_QUERY_CONVERT:
516 GstFormat src_fmt, dest_fmt;
517 gint64 src_val, dest_val;
519 gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, &dest_val);
521 gst_speex_enc_convert_sink (pad, src_fmt, src_val, &dest_fmt,
524 gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val);
528 res = gst_pad_query_default (pad, query);
537 gst_speex_enc_init (GstSpeexEnc * enc, GstSpeexEncClass * klass)
539 enc->sinkpad = gst_pad_new_from_static_template (&sink_factory, "sink");
540 gst_element_add_pad (GST_ELEMENT (enc), enc->sinkpad);
541 gst_pad_set_event_function (enc->sinkpad,
542 GST_DEBUG_FUNCPTR (gst_speex_enc_sinkevent));
543 gst_pad_set_chain_function (enc->sinkpad,
544 GST_DEBUG_FUNCPTR (gst_speex_enc_chain));
545 gst_pad_set_setcaps_function (enc->sinkpad,
546 GST_DEBUG_FUNCPTR (gst_speex_enc_sink_setcaps));
547 gst_pad_set_getcaps_function (enc->sinkpad,
548 GST_DEBUG_FUNCPTR (gst_speex_enc_sink_getcaps));
549 gst_pad_set_query_function (enc->sinkpad,
550 GST_DEBUG_FUNCPTR (gst_speex_enc_sink_query));
552 enc->srcpad = gst_pad_new_from_static_template (&src_factory, "src");
553 gst_pad_set_query_function (enc->srcpad,
554 GST_DEBUG_FUNCPTR (gst_speex_enc_src_query));
555 gst_pad_set_query_type_function (enc->srcpad,
556 GST_DEBUG_FUNCPTR (gst_speex_enc_get_query_types));
557 gst_element_add_pad (GST_ELEMENT (enc), enc->srcpad);
562 enc->quality = DEFAULT_QUALITY;
563 enc->bitrate = DEFAULT_BITRATE;
564 enc->mode = DEFAULT_MODE;
565 enc->vbr = DEFAULT_VBR;
566 enc->abr = DEFAULT_ABR;
567 enc->vad = DEFAULT_VAD;
568 enc->dtx = DEFAULT_DTX;
569 enc->complexity = DEFAULT_COMPLEXITY;
570 enc->nframes = DEFAULT_NFRAMES;
573 enc->header_sent = FALSE;
575 enc->adapter = gst_adapter_new ();
579 gst_speex_enc_create_metadata_buffer (GstSpeexEnc * enc)
581 const GstTagList *user_tags;
582 GstTagList *merged_tags;
583 GstBuffer *comments = NULL;
585 user_tags = gst_tag_setter_get_tag_list (GST_TAG_SETTER (enc));
587 GST_DEBUG_OBJECT (enc, "upstream tags = %" GST_PTR_FORMAT, enc->tags);
588 GST_DEBUG_OBJECT (enc, "user-set tags = %" GST_PTR_FORMAT, user_tags);
590 /* gst_tag_list_merge() will handle NULL for either or both lists fine */
591 merged_tags = gst_tag_list_merge (user_tags, enc->tags,
592 gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (enc)));
594 if (merged_tags == NULL)
595 merged_tags = gst_tag_list_new ();
597 GST_DEBUG_OBJECT (enc, "merged tags = %" GST_PTR_FORMAT, merged_tags);
598 comments = gst_tag_list_to_vorbiscomment_buffer (merged_tags, NULL,
599 0, "Encoded with GStreamer Speexenc");
600 gst_tag_list_free (merged_tags);
602 GST_BUFFER_OFFSET (comments) = enc->bytes_out;
603 GST_BUFFER_OFFSET_END (comments) = 0;
609 gst_speex_enc_set_last_msg (GstSpeexEnc * enc, const gchar * msg)
611 g_free (enc->last_message);
612 enc->last_message = g_strdup (msg);
613 GST_WARNING_OBJECT (enc, "%s", msg);
614 g_object_notify (G_OBJECT (enc), "last-message");
618 gst_speex_enc_setup (GstSpeexEnc * enc)
623 case GST_SPEEX_ENC_MODE_UWB:
624 GST_LOG_OBJECT (enc, "configuring for requested UWB mode");
625 enc->speex_mode = (SpeexMode *) & speex_uwb_mode;
627 case GST_SPEEX_ENC_MODE_WB:
628 GST_LOG_OBJECT (enc, "configuring for requested WB mode");
629 enc->speex_mode = (SpeexMode *) & speex_wb_mode;
631 case GST_SPEEX_ENC_MODE_NB:
632 GST_LOG_OBJECT (enc, "configuring for requested NB mode");
633 enc->speex_mode = (SpeexMode *) & speex_nb_mode;
635 case GST_SPEEX_ENC_MODE_AUTO:
637 GST_LOG_OBJECT (enc, "finding best mode");
642 if (enc->rate > 25000) {
643 if (enc->mode == GST_SPEEX_ENC_MODE_AUTO) {
644 GST_LOG_OBJECT (enc, "selected UWB mode for samplerate %d", enc->rate);
645 enc->speex_mode = (SpeexMode *) & speex_uwb_mode;
647 if (enc->speex_mode != &speex_uwb_mode) {
648 gst_speex_enc_set_last_msg (enc,
649 "Warning: suggest to use ultra wide band mode for this rate");
652 } else if (enc->rate > 12500) {
653 if (enc->mode == GST_SPEEX_ENC_MODE_AUTO) {
654 GST_LOG_OBJECT (enc, "selected WB mode for samplerate %d", enc->rate);
655 enc->speex_mode = (SpeexMode *) & speex_wb_mode;
657 if (enc->speex_mode != &speex_wb_mode) {
658 gst_speex_enc_set_last_msg (enc,
659 "Warning: suggest to use wide band mode for this rate");
663 if (enc->mode == GST_SPEEX_ENC_MODE_AUTO) {
664 GST_LOG_OBJECT (enc, "selected NB mode for samplerate %d", enc->rate);
665 enc->speex_mode = (SpeexMode *) & speex_nb_mode;
667 if (enc->speex_mode != &speex_nb_mode) {
668 gst_speex_enc_set_last_msg (enc,
669 "Warning: suggest to use narrow band mode for this rate");
674 if (enc->rate != 8000 && enc->rate != 16000 && enc->rate != 32000) {
675 gst_speex_enc_set_last_msg (enc,
676 "Warning: speex is optimized for 8, 16 and 32 KHz");
679 speex_init_header (&enc->header, enc->rate, 1, enc->speex_mode);
680 enc->header.frames_per_packet = enc->nframes;
681 enc->header.vbr = enc->vbr;
682 enc->header.nb_channels = enc->channels;
684 /*Initialize Speex encoder */
685 enc->state = speex_encoder_init (enc->speex_mode);
687 speex_encoder_ctl (enc->state, SPEEX_GET_FRAME_SIZE, &enc->frame_size);
688 speex_encoder_ctl (enc->state, SPEEX_SET_COMPLEXITY, &enc->complexity);
689 speex_encoder_ctl (enc->state, SPEEX_SET_SAMPLING_RATE, &enc->rate);
692 speex_encoder_ctl (enc->state, SPEEX_SET_VBR_QUALITY, &enc->quality);
694 gint tmp = floor (enc->quality);
696 speex_encoder_ctl (enc->state, SPEEX_SET_QUALITY, &tmp);
699 if (enc->quality >= 0.0 && enc->vbr) {
700 gst_speex_enc_set_last_msg (enc,
701 "Warning: bitrate option is overriding quality");
703 speex_encoder_ctl (enc->state, SPEEX_SET_BITRATE, &enc->bitrate);
708 speex_encoder_ctl (enc->state, SPEEX_SET_VBR, &tmp);
709 } else if (enc->vad) {
712 speex_encoder_ctl (enc->state, SPEEX_SET_VAD, &tmp);
718 speex_encoder_ctl (enc->state, SPEEX_SET_DTX, &tmp);
721 if (enc->dtx && !(enc->vbr || enc->abr || enc->vad)) {
722 gst_speex_enc_set_last_msg (enc,
723 "Warning: dtx is useless without vad, vbr or abr");
724 } else if ((enc->vbr || enc->abr) && (enc->vad)) {
725 gst_speex_enc_set_last_msg (enc,
726 "Warning: vad is already implied by vbr or abr");
730 speex_encoder_ctl (enc->state, SPEEX_SET_ABR, &enc->abr);
733 speex_encoder_ctl (enc->state, SPEEX_GET_LOOKAHEAD, &enc->lookahead);
735 GST_LOG_OBJECT (enc, "we have frame size %d, lookahead %d", enc->frame_size,
743 /* prepare a buffer for transmission */
745 gst_speex_enc_buffer_from_data (GstSpeexEnc * enc, guchar * data,
746 gint data_len, guint64 granulepos)
750 outbuf = gst_buffer_new_and_alloc (data_len);
751 memcpy (GST_BUFFER_DATA (outbuf), data, data_len);
752 GST_BUFFER_OFFSET (outbuf) = enc->bytes_out;
753 GST_BUFFER_OFFSET_END (outbuf) = granulepos;
755 GST_LOG_OBJECT (enc, "encoded buffer of %d bytes", GST_BUFFER_SIZE (outbuf));
760 /* push out the buffer and do internal bookkeeping */
762 gst_speex_enc_push_buffer (GstSpeexEnc * enc, GstBuffer * buffer)
766 size = GST_BUFFER_SIZE (buffer);
768 enc->bytes_out += size;
770 GST_DEBUG_OBJECT (enc, "pushing output buffer of size %u", size);
772 return gst_pad_push (enc->srcpad, buffer);
776 gst_speex_enc_set_header_on_caps (GstCaps * caps, GstBuffer * buf1,
779 GstStructure *structure = NULL;
781 GValue array = { 0 };
782 GValue value = { 0 };
784 caps = gst_caps_make_writable (caps);
785 structure = gst_caps_get_structure (caps, 0);
787 g_assert (gst_buffer_is_metadata_writable (buf1));
788 g_assert (gst_buffer_is_metadata_writable (buf2));
791 GST_BUFFER_FLAG_SET (buf1, GST_BUFFER_FLAG_IN_CAPS);
792 GST_BUFFER_FLAG_SET (buf2, GST_BUFFER_FLAG_IN_CAPS);
794 /* put buffers in a fixed list */
795 g_value_init (&array, GST_TYPE_ARRAY);
796 g_value_init (&value, GST_TYPE_BUFFER);
797 buf = gst_buffer_copy (buf1);
798 gst_value_set_buffer (&value, buf);
799 gst_buffer_unref (buf);
800 gst_value_array_append_value (&array, &value);
801 g_value_unset (&value);
802 g_value_init (&value, GST_TYPE_BUFFER);
803 buf = gst_buffer_copy (buf2);
804 gst_value_set_buffer (&value, buf);
805 gst_buffer_unref (buf);
806 gst_value_array_append_value (&array, &value);
807 gst_structure_set_value (structure, "streamheader", &array);
808 g_value_unset (&value);
809 g_value_unset (&array);
816 gst_speex_enc_sinkevent (GstPad * pad, GstEvent * event)
821 enc = GST_SPEEX_ENC (gst_pad_get_parent (pad));
823 switch (GST_EVENT_TYPE (event)) {
826 res = gst_pad_event_default (pad, event);
832 gst_event_parse_tag (event, &list);
834 gst_tag_list_insert (enc->tags, list,
835 gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (enc)));
837 res = gst_pad_event_default (pad, event);
841 res = gst_pad_event_default (pad, event);
845 gst_object_unref (enc);
852 gst_speex_enc_chain (GstPad * pad, GstBuffer * buf)
855 GstFlowReturn ret = GST_FLOW_OK;
857 enc = GST_SPEEX_ENC (GST_PAD_PARENT (pad));
862 if (!enc->header_sent) {
863 /* Speex streams begin with two headers; the initial header (with
864 most of the codec setup parameters) which is mandated by the Ogg
865 bitstream spec. The second header holds any comment fields.
866 We merely need to make the headers, then pass them to libspeex
867 one at a time; libspeex handles the additional Ogg bitstream
869 GstBuffer *buf1, *buf2;
874 /* create header buffer */
875 data = (guint8 *) speex_header_to_packet (&enc->header, &data_len);
876 buf1 = gst_speex_enc_buffer_from_data (enc, data, data_len, 0);
879 /* create comment buffer */
880 buf2 = gst_speex_enc_create_metadata_buffer (enc);
882 /* mark and put on caps */
883 caps = gst_pad_get_caps (enc->srcpad);
884 caps = gst_speex_enc_set_header_on_caps (caps, buf1, buf2);
886 gst_caps_set_simple (caps,
887 "rate", G_TYPE_INT, enc->rate,
888 "channels", G_TYPE_INT, enc->channels, NULL);
890 /* negotiate with these caps */
891 GST_DEBUG_OBJECT (enc, "here are the caps: %" GST_PTR_FORMAT, caps);
892 gst_pad_set_caps (enc->srcpad, caps);
894 gst_buffer_set_caps (buf1, caps);
895 gst_buffer_set_caps (buf2, caps);
896 gst_caps_unref (caps);
898 /* push out buffers */
899 ret = gst_speex_enc_push_buffer (enc, buf1);
901 if (ret != GST_FLOW_OK) {
902 gst_buffer_unref (buf2);
906 ret = gst_speex_enc_push_buffer (enc, buf2);
908 if (ret != GST_FLOW_OK)
911 speex_bits_reset (&enc->bits);
913 enc->header_sent = TRUE;
917 gint frame_size = enc->frame_size;
918 gint bytes = frame_size * 2 * enc->channels;
920 GST_DEBUG_OBJECT (enc, "received buffer of %u bytes",
921 GST_BUFFER_SIZE (buf));
923 /* push buffer to adapter */
924 gst_adapter_push (enc->adapter, buf);
927 while (gst_adapter_available (enc->adapter) >= bytes) {
930 gint outsize, written;
933 data = (gint16 *) gst_adapter_peek (enc->adapter, bytes);
935 for (i = 0; i < frame_size * enc->channels; i++) {
936 enc->input[i] = (gfloat) data[i];
938 gst_adapter_flush (enc->adapter, bytes);
940 enc->samples_in += frame_size;
942 GST_DEBUG_OBJECT (enc, "encoding %d samples (%d bytes)", frame_size,
945 if (enc->channels == 2) {
946 speex_encode_stereo (enc->input, frame_size, &enc->bits);
948 speex_encode (enc->state, enc->input, &enc->bits);
952 if ((enc->frameno % enc->nframes) != 0)
955 speex_bits_insert_terminator (&enc->bits);
956 outsize = speex_bits_nbytes (&enc->bits);
958 ret = gst_pad_alloc_buffer_and_set_caps (enc->srcpad,
959 GST_BUFFER_OFFSET_NONE, outsize, GST_PAD_CAPS (enc->srcpad), &outbuf);
961 if ((GST_FLOW_OK != ret))
964 written = speex_bits_write (&enc->bits,
965 (gchar *) GST_BUFFER_DATA (outbuf), outsize);
966 g_assert (written == outsize);
967 speex_bits_reset (&enc->bits);
969 GST_BUFFER_TIMESTAMP (outbuf) =
970 gst_util_uint64_scale_int (enc->frameno * frame_size -
971 enc->lookahead, GST_SECOND, enc->rate);
972 GST_BUFFER_DURATION (outbuf) = gst_util_uint64_scale_int (frame_size,
973 GST_SECOND, enc->rate);
974 /* set gp time and granulepos; see gst-plugins-base/ext/ogg/README */
975 GST_BUFFER_OFFSET_END (outbuf) =
976 ((enc->frameno + 1) * frame_size - enc->lookahead);
977 GST_BUFFER_OFFSET (outbuf) =
978 gst_util_uint64_scale_int (GST_BUFFER_OFFSET_END (outbuf), GST_SECOND,
981 ret = gst_speex_enc_push_buffer (enc, outbuf);
983 if ((GST_FLOW_OK != ret) && (GST_FLOW_NOT_LINKED != ret))
991 gst_buffer_unref (buf);
998 GST_ELEMENT_ERROR (enc, CORE, NEGOTIATION, (NULL),
999 ("encoder not initialized (input is not audio?)"));
1000 ret = GST_FLOW_NOT_NEGOTIATED;
1008 gst_speex_enc_get_property (GObject * object, guint prop_id, GValue * value,
1013 enc = GST_SPEEX_ENC (object);
1017 g_value_set_float (value, enc->quality);
1020 g_value_set_int (value, enc->bitrate);
1023 g_value_set_enum (value, enc->mode);
1026 g_value_set_boolean (value, enc->vbr);
1029 g_value_set_int (value, enc->abr);
1032 g_value_set_boolean (value, enc->vad);
1035 g_value_set_boolean (value, enc->dtx);
1037 case PROP_COMPLEXITY:
1038 g_value_set_int (value, enc->complexity);
1041 g_value_set_int (value, enc->nframes);
1043 case PROP_LAST_MESSAGE:
1044 g_value_set_string (value, enc->last_message);
1047 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1053 gst_speex_enc_set_property (GObject * object, guint prop_id,
1054 const GValue * value, GParamSpec * pspec)
1058 enc = GST_SPEEX_ENC (object);
1062 enc->quality = g_value_get_float (value);
1065 enc->bitrate = g_value_get_int (value);
1068 enc->mode = g_value_get_enum (value);
1071 enc->vbr = g_value_get_boolean (value);
1074 enc->abr = g_value_get_int (value);
1077 enc->vad = g_value_get_boolean (value);
1080 enc->dtx = g_value_get_boolean (value);
1082 case PROP_COMPLEXITY:
1083 enc->complexity = g_value_get_int (value);
1086 enc->nframes = g_value_get_int (value);
1089 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1094 static GstStateChangeReturn
1095 gst_speex_enc_change_state (GstElement * element, GstStateChange transition)
1097 GstSpeexEnc *enc = GST_SPEEX_ENC (element);
1098 GstStateChangeReturn res;
1100 switch (transition) {
1101 case GST_STATE_CHANGE_NULL_TO_READY:
1102 enc->tags = gst_tag_list_new ();
1104 case GST_STATE_CHANGE_READY_TO_PAUSED:
1105 speex_bits_init (&enc->bits);
1107 enc->samples_in = 0;
1109 case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
1115 res = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1116 if (res == GST_STATE_CHANGE_FAILURE)
1119 switch (transition) {
1120 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
1122 case GST_STATE_CHANGE_PAUSED_TO_READY:
1124 enc->header_sent = FALSE;
1126 speex_encoder_destroy (enc->state);
1129 speex_bits_destroy (&enc->bits);
1131 case GST_STATE_CHANGE_READY_TO_NULL:
1132 gst_tag_list_free (enc->tags);