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")
54 static const GstElementDetails speexenc_details =
55 GST_ELEMENT_DETAILS ("Speex audio encoder",
56 "Codec/Encoder/Audio",
57 "Encodes audio in Speex format",
58 "Wim Taymans <wim@fluendo.com>");
60 #define DEFAULT_QUALITY 8.0
61 #define DEFAULT_BITRATE 0
62 #define DEFAULT_VBR FALSE
64 #define DEFAULT_VAD FALSE
65 #define DEFAULT_DTX FALSE
66 #define DEFAULT_COMPLEXITY 3
67 #define DEFAULT_NFRAMES 1
84 static const GstFormat *
85 gst_speex_enc_get_formats (GstPad * pad)
87 static const GstFormat src_formats[] = {
92 static const GstFormat sink_formats[] = {
99 return (GST_PAD_IS_SRC (pad) ? src_formats : sink_formats);
103 static void gst_speex_enc_finalize (GObject * object);
105 static gboolean gst_speex_enc_sinkevent (GstPad * pad, GstEvent * event);
106 static GstFlowReturn gst_speex_enc_chain (GstPad * pad, GstBuffer * buf);
107 static gboolean gst_speex_enc_setup (GstSpeexEnc * enc);
109 static void gst_speex_enc_get_property (GObject * object, guint prop_id,
110 GValue * value, GParamSpec * pspec);
111 static void gst_speex_enc_set_property (GObject * object, guint prop_id,
112 const GValue * value, GParamSpec * pspec);
113 static GstStateChangeReturn gst_speex_enc_change_state (GstElement * element,
114 GstStateChange transition);
117 gst_speex_enc_setup_interfaces (GType speexenc_type)
119 static const GInterfaceInfo tag_setter_info = { NULL, NULL, NULL };
121 g_type_add_interface_static (speexenc_type, GST_TYPE_TAG_SETTER,
124 GST_DEBUG_CATEGORY_INIT (speexenc_debug, "speexenc", 0, "Speex encoder");
127 GST_BOILERPLATE_FULL (GstSpeexEnc, gst_speex_enc, GstElement, GST_TYPE_ELEMENT,
128 gst_speex_enc_setup_interfaces);
131 gst_speex_enc_base_init (gpointer g_class)
133 GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
135 gst_element_class_add_pad_template (element_class,
136 gst_static_pad_template_get (&src_factory));
137 gst_element_class_add_pad_template (element_class,
138 gst_static_pad_template_get (&sink_factory));
139 gst_element_class_set_details (element_class, &speexenc_details);
143 gst_speex_enc_class_init (GstSpeexEncClass * klass)
145 GObjectClass *gobject_class;
146 GstElementClass *gstelement_class;
148 gobject_class = (GObjectClass *) klass;
149 gstelement_class = (GstElementClass *) klass;
151 gobject_class->set_property = gst_speex_enc_set_property;
152 gobject_class->get_property = gst_speex_enc_get_property;
154 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_QUALITY,
155 g_param_spec_float ("quality", "Quality", "Encoding quality",
156 0.0, 10.0, DEFAULT_QUALITY, G_PARAM_READWRITE));
157 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_BITRATE,
158 g_param_spec_int ("bitrate", "Encoding Bit-rate",
159 "Specify an encoding bit-rate (in bps). (0 = automatic)",
160 0, G_MAXINT, DEFAULT_BITRATE, G_PARAM_READWRITE));
161 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_VBR,
162 g_param_spec_boolean ("vbr", "VBR",
163 "Enable variable bit-rate", DEFAULT_VBR, G_PARAM_READWRITE));
164 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_ABR,
165 g_param_spec_int ("abr", "ABR",
166 "Enable average bit-rate (0 = disabled)",
167 0, G_MAXINT, DEFAULT_ABR, G_PARAM_READWRITE));
168 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_VAD,
169 g_param_spec_boolean ("vad", "VAD",
170 "Enable voice activity detection", DEFAULT_VAD, G_PARAM_READWRITE));
171 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_DTX,
172 g_param_spec_boolean ("dtx", "DTX",
173 "Enable discontinuous transmission", DEFAULT_DTX, G_PARAM_READWRITE));
174 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_COMPLEXITY,
175 g_param_spec_int ("complexity", "Complexity",
176 "Set encoding complexity",
177 0, G_MAXINT, DEFAULT_COMPLEXITY, G_PARAM_READWRITE));
178 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_NFRAMES,
179 g_param_spec_int ("nframes", "NFrames",
180 "Number of frames per buffer",
181 0, G_MAXINT, DEFAULT_NFRAMES, G_PARAM_READWRITE));
182 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_LAST_MESSAGE,
183 g_param_spec_string ("last-message", "last-message",
184 "The last status message", NULL, G_PARAM_READABLE));
186 gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_speex_enc_finalize);
188 gstelement_class->change_state =
189 GST_DEBUG_FUNCPTR (gst_speex_enc_change_state);
193 gst_speex_enc_finalize (GObject * object)
197 enc = GST_SPEEX_ENC (object);
199 g_free (enc->last_message);
200 g_object_unref (enc->adapter);
202 G_OBJECT_CLASS (parent_class)->finalize (object);
206 gst_speex_enc_sink_setcaps (GstPad * pad, GstCaps * caps)
209 GstStructure *structure;
211 enc = GST_SPEEX_ENC (GST_PAD_PARENT (pad));
214 structure = gst_caps_get_structure (caps, 0);
215 gst_structure_get_int (structure, "channels", &enc->channels);
216 gst_structure_get_int (structure, "rate", &enc->rate);
218 gst_speex_enc_setup (enc);
224 gst_speex_enc_convert_src (GstPad * pad, GstFormat src_format, gint64 src_value,
225 GstFormat * dest_format, gint64 * dest_value)
231 enc = GST_SPEEX_ENC (GST_PAD_PARENT (pad));
233 if (enc->samples_in == 0 || enc->bytes_out == 0 || enc->rate == 0)
236 avg = (enc->bytes_out * enc->rate) / (enc->samples_in);
238 switch (src_format) {
239 case GST_FORMAT_BYTES:
240 switch (*dest_format) {
241 case GST_FORMAT_TIME:
242 *dest_value = src_value * GST_SECOND / avg;
248 case GST_FORMAT_TIME:
249 switch (*dest_format) {
250 case GST_FORMAT_BYTES:
251 *dest_value = src_value * avg / GST_SECOND;
264 gst_speex_enc_convert_sink (GstPad * pad, GstFormat src_format,
265 gint64 src_value, GstFormat * dest_format, gint64 * dest_value)
269 gint bytes_per_sample;
272 enc = GST_SPEEX_ENC (GST_PAD_PARENT (pad));
274 bytes_per_sample = enc->channels * 2;
276 switch (src_format) {
277 case GST_FORMAT_BYTES:
278 switch (*dest_format) {
279 case GST_FORMAT_DEFAULT:
280 if (bytes_per_sample == 0)
282 *dest_value = src_value / bytes_per_sample;
284 case GST_FORMAT_TIME:
286 gint byterate = bytes_per_sample * enc->rate;
290 *dest_value = src_value * GST_SECOND / byterate;
297 case GST_FORMAT_DEFAULT:
298 switch (*dest_format) {
299 case GST_FORMAT_BYTES:
300 *dest_value = src_value * bytes_per_sample;
302 case GST_FORMAT_TIME:
305 *dest_value = src_value * GST_SECOND / enc->rate;
311 case GST_FORMAT_TIME:
312 switch (*dest_format) {
313 case GST_FORMAT_BYTES:
314 scale = bytes_per_sample;
316 case GST_FORMAT_DEFAULT:
317 *dest_value = src_value * scale * enc->rate / GST_SECOND;
329 static const GstQueryType *
330 gst_speex_enc_get_query_types (GstPad * pad)
332 static const GstQueryType gst_speex_enc_src_query_types[] = {
339 return gst_speex_enc_src_query_types;
343 gst_speex_enc_src_query (GstPad * pad, GstQuery * query)
348 enc = GST_SPEEX_ENC (gst_pad_get_parent (pad));
350 switch (GST_QUERY_TYPE (query)) {
351 case GST_QUERY_POSITION:
353 GstFormat fmt, req_fmt;
356 gst_query_parse_position (query, &req_fmt, NULL);
357 if ((res = gst_pad_query_peer_position (enc->sinkpad, &req_fmt, &val))) {
358 gst_query_set_position (query, req_fmt, val);
362 fmt = GST_FORMAT_TIME;
363 if (!(res = gst_pad_query_peer_position (enc->sinkpad, &fmt, &pos)))
367 gst_pad_query_peer_convert (enc->sinkpad, fmt, pos, &req_fmt,
369 gst_query_set_position (query, req_fmt, val);
373 case GST_QUERY_DURATION:
375 GstFormat fmt, req_fmt;
378 gst_query_parse_duration (query, &req_fmt, NULL);
379 if ((res = gst_pad_query_peer_duration (enc->sinkpad, &req_fmt, &val))) {
380 gst_query_set_duration (query, req_fmt, val);
384 fmt = GST_FORMAT_TIME;
385 if (!(res = gst_pad_query_peer_duration (enc->sinkpad, &fmt, &dur)))
389 gst_pad_query_peer_convert (enc->sinkpad, fmt, dur, &req_fmt,
391 gst_query_set_duration (query, req_fmt, val);
395 case GST_QUERY_CONVERT:
397 GstFormat src_fmt, dest_fmt;
398 gint64 src_val, dest_val;
400 gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, &dest_val);
401 if (!(res = gst_speex_enc_convert_src (pad, src_fmt, src_val, &dest_fmt,
404 gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val);
408 res = gst_pad_query_default (pad, query);
414 gst_object_unref (enc);
420 gst_speex_enc_sink_query (GstPad * pad, GstQuery * query)
425 enc = GST_SPEEX_ENC (GST_PAD_PARENT (pad));
427 switch (GST_QUERY_TYPE (query)) {
428 case GST_QUERY_CONVERT:
430 GstFormat src_fmt, dest_fmt;
431 gint64 src_val, dest_val;
433 gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, &dest_val);
435 gst_speex_enc_convert_sink (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);
451 gst_speex_enc_init (GstSpeexEnc * enc, GstSpeexEncClass * klass)
453 enc->sinkpad = gst_pad_new_from_static_template (&sink_factory, "sink");
454 gst_element_add_pad (GST_ELEMENT (enc), enc->sinkpad);
455 gst_pad_set_event_function (enc->sinkpad,
456 GST_DEBUG_FUNCPTR (gst_speex_enc_sinkevent));
457 gst_pad_set_chain_function (enc->sinkpad,
458 GST_DEBUG_FUNCPTR (gst_speex_enc_chain));
459 gst_pad_set_setcaps_function (enc->sinkpad,
460 GST_DEBUG_FUNCPTR (gst_speex_enc_sink_setcaps));
461 gst_pad_set_query_function (enc->sinkpad,
462 GST_DEBUG_FUNCPTR (gst_speex_enc_sink_query));
464 enc->srcpad = gst_pad_new_from_static_template (&src_factory, "src");
465 gst_pad_set_query_function (enc->srcpad,
466 GST_DEBUG_FUNCPTR (gst_speex_enc_src_query));
467 gst_pad_set_query_type_function (enc->srcpad,
468 GST_DEBUG_FUNCPTR (gst_speex_enc_get_query_types));
469 gst_element_add_pad (GST_ELEMENT (enc), enc->srcpad);
474 enc->quality = DEFAULT_QUALITY;
475 enc->bitrate = DEFAULT_BITRATE;
476 enc->vbr = DEFAULT_VBR;
477 enc->abr = DEFAULT_ABR;
478 enc->vad = DEFAULT_VAD;
479 enc->dtx = DEFAULT_DTX;
480 enc->complexity = DEFAULT_COMPLEXITY;
481 enc->nframes = DEFAULT_NFRAMES;
483 /* FIXME: what about enc->mode? */
486 enc->header_sent = FALSE;
488 enc->adapter = gst_adapter_new ();
492 gst_speex_enc_create_metadata_buffer (GstSpeexEnc * enc)
494 const GstTagList *user_tags;
495 GstTagList *merged_tags;
496 GstBuffer *comments = NULL;
498 user_tags = gst_tag_setter_get_tag_list (GST_TAG_SETTER (enc));
500 GST_DEBUG_OBJECT (enc, "upstream tags = %" GST_PTR_FORMAT, enc->tags);
501 GST_DEBUG_OBJECT (enc, "user-set tags = %" GST_PTR_FORMAT, user_tags);
503 /* gst_tag_list_merge() will handle NULL for either or both lists fine */
504 merged_tags = gst_tag_list_merge (user_tags, enc->tags,
505 gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (enc)));
507 if (merged_tags == NULL)
508 merged_tags = gst_tag_list_new ();
510 GST_DEBUG_OBJECT (enc, "merged tags = %" GST_PTR_FORMAT, merged_tags);
511 comments = gst_tag_list_to_vorbiscomment_buffer (merged_tags, NULL,
512 0, "Encoded with GStreamer Speexenc");
513 gst_tag_list_free (merged_tags);
515 GST_BUFFER_OFFSET (comments) = enc->bytes_out;
516 GST_BUFFER_OFFSET_END (comments) = 0;
522 gst_speex_enc_set_last_msg (GstSpeexEnc * enc, const gchar * msg)
524 g_free (enc->last_message);
525 enc->last_message = g_strdup (msg);
526 GST_WARNING_OBJECT (enc, "%s", msg);
527 g_object_notify (G_OBJECT (enc), "last-message");
531 gst_speex_enc_setup (GstSpeexEnc * enc)
536 case GST_SPEEX_ENC_MODE_UWB:
537 enc->speex_mode = (SpeexMode *) & speex_uwb_mode;
539 case GST_SPEEX_ENC_MODE_WB:
540 enc->speex_mode = (SpeexMode *) & speex_wb_mode;
542 case GST_SPEEX_ENC_MODE_NB:
543 enc->speex_mode = (SpeexMode *) & speex_nb_mode;
545 case GST_SPEEX_ENC_MODE_AUTO:
551 if (enc->rate > 25000) {
552 if (enc->mode == GST_SPEEX_ENC_MODE_AUTO) {
553 enc->speex_mode = (SpeexMode *) & speex_uwb_mode;
555 if (enc->speex_mode != &speex_uwb_mode) {
556 gst_speex_enc_set_last_msg (enc,
557 "Warning: suggest to use ultra wide band mode for this rate");
560 } else if (enc->rate > 12500) {
561 if (enc->mode == GST_SPEEX_ENC_MODE_AUTO) {
562 enc->speex_mode = (SpeexMode *) & speex_wb_mode;
564 if (enc->speex_mode != &speex_wb_mode) {
565 gst_speex_enc_set_last_msg (enc,
566 "Warning: suggest to use wide band mode for this rate");
570 if (enc->mode == GST_SPEEX_ENC_MODE_AUTO) {
571 enc->speex_mode = (SpeexMode *) & speex_nb_mode;
573 if (enc->speex_mode != &speex_nb_mode) {
574 gst_speex_enc_set_last_msg (enc,
575 "Warning: suggest to use narrow band mode for this rate");
580 if (enc->rate != 8000 && enc->rate != 16000 && enc->rate != 32000) {
581 gst_speex_enc_set_last_msg (enc,
582 "Warning: speex is optimized for 8, 16 and 32 KHz");
585 speex_init_header (&enc->header, enc->rate, 1, enc->speex_mode);
586 enc->header.frames_per_packet = enc->nframes;
587 enc->header.vbr = enc->vbr;
588 enc->header.nb_channels = enc->channels;
590 /*Initialize Speex encoder */
591 enc->state = speex_encoder_init (enc->speex_mode);
593 speex_encoder_ctl (enc->state, SPEEX_GET_FRAME_SIZE, &enc->frame_size);
594 speex_encoder_ctl (enc->state, SPEEX_SET_COMPLEXITY, &enc->complexity);
595 speex_encoder_ctl (enc->state, SPEEX_SET_SAMPLING_RATE, &enc->rate);
598 speex_encoder_ctl (enc->state, SPEEX_SET_VBR_QUALITY, &enc->quality);
600 gint tmp = floor (enc->quality);
602 speex_encoder_ctl (enc->state, SPEEX_SET_QUALITY, &tmp);
605 if (enc->quality >= 0.0 && enc->vbr) {
606 gst_speex_enc_set_last_msg (enc,
607 "Warning: bitrate option is overriding quality");
609 speex_encoder_ctl (enc->state, SPEEX_SET_BITRATE, &enc->bitrate);
614 speex_encoder_ctl (enc->state, SPEEX_SET_VBR, &tmp);
615 } else if (enc->vad) {
618 speex_encoder_ctl (enc->state, SPEEX_SET_VAD, &tmp);
624 speex_encoder_ctl (enc->state, SPEEX_SET_DTX, &tmp);
627 if (enc->dtx && !(enc->vbr || enc->abr || enc->vad)) {
628 gst_speex_enc_set_last_msg (enc,
629 "Warning: dtx is useless without vad, vbr or abr");
630 } else if ((enc->vbr || enc->abr) && (enc->vad)) {
631 gst_speex_enc_set_last_msg (enc,
632 "Warning: vad is already implied by vbr or abr");
636 speex_encoder_ctl (enc->state, SPEEX_SET_ABR, &enc->abr);
639 speex_encoder_ctl (enc->state, SPEEX_GET_LOOKAHEAD, &enc->lookahead);
646 /* prepare a buffer for transmission */
648 gst_speex_enc_buffer_from_data (GstSpeexEnc * enc, guchar * data,
649 gint data_len, guint64 granulepos)
653 outbuf = gst_buffer_new_and_alloc (data_len);
654 memcpy (GST_BUFFER_DATA (outbuf), data, data_len);
655 GST_BUFFER_OFFSET (outbuf) = enc->bytes_out;
656 GST_BUFFER_OFFSET_END (outbuf) = granulepos;
658 GST_LOG_OBJECT (enc, "encoded buffer of %d bytes", GST_BUFFER_SIZE (outbuf));
663 /* push out the buffer and do internal bookkeeping */
665 gst_speex_enc_push_buffer (GstSpeexEnc * enc, GstBuffer * buffer)
667 enc->bytes_out += GST_BUFFER_SIZE (buffer);
669 return gst_pad_push (enc->srcpad, buffer);
674 gst_speex_enc_set_header_on_caps (GstCaps * caps, GstBuffer * buf1,
677 GstStructure *structure = NULL;
679 GValue array = { 0 };
680 GValue value = { 0 };
682 caps = gst_caps_make_writable (caps);
683 structure = gst_caps_get_structure (caps, 0);
685 g_assert (gst_buffer_is_metadata_writable (buf1));
686 g_assert (gst_buffer_is_metadata_writable (buf2));
689 GST_BUFFER_FLAG_SET (buf1, GST_BUFFER_FLAG_IN_CAPS);
690 GST_BUFFER_FLAG_SET (buf2, GST_BUFFER_FLAG_IN_CAPS);
692 /* put buffers in a fixed list */
693 g_value_init (&array, GST_TYPE_ARRAY);
694 g_value_init (&value, GST_TYPE_BUFFER);
695 buf = gst_buffer_copy (buf1);
696 gst_value_set_buffer (&value, buf);
697 gst_buffer_unref (buf);
698 gst_value_array_append_value (&array, &value);
699 g_value_unset (&value);
700 g_value_init (&value, GST_TYPE_BUFFER);
701 buf = gst_buffer_copy (buf2);
702 gst_value_set_buffer (&value, buf);
703 gst_buffer_unref (buf);
704 gst_value_array_append_value (&array, &value);
705 gst_structure_set_value (structure, "streamheader", &array);
706 g_value_unset (&value);
707 g_value_unset (&array);
714 gst_speex_enc_sinkevent (GstPad * pad, GstEvent * event)
719 enc = GST_SPEEX_ENC (gst_pad_get_parent (pad));
721 switch (GST_EVENT_TYPE (event)) {
724 res = gst_pad_event_default (pad, event);
730 gst_event_parse_tag (event, &list);
732 gst_tag_list_insert (enc->tags, list,
733 gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (enc)));
735 res = gst_pad_event_default (pad, event);
739 res = gst_pad_event_default (pad, event);
743 gst_object_unref (enc);
750 gst_speex_enc_chain (GstPad * pad, GstBuffer * buf)
753 GstFlowReturn ret = GST_FLOW_OK;
755 enc = GST_SPEEX_ENC (GST_PAD_PARENT (pad));
760 if (!enc->header_sent) {
761 /* Speex streams begin with two headers; the initial header (with
762 most of the codec setup parameters) which is mandated by the Ogg
763 bitstream spec. The second header holds any comment fields.
764 We merely need to make the headers, then pass them to libspeex
765 one at a time; libspeex handles the additional Ogg bitstream
767 GstBuffer *buf1, *buf2;
772 /* create header buffer */
773 data = (guint8 *) speex_header_to_packet (&enc->header, &data_len);
774 buf1 = gst_speex_enc_buffer_from_data (enc, data, data_len, 0);
777 /* create comment buffer */
778 buf2 = gst_speex_enc_create_metadata_buffer (enc);
780 /* mark and put on caps */
781 caps = gst_pad_get_caps (enc->srcpad);
782 caps = gst_speex_enc_set_header_on_caps (caps, buf1, buf2);
784 /* negotiate with these caps */
785 GST_DEBUG ("here are the caps: %" GST_PTR_FORMAT, caps);
786 gst_pad_set_caps (enc->srcpad, caps);
788 gst_buffer_set_caps (buf1, caps);
789 gst_buffer_set_caps (buf2, caps);
790 gst_caps_unref (caps);
792 /* push out buffers */
793 ret = gst_speex_enc_push_buffer (enc, buf1);
795 if (ret != GST_FLOW_OK) {
796 gst_buffer_unref (buf2);
800 ret = gst_speex_enc_push_buffer (enc, buf2);
802 if (ret != GST_FLOW_OK)
805 speex_bits_reset (&enc->bits);
807 enc->header_sent = TRUE;
811 gint frame_size = enc->frame_size;
812 gint bytes = frame_size * 2 * enc->channels;
814 /* push buffer to adapter */
815 gst_adapter_push (enc->adapter, buf);
818 while (gst_adapter_available (enc->adapter) >= bytes) {
821 gint outsize, written;
824 data = (gint16 *) gst_adapter_peek (enc->adapter, bytes);
826 for (i = 0; i < frame_size * enc->channels; i++) {
827 enc->input[i] = (gfloat) data[i];
829 gst_adapter_flush (enc->adapter, bytes);
831 enc->samples_in += frame_size;
833 if (enc->channels == 2) {
834 speex_encode_stereo (enc->input, frame_size, &enc->bits);
836 speex_encode (enc->state, enc->input, &enc->bits);
840 if ((enc->frameno % enc->nframes) != 0)
843 speex_bits_insert_terminator (&enc->bits);
844 outsize = speex_bits_nbytes (&enc->bits);
846 ret = gst_pad_alloc_buffer_and_set_caps (enc->srcpad,
847 GST_BUFFER_OFFSET_NONE, outsize, GST_PAD_CAPS (enc->srcpad), &outbuf);
849 if ((GST_FLOW_OK != ret))
852 written = speex_bits_write (&enc->bits,
853 (gchar *) GST_BUFFER_DATA (outbuf), outsize);
854 g_assert (written == outsize);
855 speex_bits_reset (&enc->bits);
857 GST_BUFFER_TIMESTAMP (outbuf) =
858 gst_util_uint64_scale_int (enc->frameno * frame_size -
859 enc->lookahead, GST_SECOND, enc->rate);
860 GST_BUFFER_DURATION (outbuf) = gst_util_uint64_scale_int (frame_size,
861 GST_SECOND, enc->rate);
862 /* set gp time and granulepos; see gst-plugins-base/ext/ogg/README */
863 GST_BUFFER_OFFSET_END (outbuf) =
864 ((enc->frameno + 1) * frame_size - enc->lookahead);
865 GST_BUFFER_OFFSET (outbuf) =
866 gst_util_uint64_scale_int (GST_BUFFER_OFFSET_END (outbuf), GST_SECOND,
869 ret = gst_speex_enc_push_buffer (enc, outbuf);
871 if ((GST_FLOW_OK != ret) && (GST_FLOW_NOT_LINKED != ret))
879 gst_buffer_unref (buf);
886 GST_ELEMENT_ERROR (enc, CORE, NEGOTIATION, (NULL),
887 ("encoder not initialized (input is not audio?)"));
888 ret = GST_FLOW_NOT_NEGOTIATED;
896 gst_speex_enc_get_property (GObject * object, guint prop_id, GValue * value,
901 enc = GST_SPEEX_ENC (object);
905 g_value_set_float (value, enc->quality);
908 g_value_set_int (value, enc->bitrate);
911 g_value_set_boolean (value, enc->vbr);
914 g_value_set_int (value, enc->abr);
917 g_value_set_boolean (value, enc->vad);
920 g_value_set_boolean (value, enc->dtx);
923 g_value_set_int (value, enc->complexity);
926 g_value_set_int (value, enc->nframes);
928 case ARG_LAST_MESSAGE:
929 g_value_set_string (value, enc->last_message);
932 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
938 gst_speex_enc_set_property (GObject * object, guint prop_id,
939 const GValue * value, GParamSpec * pspec)
943 enc = GST_SPEEX_ENC (object);
947 enc->quality = g_value_get_float (value);
950 enc->bitrate = g_value_get_int (value);
953 enc->vbr = g_value_get_boolean (value);
956 enc->abr = g_value_get_int (value);
959 enc->vad = g_value_get_boolean (value);
962 enc->dtx = g_value_get_boolean (value);
965 enc->complexity = g_value_get_int (value);
968 enc->nframes = g_value_get_int (value);
971 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
976 static GstStateChangeReturn
977 gst_speex_enc_change_state (GstElement * element, GstStateChange transition)
979 GstSpeexEnc *enc = GST_SPEEX_ENC (element);
980 GstStateChangeReturn res;
982 switch (transition) {
983 case GST_STATE_CHANGE_NULL_TO_READY:
984 enc->tags = gst_tag_list_new ();
986 case GST_STATE_CHANGE_READY_TO_PAUSED:
987 speex_bits_init (&enc->bits);
991 case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
997 res = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
998 if (res == GST_STATE_CHANGE_FAILURE)
1001 switch (transition) {
1002 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
1004 case GST_STATE_CHANGE_PAUSED_TO_READY:
1006 enc->header_sent = FALSE;
1008 speex_encoder_destroy (enc->state);
1011 speex_bits_destroy (&enc->bits);
1013 case GST_STATE_CHANGE_READY_TO_NULL:
1014 gst_tag_list_free (enc->tags);