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_VBR FALSE
65 #define DEFAULT_VAD FALSE
66 #define DEFAULT_DTX FALSE
67 #define DEFAULT_COMPLEXITY 3
68 #define DEFAULT_NFRAMES 1
85 static const GstFormat *
86 gst_speex_enc_get_formats (GstPad * pad)
88 static const GstFormat src_formats[] = {
93 static const GstFormat sink_formats[] = {
100 return (GST_PAD_IS_SRC (pad) ? src_formats : sink_formats);
104 static void gst_speex_enc_finalize (GObject * object);
106 static gboolean gst_speex_enc_sinkevent (GstPad * pad, GstEvent * event);
107 static GstFlowReturn gst_speex_enc_chain (GstPad * pad, GstBuffer * buf);
108 static gboolean gst_speex_enc_setup (GstSpeexEnc * enc);
110 static void gst_speex_enc_get_property (GObject * object, guint prop_id,
111 GValue * value, GParamSpec * pspec);
112 static void gst_speex_enc_set_property (GObject * object, guint prop_id,
113 const GValue * value, GParamSpec * pspec);
114 static GstStateChangeReturn gst_speex_enc_change_state (GstElement * element,
115 GstStateChange transition);
118 gst_speex_enc_setup_interfaces (GType speexenc_type)
120 static const GInterfaceInfo tag_setter_info = { NULL, NULL, NULL };
122 g_type_add_interface_static (speexenc_type, GST_TYPE_TAG_SETTER,
125 GST_DEBUG_CATEGORY_INIT (speexenc_debug, "speexenc", 0, "Speex encoder");
128 GST_BOILERPLATE_FULL (GstSpeexEnc, gst_speex_enc, GstElement, GST_TYPE_ELEMENT,
129 gst_speex_enc_setup_interfaces);
132 gst_speex_enc_base_init (gpointer g_class)
134 GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
136 gst_element_class_add_pad_template (element_class,
137 gst_static_pad_template_get (&src_factory));
138 gst_element_class_add_pad_template (element_class,
139 gst_static_pad_template_get (&sink_factory));
140 gst_element_class_set_details (element_class, &speexenc_details);
144 gst_speex_enc_class_init (GstSpeexEncClass * klass)
146 GObjectClass *gobject_class;
147 GstElementClass *gstelement_class;
149 gobject_class = (GObjectClass *) klass;
150 gstelement_class = (GstElementClass *) klass;
152 gobject_class->set_property = gst_speex_enc_set_property;
153 gobject_class->get_property = gst_speex_enc_get_property;
155 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_QUALITY,
156 g_param_spec_float ("quality", "Quality", "Encoding quality",
157 0.0, 10.0, DEFAULT_QUALITY, G_PARAM_READWRITE));
158 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_BITRATE,
159 g_param_spec_int ("bitrate", "Encoding Bit-rate",
160 "Specify an encoding bit-rate (in bps). (0 = automatic)",
161 0, G_MAXINT, DEFAULT_BITRATE, G_PARAM_READWRITE));
162 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_VBR,
163 g_param_spec_boolean ("vbr", "VBR",
164 "Enable variable bit-rate", DEFAULT_VBR, G_PARAM_READWRITE));
165 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_ABR,
166 g_param_spec_int ("abr", "ABR",
167 "Enable average bit-rate (0 = disabled)",
168 0, G_MAXINT, DEFAULT_ABR, G_PARAM_READWRITE));
169 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_VAD,
170 g_param_spec_boolean ("vad", "VAD",
171 "Enable voice activity detection", DEFAULT_VAD, G_PARAM_READWRITE));
172 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_DTX,
173 g_param_spec_boolean ("dtx", "DTX",
174 "Enable discontinuous transmission", DEFAULT_DTX, G_PARAM_READWRITE));
175 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_COMPLEXITY,
176 g_param_spec_int ("complexity", "Complexity",
177 "Set encoding complexity",
178 0, G_MAXINT, DEFAULT_COMPLEXITY, G_PARAM_READWRITE));
179 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_NFRAMES,
180 g_param_spec_int ("nframes", "NFrames",
181 "Number of frames per buffer",
182 0, G_MAXINT, DEFAULT_NFRAMES, G_PARAM_READWRITE));
183 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_LAST_MESSAGE,
184 g_param_spec_string ("last-message", "last-message",
185 "The last status message", NULL, G_PARAM_READABLE));
187 gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_speex_enc_finalize);
189 gstelement_class->change_state =
190 GST_DEBUG_FUNCPTR (gst_speex_enc_change_state);
194 gst_speex_enc_finalize (GObject * object)
198 enc = GST_SPEEX_ENC (object);
200 g_free (enc->last_message);
201 g_object_unref (enc->adapter);
203 G_OBJECT_CLASS (parent_class)->finalize (object);
207 gst_speex_enc_sink_setcaps (GstPad * pad, GstCaps * caps)
210 GstStructure *structure;
212 enc = GST_SPEEX_ENC (GST_PAD_PARENT (pad));
215 structure = gst_caps_get_structure (caps, 0);
216 gst_structure_get_int (structure, "channels", &enc->channels);
217 gst_structure_get_int (structure, "rate", &enc->rate);
219 gst_speex_enc_setup (enc);
226 gst_speex_enc_sink_getcaps (GstPad * pad)
228 GstCaps *caps = gst_caps_copy (gst_pad_get_pad_template_caps (pad));
229 GstCaps *peercaps = NULL;
230 GstSpeexEnc *enc = GST_SPEEX_ENC (gst_pad_get_parent_element (pad));
232 peercaps = gst_pad_peer_get_caps (enc->srcpad);
235 if (!gst_caps_is_empty (peercaps) && !gst_caps_is_any (peercaps)) {
236 GstStructure *ps = gst_caps_get_structure (peercaps, 0);
237 GstStructure *s = gst_caps_get_structure (caps, 0);;
240 if (gst_structure_get_int (ps, "rate", &rate)) {
241 gst_structure_fixate_field_nearest_int (s, "rate", rate);
244 if (gst_structure_get_int (ps, "channels", &channels)) {
245 gst_structure_fixate_field_nearest_int (s, "channels", channels);
248 gst_caps_unref (peercaps);
251 gst_object_unref (enc);
258 gst_speex_enc_convert_src (GstPad * pad, GstFormat src_format, gint64 src_value,
259 GstFormat * dest_format, gint64 * dest_value)
265 enc = GST_SPEEX_ENC (GST_PAD_PARENT (pad));
267 if (enc->samples_in == 0 || enc->bytes_out == 0 || enc->rate == 0)
270 avg = (enc->bytes_out * enc->rate) / (enc->samples_in);
272 switch (src_format) {
273 case GST_FORMAT_BYTES:
274 switch (*dest_format) {
275 case GST_FORMAT_TIME:
276 *dest_value = src_value * GST_SECOND / avg;
282 case GST_FORMAT_TIME:
283 switch (*dest_format) {
284 case GST_FORMAT_BYTES:
285 *dest_value = src_value * avg / GST_SECOND;
298 gst_speex_enc_convert_sink (GstPad * pad, GstFormat src_format,
299 gint64 src_value, GstFormat * dest_format, gint64 * dest_value)
303 gint bytes_per_sample;
306 enc = GST_SPEEX_ENC (GST_PAD_PARENT (pad));
308 bytes_per_sample = enc->channels * 2;
310 switch (src_format) {
311 case GST_FORMAT_BYTES:
312 switch (*dest_format) {
313 case GST_FORMAT_DEFAULT:
314 if (bytes_per_sample == 0)
316 *dest_value = src_value / bytes_per_sample;
318 case GST_FORMAT_TIME:
320 gint byterate = bytes_per_sample * enc->rate;
324 *dest_value = src_value * GST_SECOND / byterate;
331 case GST_FORMAT_DEFAULT:
332 switch (*dest_format) {
333 case GST_FORMAT_BYTES:
334 *dest_value = src_value * bytes_per_sample;
336 case GST_FORMAT_TIME:
339 *dest_value = src_value * GST_SECOND / enc->rate;
345 case GST_FORMAT_TIME:
346 switch (*dest_format) {
347 case GST_FORMAT_BYTES:
348 scale = bytes_per_sample;
350 case GST_FORMAT_DEFAULT:
351 *dest_value = src_value * scale * enc->rate / GST_SECOND;
363 static const GstQueryType *
364 gst_speex_enc_get_query_types (GstPad * pad)
366 static const GstQueryType gst_speex_enc_src_query_types[] = {
373 return gst_speex_enc_src_query_types;
377 gst_speex_enc_src_query (GstPad * pad, GstQuery * query)
382 enc = GST_SPEEX_ENC (gst_pad_get_parent (pad));
384 switch (GST_QUERY_TYPE (query)) {
385 case GST_QUERY_POSITION:
387 GstFormat fmt, req_fmt;
390 gst_query_parse_position (query, &req_fmt, NULL);
391 if ((res = gst_pad_query_peer_position (enc->sinkpad, &req_fmt, &val))) {
392 gst_query_set_position (query, req_fmt, val);
396 fmt = GST_FORMAT_TIME;
397 if (!(res = gst_pad_query_peer_position (enc->sinkpad, &fmt, &pos)))
401 gst_pad_query_peer_convert (enc->sinkpad, fmt, pos, &req_fmt,
403 gst_query_set_position (query, req_fmt, val);
407 case GST_QUERY_DURATION:
409 GstFormat fmt, req_fmt;
412 gst_query_parse_duration (query, &req_fmt, NULL);
413 if ((res = gst_pad_query_peer_duration (enc->sinkpad, &req_fmt, &val))) {
414 gst_query_set_duration (query, req_fmt, val);
418 fmt = GST_FORMAT_TIME;
419 if (!(res = gst_pad_query_peer_duration (enc->sinkpad, &fmt, &dur)))
423 gst_pad_query_peer_convert (enc->sinkpad, fmt, dur, &req_fmt,
425 gst_query_set_duration (query, req_fmt, val);
429 case GST_QUERY_CONVERT:
431 GstFormat src_fmt, dest_fmt;
432 gint64 src_val, dest_val;
434 gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, &dest_val);
435 if (!(res = gst_speex_enc_convert_src (pad, src_fmt, src_val, &dest_fmt,
438 gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val);
442 res = gst_pad_query_default (pad, query);
448 gst_object_unref (enc);
454 gst_speex_enc_sink_query (GstPad * pad, GstQuery * query)
459 enc = GST_SPEEX_ENC (GST_PAD_PARENT (pad));
461 switch (GST_QUERY_TYPE (query)) {
462 case GST_QUERY_CONVERT:
464 GstFormat src_fmt, dest_fmt;
465 gint64 src_val, dest_val;
467 gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, &dest_val);
469 gst_speex_enc_convert_sink (pad, src_fmt, src_val, &dest_fmt,
472 gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val);
476 res = gst_pad_query_default (pad, query);
485 gst_speex_enc_init (GstSpeexEnc * enc, GstSpeexEncClass * klass)
487 enc->sinkpad = gst_pad_new_from_static_template (&sink_factory, "sink");
488 gst_element_add_pad (GST_ELEMENT (enc), enc->sinkpad);
489 gst_pad_set_event_function (enc->sinkpad,
490 GST_DEBUG_FUNCPTR (gst_speex_enc_sinkevent));
491 gst_pad_set_chain_function (enc->sinkpad,
492 GST_DEBUG_FUNCPTR (gst_speex_enc_chain));
493 gst_pad_set_setcaps_function (enc->sinkpad,
494 GST_DEBUG_FUNCPTR (gst_speex_enc_sink_setcaps));
495 gst_pad_set_getcaps_function (enc->sinkpad,
496 GST_DEBUG_FUNCPTR (gst_speex_enc_sink_getcaps));
497 gst_pad_set_query_function (enc->sinkpad,
498 GST_DEBUG_FUNCPTR (gst_speex_enc_sink_query));
500 enc->srcpad = gst_pad_new_from_static_template (&src_factory, "src");
501 gst_pad_set_query_function (enc->srcpad,
502 GST_DEBUG_FUNCPTR (gst_speex_enc_src_query));
503 gst_pad_set_query_type_function (enc->srcpad,
504 GST_DEBUG_FUNCPTR (gst_speex_enc_get_query_types));
505 gst_element_add_pad (GST_ELEMENT (enc), enc->srcpad);
510 enc->quality = DEFAULT_QUALITY;
511 enc->bitrate = DEFAULT_BITRATE;
512 enc->vbr = DEFAULT_VBR;
513 enc->abr = DEFAULT_ABR;
514 enc->vad = DEFAULT_VAD;
515 enc->dtx = DEFAULT_DTX;
516 enc->complexity = DEFAULT_COMPLEXITY;
517 enc->nframes = DEFAULT_NFRAMES;
519 /* FIXME: what about enc->mode? */
522 enc->header_sent = FALSE;
524 enc->adapter = gst_adapter_new ();
528 gst_speex_enc_create_metadata_buffer (GstSpeexEnc * enc)
530 const GstTagList *user_tags;
531 GstTagList *merged_tags;
532 GstBuffer *comments = NULL;
534 user_tags = gst_tag_setter_get_tag_list (GST_TAG_SETTER (enc));
536 GST_DEBUG_OBJECT (enc, "upstream tags = %" GST_PTR_FORMAT, enc->tags);
537 GST_DEBUG_OBJECT (enc, "user-set tags = %" GST_PTR_FORMAT, user_tags);
539 /* gst_tag_list_merge() will handle NULL for either or both lists fine */
540 merged_tags = gst_tag_list_merge (user_tags, enc->tags,
541 gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (enc)));
543 if (merged_tags == NULL)
544 merged_tags = gst_tag_list_new ();
546 GST_DEBUG_OBJECT (enc, "merged tags = %" GST_PTR_FORMAT, merged_tags);
547 comments = gst_tag_list_to_vorbiscomment_buffer (merged_tags, NULL,
548 0, "Encoded with GStreamer Speexenc");
549 gst_tag_list_free (merged_tags);
551 GST_BUFFER_OFFSET (comments) = enc->bytes_out;
552 GST_BUFFER_OFFSET_END (comments) = 0;
558 gst_speex_enc_set_last_msg (GstSpeexEnc * enc, const gchar * msg)
560 g_free (enc->last_message);
561 enc->last_message = g_strdup (msg);
562 GST_WARNING_OBJECT (enc, "%s", msg);
563 g_object_notify (G_OBJECT (enc), "last-message");
567 gst_speex_enc_setup (GstSpeexEnc * enc)
572 case GST_SPEEX_ENC_MODE_UWB:
573 enc->speex_mode = (SpeexMode *) & speex_uwb_mode;
575 case GST_SPEEX_ENC_MODE_WB:
576 enc->speex_mode = (SpeexMode *) & speex_wb_mode;
578 case GST_SPEEX_ENC_MODE_NB:
579 enc->speex_mode = (SpeexMode *) & speex_nb_mode;
581 case GST_SPEEX_ENC_MODE_AUTO:
587 if (enc->rate > 25000) {
588 if (enc->mode == GST_SPEEX_ENC_MODE_AUTO) {
589 enc->speex_mode = (SpeexMode *) & speex_uwb_mode;
591 if (enc->speex_mode != &speex_uwb_mode) {
592 gst_speex_enc_set_last_msg (enc,
593 "Warning: suggest to use ultra wide band mode for this rate");
596 } else if (enc->rate > 12500) {
597 if (enc->mode == GST_SPEEX_ENC_MODE_AUTO) {
598 enc->speex_mode = (SpeexMode *) & speex_wb_mode;
600 if (enc->speex_mode != &speex_wb_mode) {
601 gst_speex_enc_set_last_msg (enc,
602 "Warning: suggest to use wide band mode for this rate");
606 if (enc->mode == GST_SPEEX_ENC_MODE_AUTO) {
607 enc->speex_mode = (SpeexMode *) & speex_nb_mode;
609 if (enc->speex_mode != &speex_nb_mode) {
610 gst_speex_enc_set_last_msg (enc,
611 "Warning: suggest to use narrow band mode for this rate");
616 if (enc->rate != 8000 && enc->rate != 16000 && enc->rate != 32000) {
617 gst_speex_enc_set_last_msg (enc,
618 "Warning: speex is optimized for 8, 16 and 32 KHz");
621 speex_init_header (&enc->header, enc->rate, 1, enc->speex_mode);
622 enc->header.frames_per_packet = enc->nframes;
623 enc->header.vbr = enc->vbr;
624 enc->header.nb_channels = enc->channels;
626 /*Initialize Speex encoder */
627 enc->state = speex_encoder_init (enc->speex_mode);
629 speex_encoder_ctl (enc->state, SPEEX_GET_FRAME_SIZE, &enc->frame_size);
630 speex_encoder_ctl (enc->state, SPEEX_SET_COMPLEXITY, &enc->complexity);
631 speex_encoder_ctl (enc->state, SPEEX_SET_SAMPLING_RATE, &enc->rate);
634 speex_encoder_ctl (enc->state, SPEEX_SET_VBR_QUALITY, &enc->quality);
636 gint tmp = floor (enc->quality);
638 speex_encoder_ctl (enc->state, SPEEX_SET_QUALITY, &tmp);
641 if (enc->quality >= 0.0 && enc->vbr) {
642 gst_speex_enc_set_last_msg (enc,
643 "Warning: bitrate option is overriding quality");
645 speex_encoder_ctl (enc->state, SPEEX_SET_BITRATE, &enc->bitrate);
650 speex_encoder_ctl (enc->state, SPEEX_SET_VBR, &tmp);
651 } else if (enc->vad) {
654 speex_encoder_ctl (enc->state, SPEEX_SET_VAD, &tmp);
660 speex_encoder_ctl (enc->state, SPEEX_SET_DTX, &tmp);
663 if (enc->dtx && !(enc->vbr || enc->abr || enc->vad)) {
664 gst_speex_enc_set_last_msg (enc,
665 "Warning: dtx is useless without vad, vbr or abr");
666 } else if ((enc->vbr || enc->abr) && (enc->vad)) {
667 gst_speex_enc_set_last_msg (enc,
668 "Warning: vad is already implied by vbr or abr");
672 speex_encoder_ctl (enc->state, SPEEX_SET_ABR, &enc->abr);
675 speex_encoder_ctl (enc->state, SPEEX_GET_LOOKAHEAD, &enc->lookahead);
682 /* prepare a buffer for transmission */
684 gst_speex_enc_buffer_from_data (GstSpeexEnc * enc, guchar * data,
685 gint data_len, guint64 granulepos)
689 outbuf = gst_buffer_new_and_alloc (data_len);
690 memcpy (GST_BUFFER_DATA (outbuf), data, data_len);
691 GST_BUFFER_OFFSET (outbuf) = enc->bytes_out;
692 GST_BUFFER_OFFSET_END (outbuf) = granulepos;
694 GST_LOG_OBJECT (enc, "encoded buffer of %d bytes", GST_BUFFER_SIZE (outbuf));
699 /* push out the buffer and do internal bookkeeping */
701 gst_speex_enc_push_buffer (GstSpeexEnc * enc, GstBuffer * buffer)
703 enc->bytes_out += GST_BUFFER_SIZE (buffer);
705 return gst_pad_push (enc->srcpad, buffer);
710 gst_speex_enc_set_header_on_caps (GstCaps * caps, GstBuffer * buf1,
713 GstStructure *structure = NULL;
715 GValue array = { 0 };
716 GValue value = { 0 };
718 caps = gst_caps_make_writable (caps);
719 structure = gst_caps_get_structure (caps, 0);
721 g_assert (gst_buffer_is_metadata_writable (buf1));
722 g_assert (gst_buffer_is_metadata_writable (buf2));
725 GST_BUFFER_FLAG_SET (buf1, GST_BUFFER_FLAG_IN_CAPS);
726 GST_BUFFER_FLAG_SET (buf2, GST_BUFFER_FLAG_IN_CAPS);
728 /* put buffers in a fixed list */
729 g_value_init (&array, GST_TYPE_ARRAY);
730 g_value_init (&value, GST_TYPE_BUFFER);
731 buf = gst_buffer_copy (buf1);
732 gst_value_set_buffer (&value, buf);
733 gst_buffer_unref (buf);
734 gst_value_array_append_value (&array, &value);
735 g_value_unset (&value);
736 g_value_init (&value, GST_TYPE_BUFFER);
737 buf = gst_buffer_copy (buf2);
738 gst_value_set_buffer (&value, buf);
739 gst_buffer_unref (buf);
740 gst_value_array_append_value (&array, &value);
741 gst_structure_set_value (structure, "streamheader", &array);
742 g_value_unset (&value);
743 g_value_unset (&array);
750 gst_speex_enc_sinkevent (GstPad * pad, GstEvent * event)
755 enc = GST_SPEEX_ENC (gst_pad_get_parent (pad));
757 switch (GST_EVENT_TYPE (event)) {
760 res = gst_pad_event_default (pad, event);
766 gst_event_parse_tag (event, &list);
768 gst_tag_list_insert (enc->tags, list,
769 gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (enc)));
771 res = gst_pad_event_default (pad, event);
775 res = gst_pad_event_default (pad, event);
779 gst_object_unref (enc);
786 gst_speex_enc_chain (GstPad * pad, GstBuffer * buf)
789 GstFlowReturn ret = GST_FLOW_OK;
791 enc = GST_SPEEX_ENC (GST_PAD_PARENT (pad));
796 if (!enc->header_sent) {
797 /* Speex streams begin with two headers; the initial header (with
798 most of the codec setup parameters) which is mandated by the Ogg
799 bitstream spec. The second header holds any comment fields.
800 We merely need to make the headers, then pass them to libspeex
801 one at a time; libspeex handles the additional Ogg bitstream
803 GstBuffer *buf1, *buf2;
808 /* create header buffer */
809 data = (guint8 *) speex_header_to_packet (&enc->header, &data_len);
810 buf1 = gst_speex_enc_buffer_from_data (enc, data, data_len, 0);
813 /* create comment buffer */
814 buf2 = gst_speex_enc_create_metadata_buffer (enc);
816 /* mark and put on caps */
817 caps = gst_pad_get_caps (enc->srcpad);
818 caps = gst_speex_enc_set_header_on_caps (caps, buf1, buf2);
820 gst_caps_set_simple (caps,
821 "rate", G_TYPE_INT, enc->rate,
822 "channels", G_TYPE_INT, enc->channels, NULL);
824 /* negotiate with these caps */
825 GST_DEBUG ("here are the caps: %" GST_PTR_FORMAT, caps);
826 gst_pad_set_caps (enc->srcpad, caps);
828 gst_buffer_set_caps (buf1, caps);
829 gst_buffer_set_caps (buf2, caps);
830 gst_caps_unref (caps);
832 /* push out buffers */
833 ret = gst_speex_enc_push_buffer (enc, buf1);
835 if (ret != GST_FLOW_OK) {
836 gst_buffer_unref (buf2);
840 ret = gst_speex_enc_push_buffer (enc, buf2);
842 if (ret != GST_FLOW_OK)
845 speex_bits_reset (&enc->bits);
847 enc->header_sent = TRUE;
851 gint frame_size = enc->frame_size;
852 gint bytes = frame_size * 2 * enc->channels;
854 /* push buffer to adapter */
855 gst_adapter_push (enc->adapter, buf);
858 while (gst_adapter_available (enc->adapter) >= bytes) {
861 gint outsize, written;
864 data = (gint16 *) gst_adapter_peek (enc->adapter, bytes);
866 for (i = 0; i < frame_size * enc->channels; i++) {
867 enc->input[i] = (gfloat) data[i];
869 gst_adapter_flush (enc->adapter, bytes);
871 enc->samples_in += frame_size;
873 if (enc->channels == 2) {
874 speex_encode_stereo (enc->input, frame_size, &enc->bits);
876 speex_encode (enc->state, enc->input, &enc->bits);
880 if ((enc->frameno % enc->nframes) != 0)
883 speex_bits_insert_terminator (&enc->bits);
884 outsize = speex_bits_nbytes (&enc->bits);
886 ret = gst_pad_alloc_buffer_and_set_caps (enc->srcpad,
887 GST_BUFFER_OFFSET_NONE, outsize, GST_PAD_CAPS (enc->srcpad), &outbuf);
889 if ((GST_FLOW_OK != ret))
892 written = speex_bits_write (&enc->bits,
893 (gchar *) GST_BUFFER_DATA (outbuf), outsize);
894 g_assert (written == outsize);
895 speex_bits_reset (&enc->bits);
897 GST_BUFFER_TIMESTAMP (outbuf) =
898 gst_util_uint64_scale_int (enc->frameno * frame_size -
899 enc->lookahead, GST_SECOND, enc->rate);
900 GST_BUFFER_DURATION (outbuf) = gst_util_uint64_scale_int (frame_size,
901 GST_SECOND, enc->rate);
902 /* set gp time and granulepos; see gst-plugins-base/ext/ogg/README */
903 GST_BUFFER_OFFSET_END (outbuf) =
904 ((enc->frameno + 1) * frame_size - enc->lookahead);
905 GST_BUFFER_OFFSET (outbuf) =
906 gst_util_uint64_scale_int (GST_BUFFER_OFFSET_END (outbuf), GST_SECOND,
909 ret = gst_speex_enc_push_buffer (enc, outbuf);
911 if ((GST_FLOW_OK != ret) && (GST_FLOW_NOT_LINKED != ret))
919 gst_buffer_unref (buf);
926 GST_ELEMENT_ERROR (enc, CORE, NEGOTIATION, (NULL),
927 ("encoder not initialized (input is not audio?)"));
928 ret = GST_FLOW_NOT_NEGOTIATED;
936 gst_speex_enc_get_property (GObject * object, guint prop_id, GValue * value,
941 enc = GST_SPEEX_ENC (object);
945 g_value_set_float (value, enc->quality);
948 g_value_set_int (value, enc->bitrate);
951 g_value_set_boolean (value, enc->vbr);
954 g_value_set_int (value, enc->abr);
957 g_value_set_boolean (value, enc->vad);
960 g_value_set_boolean (value, enc->dtx);
963 g_value_set_int (value, enc->complexity);
966 g_value_set_int (value, enc->nframes);
968 case ARG_LAST_MESSAGE:
969 g_value_set_string (value, enc->last_message);
972 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
978 gst_speex_enc_set_property (GObject * object, guint prop_id,
979 const GValue * value, GParamSpec * pspec)
983 enc = GST_SPEEX_ENC (object);
987 enc->quality = g_value_get_float (value);
990 enc->bitrate = g_value_get_int (value);
993 enc->vbr = g_value_get_boolean (value);
996 enc->abr = g_value_get_int (value);
999 enc->vad = g_value_get_boolean (value);
1002 enc->dtx = g_value_get_boolean (value);
1004 case ARG_COMPLEXITY:
1005 enc->complexity = g_value_get_int (value);
1008 enc->nframes = g_value_get_int (value);
1011 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1016 static GstStateChangeReturn
1017 gst_speex_enc_change_state (GstElement * element, GstStateChange transition)
1019 GstSpeexEnc *enc = GST_SPEEX_ENC (element);
1020 GstStateChangeReturn res;
1022 switch (transition) {
1023 case GST_STATE_CHANGE_NULL_TO_READY:
1024 enc->tags = gst_tag_list_new ();
1026 case GST_STATE_CHANGE_READY_TO_PAUSED:
1027 speex_bits_init (&enc->bits);
1029 enc->samples_in = 0;
1031 case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
1037 res = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1038 if (res == GST_STATE_CHANGE_FAILURE)
1041 switch (transition) {
1042 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
1044 case GST_STATE_CHANGE_PAUSED_TO_READY:
1046 enc->header_sent = FALSE;
1048 speex_encoder_destroy (enc->state);
1051 speex_bits_destroy (&enc->bits);
1053 case GST_STATE_CHANGE_READY_TO_NULL:
1054 gst_tag_list_free (enc->tags);