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_speexenc_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_speexenc_base_init (gpointer g_class);
104 static void gst_speexenc_class_init (GstSpeexEncClass * klass);
105 static void gst_speexenc_init (GstSpeexEnc * speexenc);
106 static void gst_speexenc_finalize (GObject * object);
108 static gboolean gst_speexenc_sinkevent (GstPad * pad, GstEvent * event);
109 static GstFlowReturn gst_speexenc_chain (GstPad * pad, GstBuffer * buf);
110 static gboolean gst_speexenc_setup (GstSpeexEnc * speexenc);
112 static void gst_speexenc_get_property (GObject * object, guint prop_id,
113 GValue * value, GParamSpec * pspec);
114 static void gst_speexenc_set_property (GObject * object, guint prop_id,
115 const GValue * value, GParamSpec * pspec);
116 static GstStateChangeReturn gst_speexenc_change_state (GstElement * element,
117 GstStateChange transition);
119 static GstElementClass *parent_class = NULL;
122 gst_speexenc_get_type (void)
124 static GType speexenc_type = 0;
126 if (!speexenc_type) {
127 static const GTypeInfo speexenc_info = {
128 sizeof (GstSpeexEncClass),
129 gst_speexenc_base_init,
131 (GClassInitFunc) gst_speexenc_class_init,
134 sizeof (GstSpeexEnc),
136 (GInstanceInitFunc) gst_speexenc_init,
138 static const GInterfaceInfo tag_setter_info = {
145 g_type_register_static (GST_TYPE_ELEMENT, "GstSpeexEnc", &speexenc_info,
148 g_type_add_interface_static (speexenc_type, GST_TYPE_TAG_SETTER,
151 GST_DEBUG_CATEGORY_INIT (speexenc_debug, "speexenc", 0, "Speex encoder");
153 return speexenc_type;
157 gst_speexenc_base_init (gpointer g_class)
159 GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
161 gst_element_class_add_pad_template (element_class,
162 gst_static_pad_template_get (&src_factory));
163 gst_element_class_add_pad_template (element_class,
164 gst_static_pad_template_get (&sink_factory));
165 gst_element_class_set_details (element_class, &speexenc_details);
169 gst_speexenc_class_init (GstSpeexEncClass * klass)
171 GObjectClass *gobject_class;
172 GstElementClass *gstelement_class;
174 gobject_class = (GObjectClass *) klass;
175 gstelement_class = (GstElementClass *) klass;
177 gobject_class->set_property = gst_speexenc_set_property;
178 gobject_class->get_property = gst_speexenc_get_property;
180 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_QUALITY,
181 g_param_spec_float ("quality", "Quality", "Encoding quality",
182 0.0, 10.0, DEFAULT_QUALITY, G_PARAM_READWRITE));
183 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_BITRATE,
184 g_param_spec_int ("bitrate", "Encoding Bit-rate",
185 "Specify an encoding bit-rate (in bps). (0 = automatic)",
186 0, G_MAXINT, DEFAULT_BITRATE, G_PARAM_READWRITE));
187 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_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), ARG_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), ARG_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), ARG_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), ARG_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), ARG_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), ARG_LAST_MESSAGE,
209 g_param_spec_string ("last-message", "last-message",
210 "The last status message", NULL, G_PARAM_READABLE));
212 parent_class = g_type_class_peek_parent (klass);
214 gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_speexenc_finalize);
216 gstelement_class->change_state =
217 GST_DEBUG_FUNCPTR (gst_speexenc_change_state);
221 gst_speexenc_finalize (GObject * object)
223 GstSpeexEnc *speexenc;
225 speexenc = GST_SPEEXENC (object);
227 g_free (speexenc->last_message);
228 g_object_unref (speexenc->adapter);
230 G_OBJECT_CLASS (parent_class)->finalize (object);
234 gst_speexenc_sink_setcaps (GstPad * pad, GstCaps * caps)
236 GstSpeexEnc *speexenc;
237 GstStructure *structure;
239 speexenc = GST_SPEEXENC (gst_pad_get_parent (pad));
240 speexenc->setup = FALSE;
242 structure = gst_caps_get_structure (caps, 0);
243 gst_structure_get_int (structure, "channels", &speexenc->channels);
244 gst_structure_get_int (structure, "rate", &speexenc->rate);
246 gst_speexenc_setup (speexenc);
248 gst_object_unref (speexenc);
250 return speexenc->setup;
254 gst_speexenc_convert_src (GstPad * pad, GstFormat src_format, gint64 src_value,
255 GstFormat * dest_format, gint64 * dest_value)
258 GstSpeexEnc *speexenc;
261 speexenc = GST_SPEEXENC (GST_PAD_PARENT (pad));
263 if (speexenc->samples_in == 0 ||
264 speexenc->bytes_out == 0 || speexenc->rate == 0)
267 avg = (speexenc->bytes_out * speexenc->rate) / (speexenc->samples_in);
269 switch (src_format) {
270 case GST_FORMAT_BYTES:
271 switch (*dest_format) {
272 case GST_FORMAT_TIME:
273 *dest_value = src_value * GST_SECOND / avg;
279 case GST_FORMAT_TIME:
280 switch (*dest_format) {
281 case GST_FORMAT_BYTES:
282 *dest_value = src_value * avg / GST_SECOND;
295 gst_speexenc_convert_sink (GstPad * pad, GstFormat src_format,
296 gint64 src_value, GstFormat * dest_format, gint64 * dest_value)
300 gint bytes_per_sample;
301 GstSpeexEnc *speexenc;
303 speexenc = GST_SPEEXENC (GST_PAD_PARENT (pad));
305 bytes_per_sample = speexenc->channels * 2;
307 switch (src_format) {
308 case GST_FORMAT_BYTES:
309 switch (*dest_format) {
310 case GST_FORMAT_DEFAULT:
311 if (bytes_per_sample == 0)
313 *dest_value = src_value / bytes_per_sample;
315 case GST_FORMAT_TIME:
317 gint byterate = bytes_per_sample * speexenc->rate;
321 *dest_value = src_value * GST_SECOND / byterate;
328 case GST_FORMAT_DEFAULT:
329 switch (*dest_format) {
330 case GST_FORMAT_BYTES:
331 *dest_value = src_value * bytes_per_sample;
333 case GST_FORMAT_TIME:
334 if (speexenc->rate == 0)
336 *dest_value = src_value * GST_SECOND / speexenc->rate;
342 case GST_FORMAT_TIME:
343 switch (*dest_format) {
344 case GST_FORMAT_BYTES:
345 scale = bytes_per_sample;
347 case GST_FORMAT_DEFAULT:
348 *dest_value = src_value * scale * speexenc->rate / GST_SECOND;
360 static const GstQueryType *
361 gst_speexenc_get_query_types (GstPad * pad)
363 static const GstQueryType gst_speexenc_src_query_types[] = {
370 return gst_speexenc_src_query_types;
374 gst_speexenc_src_query (GstPad * pad, GstQuery * query)
377 GstSpeexEnc *speexenc;
380 speexenc = GST_SPEEXENC (gst_pad_get_parent (pad));
381 peerpad = gst_pad_get_peer (GST_PAD (speexenc->sinkpad));
383 switch (GST_QUERY_TYPE (query)) {
384 case GST_QUERY_POSITION:
386 GstFormat fmt, req_fmt;
389 gst_query_parse_position (query, &req_fmt, NULL);
390 if ((res = gst_pad_query_position (peerpad, &req_fmt, &val))) {
391 gst_query_set_position (query, req_fmt, val);
395 fmt = GST_FORMAT_TIME;
396 if (!(res = gst_pad_query_position (peerpad, &fmt, &pos)))
399 if ((res = gst_pad_query_convert (peerpad, fmt, pos, &req_fmt, &val)))
400 gst_query_set_position (query, req_fmt, val);
404 case GST_QUERY_DURATION:
406 GstFormat fmt, req_fmt;
409 gst_query_parse_duration (query, &req_fmt, NULL);
410 if ((res = gst_pad_query_duration (peerpad, &req_fmt, &val))) {
411 gst_query_set_duration (query, req_fmt, val);
415 fmt = GST_FORMAT_TIME;
416 if (!(res = gst_pad_query_duration (peerpad, &fmt, &dur)))
419 if ((res = gst_pad_query_convert (peerpad, fmt, dur, &req_fmt, &val))) {
420 gst_query_set_duration (query, req_fmt, val);
424 case GST_QUERY_CONVERT:
426 GstFormat src_fmt, dest_fmt;
427 gint64 src_val, dest_val;
429 gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, &dest_val);
430 if (!(res = gst_speexenc_convert_src (pad, src_fmt, src_val, &dest_fmt,
433 gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val);
437 res = gst_pad_query_default (pad, query);
442 gst_object_unref (peerpad);
443 gst_object_unref (speexenc);
448 gst_speexenc_sink_query (GstPad * pad, GstQuery * query)
451 GstSpeexEnc *speexenc;
453 speexenc = GST_SPEEXENC (GST_PAD_PARENT (pad));
455 switch (GST_QUERY_TYPE (query)) {
456 case GST_QUERY_CONVERT:
458 GstFormat src_fmt, dest_fmt;
459 gint64 src_val, dest_val;
461 gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, &dest_val);
463 gst_speexenc_convert_sink (pad, src_fmt, src_val, &dest_fmt,
466 gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val);
470 res = gst_pad_query_default (pad, query);
479 gst_speexenc_init (GstSpeexEnc * speexenc)
481 speexenc->sinkpad = gst_pad_new_from_static_template (&sink_factory, "sink");
482 gst_element_add_pad (GST_ELEMENT (speexenc), speexenc->sinkpad);
483 gst_pad_set_event_function (speexenc->sinkpad,
484 GST_DEBUG_FUNCPTR (gst_speexenc_sinkevent));
485 gst_pad_set_chain_function (speexenc->sinkpad,
486 GST_DEBUG_FUNCPTR (gst_speexenc_chain));
487 gst_pad_set_setcaps_function (speexenc->sinkpad,
488 GST_DEBUG_FUNCPTR (gst_speexenc_sink_setcaps));
489 gst_pad_set_query_function (speexenc->sinkpad,
490 GST_DEBUG_FUNCPTR (gst_speexenc_sink_query));
492 speexenc->srcpad = gst_pad_new_from_static_template (&src_factory, "src");
493 gst_pad_set_query_function (speexenc->srcpad,
494 GST_DEBUG_FUNCPTR (gst_speexenc_src_query));
495 gst_pad_set_query_type_function (speexenc->srcpad,
496 GST_DEBUG_FUNCPTR (gst_speexenc_get_query_types));
497 gst_element_add_pad (GST_ELEMENT (speexenc), speexenc->srcpad);
499 speexenc->channels = -1;
502 speexenc->quality = DEFAULT_QUALITY;
503 speexenc->bitrate = DEFAULT_BITRATE;
504 speexenc->vbr = DEFAULT_VBR;
505 speexenc->abr = DEFAULT_ABR;
506 speexenc->vad = DEFAULT_VAD;
507 speexenc->dtx = DEFAULT_DTX;
508 speexenc->complexity = DEFAULT_COMPLEXITY;
509 speexenc->nframes = DEFAULT_NFRAMES;
511 speexenc->setup = FALSE;
512 speexenc->header_sent = FALSE;
514 speexenc->adapter = gst_adapter_new ();
518 gst_speexenc_create_metadata_buffer (GstSpeexEnc * enc)
520 const GstTagList *user_tags;
521 GstTagList *merged_tags;
522 GstBuffer *comments = NULL;
524 user_tags = gst_tag_setter_get_tag_list (GST_TAG_SETTER (enc));
526 GST_DEBUG_OBJECT (enc, "upstream tags = %" GST_PTR_FORMAT, enc->tags);
527 GST_DEBUG_OBJECT (enc, "user-set tags = %" GST_PTR_FORMAT, user_tags);
529 /* gst_tag_list_merge() will handle NULL for either or both lists fine */
530 merged_tags = gst_tag_list_merge (user_tags, enc->tags,
531 gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (enc)));
533 if (merged_tags == NULL)
534 merged_tags = gst_tag_list_new ();
536 GST_DEBUG_OBJECT (enc, "merged tags = %" GST_PTR_FORMAT, merged_tags);
537 comments = gst_tag_list_to_vorbiscomment_buffer (merged_tags, NULL,
538 0, "Encoded with GStreamer Speexenc");
539 gst_tag_list_free (merged_tags);
541 GST_BUFFER_OFFSET (comments) = enc->bytes_out;
542 GST_BUFFER_OFFSET_END (comments) = 0;
548 gst_speexenc_set_last_msg (GstSpeexEnc * enc, const gchar * msg)
550 g_free (enc->last_message);
551 enc->last_message = g_strdup (msg);
552 GST_WARNING_OBJECT (enc, "%s", msg);
553 g_object_notify (G_OBJECT (enc), "last-message");
557 gst_speexenc_setup (GstSpeexEnc * speexenc)
559 speexenc->setup = FALSE;
561 switch (speexenc->mode) {
562 case GST_SPEEXENC_MODE_UWB:
563 speexenc->speex_mode = (SpeexMode *) & speex_uwb_mode;
565 case GST_SPEEXENC_MODE_WB:
566 speexenc->speex_mode = (SpeexMode *) & speex_wb_mode;
568 case GST_SPEEXENC_MODE_NB:
569 speexenc->speex_mode = (SpeexMode *) & speex_nb_mode;
571 case GST_SPEEXENC_MODE_AUTO:
577 if (speexenc->rate > 25000) {
578 if (speexenc->mode == GST_SPEEXENC_MODE_AUTO) {
579 speexenc->speex_mode = (SpeexMode *) & speex_uwb_mode;
581 if (speexenc->speex_mode != &speex_uwb_mode) {
582 gst_speexenc_set_last_msg (speexenc,
583 "Warning: suggest to use ultra wide band mode for this rate");
586 } else if (speexenc->rate > 12500) {
587 if (speexenc->mode == GST_SPEEXENC_MODE_AUTO) {
588 speexenc->speex_mode = (SpeexMode *) & speex_wb_mode;
590 if (speexenc->speex_mode != &speex_wb_mode) {
591 gst_speexenc_set_last_msg (speexenc,
592 "Warning: suggest to use wide band mode for this rate");
596 if (speexenc->mode == GST_SPEEXENC_MODE_AUTO) {
597 speexenc->speex_mode = (SpeexMode *) & speex_nb_mode;
599 if (speexenc->speex_mode != &speex_nb_mode) {
600 gst_speexenc_set_last_msg (speexenc,
601 "Warning: suggest to use narrow band mode for this rate");
606 if (speexenc->rate != 8000 && speexenc->rate != 16000
607 && speexenc->rate != 32000) {
608 gst_speexenc_set_last_msg (speexenc,
609 "Warning: speex is optimized for 8, 16 and 32 KHz");
612 speex_init_header (&speexenc->header, speexenc->rate, 1,
613 speexenc->speex_mode);
614 speexenc->header.frames_per_packet = speexenc->nframes;
615 speexenc->header.vbr = speexenc->vbr;
616 speexenc->header.nb_channels = speexenc->channels;
618 /*Initialize Speex encoder */
619 speexenc->state = speex_encoder_init (speexenc->speex_mode);
621 speex_encoder_ctl (speexenc->state, SPEEX_GET_FRAME_SIZE,
622 &speexenc->frame_size);
623 speex_encoder_ctl (speexenc->state, SPEEX_SET_COMPLEXITY,
624 &speexenc->complexity);
625 speex_encoder_ctl (speexenc->state, SPEEX_SET_SAMPLING_RATE, &speexenc->rate);
628 speex_encoder_ctl (speexenc->state, SPEEX_SET_VBR_QUALITY,
631 gint tmp = floor (speexenc->quality);
633 speex_encoder_ctl (speexenc->state, SPEEX_SET_QUALITY, &tmp);
635 if (speexenc->bitrate) {
636 if (speexenc->quality >= 0.0 && speexenc->vbr) {
637 gst_speexenc_set_last_msg (speexenc,
638 "Warning: bitrate option is overriding quality");
640 speex_encoder_ctl (speexenc->state, SPEEX_SET_BITRATE, &speexenc->bitrate);
645 speex_encoder_ctl (speexenc->state, SPEEX_SET_VBR, &tmp);
646 } else if (speexenc->vad) {
649 speex_encoder_ctl (speexenc->state, SPEEX_SET_VAD, &tmp);
655 speex_encoder_ctl (speexenc->state, SPEEX_SET_DTX, &tmp);
658 if (speexenc->dtx && !(speexenc->vbr || speexenc->abr || speexenc->vad)) {
659 gst_speexenc_set_last_msg (speexenc,
660 "Warning: dtx is useless without vad, vbr or abr");
661 } else if ((speexenc->vbr || speexenc->abr) && (speexenc->vad)) {
662 gst_speexenc_set_last_msg (speexenc,
663 "Warning: vad is already implied by vbr or abr");
667 speex_encoder_ctl (speexenc->state, SPEEX_SET_ABR, &speexenc->abr);
670 speex_encoder_ctl (speexenc->state, SPEEX_GET_LOOKAHEAD,
671 &speexenc->lookahead);
673 speexenc->setup = TRUE;
678 /* prepare a buffer for transmission */
680 gst_speexenc_buffer_from_data (GstSpeexEnc * speexenc, guchar * data,
681 gint data_len, guint64 granulepos)
685 outbuf = gst_buffer_new_and_alloc (data_len);
686 memcpy (GST_BUFFER_DATA (outbuf), data, data_len);
687 GST_BUFFER_OFFSET (outbuf) = speexenc->bytes_out;
688 GST_BUFFER_OFFSET_END (outbuf) = granulepos;
690 GST_DEBUG ("encoded buffer of %d bytes", GST_BUFFER_SIZE (outbuf));
695 /* push out the buffer and do internal bookkeeping */
697 gst_speexenc_push_buffer (GstSpeexEnc * speexenc, GstBuffer * buffer)
699 speexenc->bytes_out += GST_BUFFER_SIZE (buffer);
701 return gst_pad_push (speexenc->srcpad, buffer);
706 gst_speexenc_set_header_on_caps (GstCaps * caps, GstBuffer * buf1,
709 GstStructure *structure = NULL;
711 GValue array = { 0 };
712 GValue value = { 0 };
714 caps = gst_caps_make_writable (caps);
715 structure = gst_caps_get_structure (caps, 0);
717 g_assert (gst_buffer_is_metadata_writable (buf1));
718 g_assert (gst_buffer_is_metadata_writable (buf2));
721 GST_BUFFER_FLAG_SET (buf1, GST_BUFFER_FLAG_IN_CAPS);
722 GST_BUFFER_FLAG_SET (buf2, GST_BUFFER_FLAG_IN_CAPS);
724 /* put buffers in a fixed list */
725 g_value_init (&array, GST_TYPE_ARRAY);
726 g_value_init (&value, GST_TYPE_BUFFER);
727 buf = gst_buffer_copy (buf1);
728 gst_value_set_buffer (&value, buf);
729 gst_buffer_unref (buf);
730 gst_value_array_append_value (&array, &value);
731 g_value_unset (&value);
732 g_value_init (&value, GST_TYPE_BUFFER);
733 buf = gst_buffer_copy (buf2);
734 gst_value_set_buffer (&value, buf);
735 gst_buffer_unref (buf);
736 gst_value_array_append_value (&array, &value);
737 gst_structure_set_value (structure, "streamheader", &array);
738 g_value_unset (&value);
739 g_value_unset (&array);
746 gst_speexenc_sinkevent (GstPad * pad, GstEvent * event)
749 GstSpeexEnc *speexenc;
751 speexenc = GST_SPEEXENC (GST_PAD_PARENT (pad));
753 switch (GST_EVENT_TYPE (event)) {
755 speexenc->eos = TRUE;
756 res = gst_pad_event_default (pad, event);
762 gst_event_parse_tag (event, &list);
763 if (speexenc->tags) {
764 gst_tag_list_insert (speexenc->tags, list,
765 gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (speexenc)));
767 g_assert_not_reached ();
769 res = gst_pad_event_default (pad, event);
773 res = gst_pad_event_default (pad, event);
781 gst_speexenc_chain (GstPad * pad, GstBuffer * buf)
783 GstSpeexEnc *speexenc;
784 GstFlowReturn ret = GST_FLOW_OK;
786 speexenc = GST_SPEEXENC (GST_PAD_PARENT (pad));
788 if (!speexenc->setup)
791 if (!speexenc->header_sent) {
792 /* Speex streams begin with two headers; the initial header (with
793 most of the codec setup parameters) which is mandated by the Ogg
794 bitstream spec. The second header holds any comment fields.
795 We merely need to make the headers, then pass them to libspeex
796 one at a time; libspeex handles the additional Ogg bitstream
798 GstBuffer *buf1, *buf2;
803 /* create header buffer */
804 data = (guint8 *) speex_header_to_packet (&speexenc->header, &data_len);
805 buf1 = gst_speexenc_buffer_from_data (speexenc, data, data_len, 0);
808 /* create comment buffer */
809 buf2 = gst_speexenc_create_metadata_buffer (speexenc);
811 /* mark and put on caps */
812 caps = gst_pad_get_caps (speexenc->srcpad);
813 caps = gst_speexenc_set_header_on_caps (caps, buf1, buf2);
815 /* negotiate with these caps */
816 GST_DEBUG ("here are the caps: %" GST_PTR_FORMAT, caps);
817 gst_pad_set_caps (speexenc->srcpad, caps);
819 gst_buffer_set_caps (buf1, caps);
820 gst_buffer_set_caps (buf2, caps);
821 gst_caps_unref (caps);
823 /* push out buffers */
824 ret = gst_speexenc_push_buffer (speexenc, buf1);
826 if (ret != GST_FLOW_OK) {
827 gst_buffer_unref (buf2);
831 ret = gst_speexenc_push_buffer (speexenc, buf2);
833 if (ret != GST_FLOW_OK)
836 speex_bits_reset (&speexenc->bits);
838 speexenc->header_sent = TRUE;
842 gint frame_size = speexenc->frame_size;
843 gint bytes = frame_size * 2 * speexenc->channels;
845 /* push buffer to adapter */
846 gst_adapter_push (speexenc->adapter, buf);
848 while (gst_adapter_available (speexenc->adapter) >= bytes) {
851 gint outsize, written;
854 data = (gint16 *) gst_adapter_peek (speexenc->adapter, bytes);
856 for (i = 0; i < frame_size * speexenc->channels; i++) {
857 speexenc->input[i] = (gfloat) data[i];
859 gst_adapter_flush (speexenc->adapter, bytes);
861 speexenc->samples_in += frame_size;
863 if (speexenc->channels == 2) {
864 speex_encode_stereo (speexenc->input, frame_size, &speexenc->bits);
866 speex_encode (speexenc->state, speexenc->input, &speexenc->bits);
870 if ((speexenc->frameno % speexenc->nframes) != 0)
873 speex_bits_insert_terminator (&speexenc->bits);
874 outsize = speex_bits_nbytes (&speexenc->bits);
876 ret = gst_pad_alloc_buffer_and_set_caps (speexenc->srcpad,
877 GST_BUFFER_OFFSET_NONE, outsize, GST_PAD_CAPS (speexenc->srcpad),
880 if ((GST_FLOW_OK != ret))
883 written = speex_bits_write (&speexenc->bits,
884 (gchar *) GST_BUFFER_DATA (outbuf), outsize);
885 g_assert (written == outsize);
886 speex_bits_reset (&speexenc->bits);
888 GST_BUFFER_TIMESTAMP (outbuf) =
889 gst_util_uint64_scale_int (speexenc->frameno * frame_size -
890 speexenc->lookahead, GST_SECOND, speexenc->rate);
891 GST_BUFFER_DURATION (outbuf) = gst_util_uint64_scale_int (frame_size,
892 GST_SECOND, speexenc->rate);
893 /* set gp time and granulepos; see gst-plugins-base/ext/ogg/README */
894 GST_BUFFER_OFFSET_END (outbuf) =
895 ((speexenc->frameno + 1) * frame_size - speexenc->lookahead);
896 GST_BUFFER_OFFSET (outbuf) =
897 gst_util_uint64_scale_int (GST_BUFFER_OFFSET_END (outbuf), GST_SECOND,
900 ret = gst_speexenc_push_buffer (speexenc, outbuf);
902 if ((GST_FLOW_OK != ret) && (GST_FLOW_NOT_LINKED != ret))
913 gst_buffer_unref (buf);
914 GST_ELEMENT_ERROR (speexenc, CORE, NEGOTIATION, (NULL),
915 ("encoder not initialized (input is not audio?)"));
916 ret = GST_FLOW_NOT_NEGOTIATED;
924 gst_speexenc_get_property (GObject * object, guint prop_id, GValue * value,
927 GstSpeexEnc *speexenc;
929 g_return_if_fail (GST_IS_SPEEXENC (object));
931 speexenc = GST_SPEEXENC (object);
935 g_value_set_float (value, speexenc->quality);
938 g_value_set_int (value, speexenc->bitrate);
941 g_value_set_boolean (value, speexenc->vbr);
944 g_value_set_int (value, speexenc->abr);
947 g_value_set_boolean (value, speexenc->vad);
950 g_value_set_boolean (value, speexenc->dtx);
953 g_value_set_int (value, speexenc->complexity);
956 g_value_set_int (value, speexenc->nframes);
958 case ARG_LAST_MESSAGE:
959 g_value_set_string (value, speexenc->last_message);
962 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
968 gst_speexenc_set_property (GObject * object, guint prop_id,
969 const GValue * value, GParamSpec * pspec)
971 GstSpeexEnc *speexenc;
973 g_return_if_fail (GST_IS_SPEEXENC (object));
975 speexenc = GST_SPEEXENC (object);
979 speexenc->quality = g_value_get_float (value);
982 speexenc->bitrate = g_value_get_int (value);
985 speexenc->vbr = g_value_get_boolean (value);
988 speexenc->abr = g_value_get_int (value);
991 speexenc->vad = g_value_get_boolean (value);
994 speexenc->dtx = g_value_get_boolean (value);
997 speexenc->complexity = g_value_get_int (value);
1000 speexenc->nframes = g_value_get_int (value);
1003 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1008 static GstStateChangeReturn
1009 gst_speexenc_change_state (GstElement * element, GstStateChange transition)
1011 GstSpeexEnc *speexenc = GST_SPEEXENC (element);
1012 GstStateChangeReturn res;
1014 switch (transition) {
1015 case GST_STATE_CHANGE_NULL_TO_READY:
1016 speexenc->tags = gst_tag_list_new ();
1018 case GST_STATE_CHANGE_READY_TO_PAUSED:
1019 speex_bits_init (&speexenc->bits);
1020 speexenc->frameno = 0;
1021 speexenc->samples_in = 0;
1023 case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
1029 res = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1031 switch (transition) {
1032 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
1034 case GST_STATE_CHANGE_PAUSED_TO_READY:
1035 speexenc->setup = FALSE;
1036 speexenc->header_sent = FALSE;
1037 if (speexenc->state) {
1038 speex_encoder_destroy (speexenc->state);
1039 speexenc->state = NULL;
1041 speex_bits_destroy (&speexenc->bits);
1043 case GST_STATE_CHANGE_READY_TO_NULL:
1044 gst_tag_list_free (speexenc->tags);
1045 speexenc->tags = NULL;