GST_STATIC_CAPS ("audio/x-speex")
);
-GST_BOILERPLATE (GstSpeexDec, gst_speex_dec, GstAudioDecoder,
- GST_TYPE_AUDIO_DECODER);
-
+#define gst_speex_dec_parent_class parent_class
- G_DEFINE_TYPE (GstSpeexDec, gst_speex_dec, GST_TYPE_ELEMENT);
-
- static gboolean speex_dec_sink_event (GstPad * pad, GstEvent * event);
- static GstFlowReturn speex_dec_chain (GstPad * pad, GstBuffer * buf);
- static GstStateChangeReturn speex_dec_change_state (GstElement * element,
- GstStateChange transition);
-
- static gboolean speex_dec_src_event (GstPad * pad, GstEvent * event);
- static gboolean speex_dec_src_query (GstPad * pad, GstQuery * query);
- static gboolean speex_dec_sink_query (GstPad * pad, GstQuery * query);
- static const GstQueryType *speex_get_src_query_types (GstPad * pad);
- static const GstQueryType *speex_get_sink_query_types (GstPad * pad);
- static gboolean speex_dec_convert (GstPad * pad,
- GstFormat src_format, gint64 src_value,
- GstFormat * dest_format, gint64 * dest_value);
++G_DEFINE_TYPE (GstSpeexDec, gst_speex_dec, GST_TYPE_AUDIO_DECODER);
+
+ static gboolean gst_speex_dec_start (GstAudioDecoder * dec);
+ static gboolean gst_speex_dec_stop (GstAudioDecoder * dec);
+ static gboolean gst_speex_dec_set_format (GstAudioDecoder * bdec,
+ GstCaps * caps);
+ static GstFlowReturn gst_speex_dec_handle_frame (GstAudioDecoder * dec,
+ GstBuffer * buffer);
static void gst_speex_dec_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
static void gst_speex_dec_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec);
- static GstFlowReturn speex_dec_chain_parse_data (GstSpeexDec * dec,
- GstBuffer * buf, GstClockTime timestamp, GstClockTime duration);
-
- static GstFlowReturn speex_dec_chain_parse_header (GstSpeexDec * dec,
- GstBuffer * buf);
- static GstFlowReturn speex_dec_chain_parse_comments (GstSpeexDec * dec,
- GstBuffer * buf);
-
static void
-gst_speex_dec_base_init (gpointer g_class)
-{
- GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
-
- gst_element_class_add_pad_template (element_class,
- gst_static_pad_template_get (&speex_dec_src_factory));
- gst_element_class_add_pad_template (element_class,
- gst_static_pad_template_get (&speex_dec_sink_factory));
- gst_element_class_set_details_simple (element_class, "Speex audio decoder",
- "Codec/Decoder/Audio",
- "decode speex streams to audio", "Wim Taymans <wim@fluendo.com>");
-}
-
-static void
gst_speex_dec_class_init (GstSpeexDecClass * klass)
{
GObjectClass *gobject_class;
+ GstElementClass *gstelement_class;
+ GstAudioDecoderClass *base_class;
gobject_class = (GObjectClass *) klass;
+ gstelement_class = (GstElementClass *) klass;
+ base_class = (GstAudioDecoderClass *) klass;
gobject_class->set_property = gst_speex_dec_set_property;
gobject_class->get_property = gst_speex_dec_get_property;
g_param_spec_boolean ("enh", "Enh", "Enable perceptual enhancement",
DEFAULT_ENH, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
- gstelement_class->change_state = GST_DEBUG_FUNCPTR (speex_dec_change_state);
-
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&speex_dec_src_factory));
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&speex_dec_sink_factory));
+ gst_element_class_set_details_simple (gstelement_class, "Speex audio decoder",
+ "Codec/Decoder/Audio",
+ "decode speex streams to audio", "Wim Taymans <wim@fluendo.com>");
+
GST_DEBUG_CATEGORY_INIT (speexdec_debug, "speexdec", 0,
"speex decoding element");
}
}
static void
-gst_speex_dec_init (GstSpeexDec * dec, GstSpeexDecClass * g_class)
+gst_speex_dec_init (GstSpeexDec * dec)
{
- dec->sinkpad =
- gst_pad_new_from_static_template (&speex_dec_sink_factory, "sink");
- gst_pad_set_chain_function (dec->sinkpad,
- GST_DEBUG_FUNCPTR (speex_dec_chain));
- gst_pad_set_event_function (dec->sinkpad,
- GST_DEBUG_FUNCPTR (speex_dec_sink_event));
- gst_pad_set_query_type_function (dec->sinkpad,
- GST_DEBUG_FUNCPTR (speex_get_sink_query_types));
- gst_pad_set_query_function (dec->sinkpad,
- GST_DEBUG_FUNCPTR (speex_dec_sink_query));
- gst_element_add_pad (GST_ELEMENT (dec), dec->sinkpad);
-
- dec->srcpad =
- gst_pad_new_from_static_template (&speex_dec_src_factory, "src");
- gst_pad_use_fixed_caps (dec->srcpad);
- gst_pad_set_event_function (dec->srcpad,
- GST_DEBUG_FUNCPTR (speex_dec_src_event));
- gst_pad_set_query_type_function (dec->srcpad,
- GST_DEBUG_FUNCPTR (speex_get_src_query_types));
- gst_pad_set_query_function (dec->srcpad,
- GST_DEBUG_FUNCPTR (speex_dec_src_query));
- gst_element_add_pad (GST_ELEMENT (dec), dec->srcpad);
-
dec->enh = DEFAULT_ENH;
gst_speex_dec_reset (dec);
}
static GstFlowReturn
- speex_dec_chain_parse_header (GstSpeexDec * dec, GstBuffer * buf)
+ gst_speex_dec_parse_header (GstSpeexDec * dec, GstBuffer * buf)
{
GstCaps *caps;
+ char *data;
+ gsize size;
/* get the header */
- dec->header = speex_packet_to_header ((char *) GST_BUFFER_DATA (buf),
- GST_BUFFER_SIZE (buf));
+ data = gst_buffer_map (buf, &size, NULL, GST_MAP_READ);
+ dec->header = speex_packet_to_header (data, size);
+ gst_buffer_unmap (buf, data, size);
if (!dec->header)
goto no_header;
speex_bits_init (&dec->bits);
/* set caps */
- caps = gst_caps_new_simple ("audio/x-raw-int",
+ caps = gst_caps_new_simple ("audio/x-raw",
+ "format", G_TYPE_STRING, FORMAT_STR,
"rate", G_TYPE_INT, dec->header->rate,
- "channels", G_TYPE_INT, dec->header->nb_channels,
- "signed", G_TYPE_BOOLEAN, TRUE,
- "endianness", G_TYPE_INT, G_BYTE_ORDER,
- "width", G_TYPE_INT, 16, "depth", G_TYPE_INT, 16, NULL);
+ "channels", G_TYPE_INT, dec->header->nb_channels, NULL);
- if (!gst_pad_set_caps (dec->srcpad, caps))
+ if (!gst_pad_set_caps (GST_AUDIO_DECODER_SRC_PAD (dec), caps))
goto nego_failed;
gst_caps_unref (caps);
if (!dec->frame_duration)
goto not_negotiated;
- if (timestamp != -1) {
- dec->segment.position = timestamp;
- } else {
- timestamp = dec->segment.position;
- }
- if (G_LIKELY (GST_BUFFER_SIZE (buf))) {
- data = GST_BUFFER_DATA (buf);
- size = GST_BUFFER_SIZE (buf);
--
- if (buf) {
++ if (G_LIKELY (gst_buffer_get_size (buf))) {
/* send data to the bitstream */
- speex_bits_read_from (&dec->bits, (char *) data, size);
+ data = gst_buffer_map (buf, &size, NULL, GST_MAP_READ);
+ speex_bits_read_from (&dec->bits, data, size);
+ gst_buffer_unmap (buf, data, size);
fpp = dec->header->frames_per_packet;
bits = &dec->bits;
GST_LOG_OBJECT (dec, "decoding frame %d/%d, %d bits remaining", i, fpp,
bits ? speex_bits_remaining (bits) : -1);
-
+#if 0
- res = gst_pad_alloc_buffer_and_set_caps (dec->srcpad,
+ res =
+ gst_pad_alloc_buffer_and_set_caps (GST_AUDIO_DECODER_SRC_PAD (dec),
GST_BUFFER_OFFSET_NONE, dec->frame_size * dec->header->nb_channels * 2,
- GST_PAD_CAPS (dec->srcpad), &outbuf);
+ GST_PAD_CAPS (GST_AUDIO_DECODER_SRC_PAD (dec)), &outbuf);
if (res != GST_FLOW_OK) {
GST_DEBUG_OBJECT (dec, "buf alloc flow: %s", gst_flow_get_name (res));
}
}
+static gboolean
+memcmp_buffers (GstBuffer * buf1, GstBuffer * buf2)
+{
+ gsize size1, size2;
+ gpointer data1;
+ gboolean res;
+
+ size1 = gst_buffer_get_size (buf1);
+ size2 = gst_buffer_get_size (buf2);
+
+ if (size1 != size2)
+ return FALSE;
+
+ data1 = gst_buffer_map (buf1, NULL, NULL, GST_MAP_READ);
+ res = gst_buffer_memcmp (buf2, 0, data1, size1) == 0;
+ gst_buffer_unmap (buf1, data1, size1);
+
+ return res;
+}
+
static GstFlowReturn
- speex_dec_chain (GstPad * pad, GstBuffer * buf)
+ gst_speex_dec_handle_frame (GstAudioDecoder * bdec, GstBuffer * buf)
{
GstFlowReturn res;
GstSpeexDec *dec;
/* If we have the streamheader and vorbiscomment from the caps already
* ignore them here */
if (dec->streamheader && dec->vorbiscomment) {
- if (GST_BUFFER_SIZE (dec->streamheader) == GST_BUFFER_SIZE (buf)
- && memcmp (GST_BUFFER_DATA (dec->streamheader), GST_BUFFER_DATA (buf),
- GST_BUFFER_SIZE (buf)) == 0) {
+ if (memcmp_buffers (dec->streamheader, buf)) {
+ GST_DEBUG_OBJECT (dec, "found streamheader");
+ gst_audio_decoder_finish_frame (bdec, NULL, 1);
res = GST_FLOW_OK;
- } else if (GST_BUFFER_SIZE (dec->vorbiscomment) == GST_BUFFER_SIZE (buf)
- && memcmp (GST_BUFFER_DATA (dec->vorbiscomment), GST_BUFFER_DATA (buf),
- GST_BUFFER_SIZE (buf)) == 0) {
+ } else if (memcmp_buffers (dec->vorbiscomment, buf)) {
+ GST_DEBUG_OBJECT (dec, "found vorbiscomments");
+ gst_audio_decoder_finish_frame (bdec, NULL, 1);
res = GST_FLOW_OK;
} else {
- res =
- speex_dec_chain_parse_data (dec, buf, GST_BUFFER_TIMESTAMP (buf),
- GST_BUFFER_DURATION (buf));
+ res = gst_speex_dec_parse_data (dec, buf);
}
} else {
/* Otherwise fall back to packet counting and assume that the
GValue * value, GParamSpec * pspec);
static void gst_speex_enc_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec);
- static GstStateChangeReturn gst_speex_enc_change_state (GstElement * element,
- GstStateChange transition);
- static GstFlowReturn gst_speex_enc_encode (GstSpeexEnc * enc, gboolean flush);
+ static GstFlowReturn gst_speex_enc_encode (GstSpeexEnc * enc, GstBuffer * buf);
+
+ static gboolean gst_speex_enc_start (GstAudioEncoder * enc);
+ static gboolean gst_speex_enc_stop (GstAudioEncoder * enc);
+ static gboolean gst_speex_enc_set_format (GstAudioEncoder * enc,
+ GstAudioInfo * info);
+ static GstFlowReturn gst_speex_enc_handle_frame (GstAudioEncoder * enc,
+ GstBuffer * in_buf);
+ static gboolean gst_speex_enc_sink_event (GstAudioEncoder * enc,
+ GstEvent * event);
-static void
-gst_speex_enc_setup_interfaces (GType speexenc_type)
-{
- static const GInterfaceInfo tag_setter_info = { NULL, NULL, NULL };
-
- g_type_add_interface_static (speexenc_type, GST_TYPE_TAG_SETTER,
- &tag_setter_info);
-
- GST_DEBUG_CATEGORY_INIT (speexenc_debug, "speexenc", 0, "Speex encoder");
-}
-
-GST_BOILERPLATE_FULL (GstSpeexEnc, gst_speex_enc, GstAudioEncoder,
- GST_TYPE_AUDIO_ENCODER, gst_speex_enc_setup_interfaces);
-
-static void
-gst_speex_enc_base_init (gpointer g_class)
-{
- GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
-
- gst_element_class_add_pad_template (element_class,
- gst_static_pad_template_get (&src_factory));
- gst_element_class_add_pad_template (element_class,
- gst_static_pad_template_get (&sink_factory));
- gst_element_class_set_details_simple (element_class, "Speex audio encoder",
- "Codec/Encoder/Audio",
- "Encodes audio in Speex format", "Wim Taymans <wim@fluendo.com>");
-}
+#define gst_speex_enc_parent_class parent_class
- G_DEFINE_TYPE_WITH_CODE (GstSpeexEnc, gst_speex_enc, GST_TYPE_ELEMENT,
++G_DEFINE_TYPE_WITH_CODE (GstSpeexEnc, gst_speex_enc, GST_TYPE_AUDIO_ENCODER,
+ G_IMPLEMENT_INTERFACE (GST_TYPE_TAG_SETTER, NULL);
+ G_IMPLEMENT_INTERFACE (GST_TYPE_PRESET, NULL));
static void
gst_speex_enc_class_init (GstSpeexEncClass * klass)
{
GObjectClass *gobject_class;
+ GstElementClass *gstelement_class;
+ GstAudioEncoderClass *base_class;
gobject_class = (GObjectClass *) klass;
+ gstelement_class = (GstElementClass *) klass;
+ base_class = (GstAudioEncoderClass *) klass;
+ gobject_class->finalize = gst_speex_enc_finalize;
gobject_class->set_property = gst_speex_enc_set_property;
gobject_class->get_property = gst_speex_enc_get_property;
"The last status message", NULL,
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
- gstelement_class->change_state =
- GST_DEBUG_FUNCPTR (gst_speex_enc_change_state);
-
- gobject_class->finalize = gst_speex_enc_finalize;
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&src_factory));
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&sink_factory));
+ gst_element_class_set_details_simple (gstelement_class, "Speex audio encoder",
+ "Codec/Encoder/Audio",
+ "Encodes audio in Speex format", "Wim Taymans <wim@fluendo.com>");
+
+ GST_DEBUG_CATEGORY_INIT (speexenc_debug, "speexenc", 0, "Speex encoder");
}
static void
G_OBJECT_CLASS (parent_class)->finalize (object);
}
- static gboolean
- gst_speex_enc_sink_setcaps (GstPad * pad, GstCaps * caps)
- {
- GstSpeexEnc *enc;
- GstStructure *structure;
-
- enc = GST_SPEEX_ENC (GST_PAD_PARENT (pad));
- enc->setup = FALSE;
-
- structure = gst_caps_get_structure (caps, 0);
- gst_structure_get_int (structure, "channels", &enc->channels);
- gst_structure_get_int (structure, "rate", &enc->rate);
-
- gst_speex_enc_setup (enc);
-
- return enc->setup;
- }
-
-
- static GstCaps *
- gst_speex_enc_sink_getcaps (GstPad * pad, GstCaps * filter)
+ static void
-gst_speex_enc_init (GstSpeexEnc * enc, GstSpeexEncClass * klass)
++gst_speex_enc_init (GstSpeexEnc * enc)
{
- GstCaps *caps = gst_caps_copy (gst_pad_get_pad_template_caps (pad));
- GstCaps *peercaps = NULL;
- GstSpeexEnc *enc = GST_SPEEX_ENC (gst_pad_get_parent_element (pad));
-
- peercaps = gst_pad_peer_get_caps (enc->srcpad, filter);
-
- if (peercaps) {
- if (!gst_caps_is_empty (peercaps) && !gst_caps_is_any (peercaps)) {
- GstStructure *ps = gst_caps_get_structure (peercaps, 0);
- GstStructure *s = gst_caps_get_structure (caps, 0);
- gint rate, channels;
-
- if (gst_structure_get_int (ps, "rate", &rate)) {
- gst_structure_fixate_field_nearest_int (s, "rate", rate);
- }
-
- if (gst_structure_get_int (ps, "channels", &channels)) {
- gst_structure_fixate_field_nearest_int (s, "channels", channels);
- }
- }
- gst_caps_unref (peercaps);
- }
-
- gst_object_unref (enc);
+ GstAudioEncoder *benc = GST_AUDIO_ENCODER (enc);
- return caps;
+ /* arrange granulepos marking (and required perfect ts) */
+ gst_audio_encoder_set_mark_granule (benc, TRUE);
+ gst_audio_encoder_set_perfect_timestamp (benc, TRUE);
}
-
static gboolean
- gst_speex_enc_convert_src (GstPad * pad, GstFormat src_format, gint64 src_value,
- GstFormat dest_format, gint64 * dest_value)
+ gst_speex_enc_start (GstAudioEncoder * benc)
{
- gboolean res = TRUE;
- GstSpeexEnc *enc;
- gint64 avg;
-
- enc = GST_SPEEX_ENC (GST_PAD_PARENT (pad));
+ GstSpeexEnc *enc = GST_SPEEX_ENC (benc);
- if (enc->samples_in == 0 || enc->bytes_out == 0 || enc->rate == 0)
- return FALSE;
-
- avg = (enc->bytes_out * enc->rate) / (enc->samples_in);
+ GST_DEBUG_OBJECT (enc, "start");
+ speex_bits_init (&enc->bits);
+ enc->tags = gst_tag_list_new ();
+ enc->header_sent = FALSE;
- switch (src_format) {
- case GST_FORMAT_BYTES:
- switch (dest_format) {
- case GST_FORMAT_TIME:
- *dest_value = src_value * GST_SECOND / avg;
- break;
- default:
- res = FALSE;
- }
- break;
- case GST_FORMAT_TIME:
- switch (dest_format) {
- case GST_FORMAT_BYTES:
- *dest_value = src_value * avg / GST_SECOND;
- break;
- default:
- res = FALSE;
- }
- break;
- default:
- res = FALSE;
- }
- return res;
+ return TRUE;
}
static gboolean
static GstFlowReturn
gst_speex_enc_push_buffer (GstSpeexEnc * enc, GstBuffer * buffer)
{
-- guint size;
-
- size = gst_buffer_get_size (buffer);
- enc->bytes_out += size;
--
- size = GST_BUFFER_SIZE (buffer);
-- GST_DEBUG_OBJECT (enc, "pushing output buffer of size %u", size);
-
- return gst_pad_push (enc->srcpad, buffer);
- }
-
- static GstCaps *
- gst_speex_enc_set_header_on_caps (GstCaps * caps, GstBuffer * buf1,
- GstBuffer * buf2)
- {
- GstStructure *structure = NULL;
- GstBuffer *buf;
- GValue array = { 0 };
- GValue value = { 0 };
-
- caps = gst_caps_make_writable (caps);
- structure = gst_caps_get_structure (caps, 0);
++ GST_DEBUG_OBJECT (enc, "pushing output buffer of size %u",
++ gst_buffer_get_size (buffer));
- g_assert (gst_buffer_is_writable (buf1));
- g_assert (gst_buffer_is_writable (buf2));
-
- /* mark buffers */
- GST_BUFFER_FLAG_SET (buf1, GST_BUFFER_FLAG_IN_CAPS);
- GST_BUFFER_FLAG_SET (buf2, GST_BUFFER_FLAG_IN_CAPS);
-
- /* put buffers in a fixed list */
- g_value_init (&array, GST_TYPE_ARRAY);
- g_value_init (&value, GST_TYPE_BUFFER);
- buf = gst_buffer_copy (buf1);
- gst_value_set_buffer (&value, buf);
- gst_buffer_unref (buf);
- gst_value_array_append_value (&array, &value);
- g_value_unset (&value);
- g_value_init (&value, GST_TYPE_BUFFER);
- buf = gst_buffer_copy (buf2);
- gst_value_set_buffer (&value, buf);
- gst_buffer_unref (buf);
- gst_value_array_append_value (&array, &value);
- gst_structure_set_value (structure, "streamheader", &array);
- g_value_unset (&value);
- g_value_unset (&array);
-
- return caps;
+ return gst_pad_push (GST_AUDIO_ENCODER_SRC_PAD (enc), buffer);
}
-
static gboolean
- gst_speex_enc_sink_event (GstPad * pad, GstEvent * event)
+ gst_speex_enc_sink_event (GstAudioEncoder * benc, GstEvent * event)
{
- gboolean res = TRUE;
GstSpeexEnc *enc;
- enc = GST_SPEEX_ENC (gst_pad_get_parent (pad));
+ enc = GST_SPEEX_ENC (benc);
switch (GST_EVENT_TYPE (event)) {
- case GST_EVENT_CAPS:
- {
- GstCaps *caps;
-
- gst_event_parse_caps (event, &caps);
- res = gst_speex_enc_sink_setcaps (pad, caps);
- gst_event_unref (event);
- break;
- }
- case GST_EVENT_EOS:
- if (enc->setup)
- gst_speex_enc_encode (enc, TRUE);
- res = gst_pad_event_default (pad, event);
- break;
case GST_EVENT_TAG:
{
if (enc->tags) {
}
static GstFlowReturn
- gst_speex_enc_encode (GstSpeexEnc * enc, gboolean flush)
+ gst_speex_enc_encode (GstSpeexEnc * enc, GstBuffer * buf)
{
gint frame_size = enc->frame_size;
- gint bytes = frame_size * 2 * enc->channels;
- gint bytes = frame_size * 2 * enc->channels, samples, size;
++ gint bytes = frame_size * 2 * enc->channels, samples;
+ gint outsize, written, dtx_ret = 0;
- guint8 *data;
++ guint8 *data, *bdata, *outdata;
++ gsize bsize, size;
+ GstBuffer *outbuf;
GstFlowReturn ret = GST_FLOW_OK;
- if (flush && gst_adapter_available (enc->adapter) % bytes != 0) {
- guint diff = gst_adapter_available (enc->adapter) % bytes;
- GstBuffer *buf = gst_buffer_new_and_alloc (diff);
- gst_buffer_memset (buf, 0, 0, diff);
- gst_adapter_push (enc->adapter, buf);
- }
+ if (G_LIKELY (buf)) {
- data = GST_BUFFER_DATA (buf);
- size = GST_BUFFER_SIZE (buf);
++ bdata = gst_buffer_map (buf, &bsize, NULL, GST_MAP_READ);
+
- if (G_UNLIKELY (size % bytes)) {
++ if (G_UNLIKELY (bsize % bytes)) {
+ GST_DEBUG_OBJECT (enc, "draining; adding silence samples");
- size = ((size / bytes) + 1) * bytes;
+
- while (gst_adapter_available (enc->adapter) >= bytes) {
- gint16 *data;
- gint outsize, written, dtx_ret;
- GstBuffer *outbuf;
- gchar *outdata;
++ size = ((bsize / bytes) + 1) * bytes;
+ data = g_malloc0 (size);
- memcpy (data, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
++ memcpy (data, bdata, bsize);
++ gst_buffer_unmap (buf, bdata, bsize);
++ bdata = NULL;
++ } else {
++ data = bdata;
++ size = bsize;
+ }
+ } else {
+ GST_DEBUG_OBJECT (enc, "nothing to drain");
+ goto done;
+ }
- data = (gint16 *) gst_adapter_take (enc->adapter, bytes);
+ samples = size / (2 * enc->channels);
+ speex_bits_reset (&enc->bits);
- enc->samples_in += frame_size;
+ /* FIXME what about dropped samples if DTS enabled ?? */
+ while (size) {
GST_DEBUG_OBJECT (enc, "encoding %d samples (%d bytes)", frame_size, bytes);
if (enc->channels == 2) {
- speex_encode_stereo_int (data, frame_size, &enc->bits);
+ speex_encode_stereo_int ((gint16 *) data, frame_size, &enc->bits);
}
- dtx_ret = speex_encode_int (enc->state, data, &enc->bits);
-
- g_free (data);
+ dtx_ret += speex_encode_int (enc->state, (gint16 *) data, &enc->bits);
- enc->frameno++;
- enc->frameno_out++;
+ data += bytes;
+ size -= bytes;
+ }
- if ((enc->frameno % enc->nframes) != 0)
- continue;
+ speex_bits_insert_terminator (&enc->bits);
+ outsize = speex_bits_nbytes (&enc->bits);
- speex_bits_insert_terminator (&enc->bits);
- outsize = speex_bits_nbytes (&enc->bits);
++ if (bdata)
++ gst_buffer_unmap (buf, bdata, bsize);
+
+#if 0
- ret = gst_pad_alloc_buffer_and_set_caps (enc->srcpad,
- GST_BUFFER_OFFSET_NONE, outsize, GST_PAD_CAPS (enc->srcpad), &outbuf);
- if ((GST_FLOW_OK != ret))
- goto done;
+ ret = gst_pad_alloc_buffer_and_set_caps (GST_AUDIO_ENCODER_SRC_PAD (enc),
+ GST_BUFFER_OFFSET_NONE, outsize,
+ GST_PAD_CAPS (GST_AUDIO_ENCODER_SRC_PAD (enc)), &outbuf);
+
+ if ((GST_FLOW_OK != ret))
+ goto done;
+#endif
- outbuf = gst_buffer_new_allocate (NULL, outsize, 0);
++ outbuf = gst_buffer_new_allocate (NULL, outsize, 0);
++ outdata = gst_buffer_map (outbuf, NULL, NULL, GST_MAP_WRITE);
- outdata = gst_buffer_map (outbuf, NULL, NULL, GST_MAP_WRITE);
- written = speex_bits_write (&enc->bits, outdata, outsize);
- written = speex_bits_write (&enc->bits,
- (gchar *) GST_BUFFER_DATA (outbuf), outsize);
++ written = speex_bits_write (&enc->bits, (gchar *) outdata, outsize);
- if (G_UNLIKELY (written != outsize)) {
- GST_ERROR_OBJECT (enc, "short write: %d < %d bytes", written, outsize);
- }
- gst_buffer_unmap (outbuf, outdata, written);
+ if (G_UNLIKELY (written < outsize)) {
+ GST_ERROR_OBJECT (enc, "short write: %d < %d bytes", written, outsize);
- GST_BUFFER_SIZE (outbuf) = written;
+ } else if (G_UNLIKELY (written > outsize)) {
+ GST_ERROR_OBJECT (enc, "overrun: %d > %d bytes", written, outsize);
++ written = outsize;
+ }
++ gst_buffer_unmap (outbuf, outdata, written);
+
+ if (!dtx_ret)
+ GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_GAP);
- speex_bits_reset (&enc->bits);
+ ret = gst_audio_encoder_finish_frame (GST_AUDIO_ENCODER (enc),
+ outbuf, samples);
- if (!dtx_ret)
- GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_GAP);
+ done:
+ return ret;
+ }
- GST_BUFFER_TIMESTAMP (outbuf) = enc->start_ts +
- gst_util_uint64_scale_int ((enc->frameno_out -
- enc->nframes) * frame_size - enc->lookahead, GST_SECOND, enc->rate);
- GST_BUFFER_DURATION (outbuf) =
- gst_util_uint64_scale_int (frame_size * enc->nframes, GST_SECOND,
- enc->rate);
- /* set gp time and granulepos; see gst-plugins-base/ext/ogg/README */
- GST_BUFFER_OFFSET_END (outbuf) = enc->granulepos_offset +
- ((enc->frameno_out) * frame_size - enc->lookahead);
- GST_BUFFER_OFFSET (outbuf) =
- gst_util_uint64_scale_int (GST_BUFFER_OFFSET_END (outbuf), GST_SECOND,
- enc->rate);
+ /*
+ * (really really) FIXME: move into core (dixit tpm)
+ */
+ /**
+ * _gst_caps_set_buffer_array:
+ * @caps: a #GstCaps
+ * @field: field in caps to set
+ * @buf: header buffers
+ *
+ * Adds given buffers to an array of buffers set as the given @field
+ * on the given @caps. List of buffer arguments must be NULL-terminated.
+ *
+ * Returns: input caps with a streamheader field added, or NULL if some error
+ */
+ static GstCaps *
+ _gst_caps_set_buffer_array (GstCaps * caps, const gchar * field,
+ GstBuffer * buf, ...)
+ {
+ GstStructure *structure = NULL;
+ va_list va;
+ GValue array = { 0 };
+ GValue value = { 0 };
- ret = gst_speex_enc_push_buffer (enc, outbuf);
+ g_return_val_if_fail (caps != NULL, NULL);
+ g_return_val_if_fail (gst_caps_is_fixed (caps), NULL);
+ g_return_val_if_fail (field != NULL, NULL);
- if ((GST_FLOW_OK != ret) && (GST_FLOW_NOT_LINKED != ret))
- goto done;
+ caps = gst_caps_make_writable (caps);
+ structure = gst_caps_get_structure (caps, 0);
+
+ g_value_init (&array, GST_TYPE_ARRAY);
+
+ va_start (va, buf);
+ /* put buffers in a fixed list */
+ while (buf) {
- g_assert (gst_buffer_is_metadata_writable (buf));
++ g_assert (gst_buffer_is_writable (buf));
+
+ /* mark buffer */
+ GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_IN_CAPS);
+
+ g_value_init (&value, GST_TYPE_BUFFER);
+ buf = gst_buffer_copy (buf);
+ GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_IN_CAPS);
+ gst_value_set_buffer (&value, buf);
+ gst_buffer_unref (buf);
+ gst_value_array_append_value (&array, &value);
+ g_value_unset (&value);
+
+ buf = va_arg (va, GstBuffer *);
}
- done:
+ gst_structure_set_value (structure, field, &array);
+ g_value_unset (&array);
- return ret;
+ return caps;
}
static GstFlowReturn
/* create header buffer */
data = (guint8 *) speex_header_to_packet (&enc->header, &data_len);
- buf1 = gst_speex_enc_buffer_from_data (enc, data, data_len, 0);
- free (data);
- buf1 = gst_buffer_new ();
- GST_BUFFER_DATA (buf1) = GST_BUFFER_MALLOCDATA (buf1) = data;
- GST_BUFFER_SIZE (buf1) = data_len;
++ buf1 = gst_buffer_new_wrapped (data, data_len);
+ GST_BUFFER_OFFSET_END (buf1) = 0;
+ GST_BUFFER_OFFSET (buf1) = 0;
/* create comment buffer */
buf2 = gst_speex_enc_create_metadata_buffer (enc);
/* negotiate with these caps */
GST_DEBUG_OBJECT (enc, "here are the caps: %" GST_PTR_FORMAT, caps);
- gst_pad_set_caps (enc->srcpad, caps);
- gst_caps_unref (caps);
- gst_buffer_set_caps (buf1, caps);
- gst_buffer_set_caps (buf2, caps);
- gst_caps_unref (caps);
-
/* push out buffers */
ret = gst_speex_enc_push_buffer (enc, buf1);
enc->header_sent = TRUE;
}
- /* Save the timestamp of the first buffer. This will be later
- * used as offset for all following buffers */
- if (enc->start_ts == GST_CLOCK_TIME_NONE) {
- if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)) {
- enc->start_ts = GST_BUFFER_TIMESTAMP (buf);
- enc->granulepos_offset = gst_util_uint64_scale
- (GST_BUFFER_TIMESTAMP (buf), enc->rate, GST_SECOND);
- } else {
- enc->start_ts = 0;
- enc->granulepos_offset = 0;
- }
- }
-
- /* Check if we have a continous stream, if not drop some samples or the buffer or
- * insert some silence samples */
- if (enc->next_ts != GST_CLOCK_TIME_NONE &&
- GST_BUFFER_TIMESTAMP_IS_VALID (buf) &&
- GST_BUFFER_TIMESTAMP (buf) < enc->next_ts) {
- guint64 diff = enc->next_ts - GST_BUFFER_TIMESTAMP (buf);
- guint64 diff_bytes;
-
- GST_WARNING_OBJECT (enc, "Buffer is older than previous "
- "timestamp + duration (%" GST_TIME_FORMAT "< %" GST_TIME_FORMAT
- "), cannot handle. Clipping buffer.",
- GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
- GST_TIME_ARGS (enc->next_ts));
-
- diff_bytes = GST_CLOCK_TIME_TO_FRAMES (diff, enc->rate) * enc->channels * 2;
- if (diff_bytes >= gst_buffer_get_size (buf)) {
- gst_buffer_unref (buf);
- return GST_FLOW_OK;
- }
- buf = gst_buffer_make_writable (buf);
- gst_buffer_resize (buf, diff_bytes, -1);
-
- GST_BUFFER_TIMESTAMP (buf) += diff;
- if (GST_BUFFER_DURATION_IS_VALID (buf))
- GST_BUFFER_DURATION (buf) -= diff;
- }
+ GST_DEBUG_OBJECT (enc, "received buffer %p of %u bytes", buf,
- buf ? GST_BUFFER_SIZE (buf) : 0);
++ buf ? gst_buffer_get_size (buf) : 0);
- if (enc->next_ts != GST_CLOCK_TIME_NONE
- && GST_BUFFER_TIMESTAMP_IS_VALID (buf)) {
- guint64 max_diff =
- gst_util_uint64_scale (enc->frame_size, GST_SECOND, enc->rate);
-
- if (GST_BUFFER_TIMESTAMP (buf) != enc->next_ts &&
- GST_BUFFER_TIMESTAMP (buf) - enc->next_ts > max_diff) {
- GST_WARNING_OBJECT (enc,
- "Discontinuity detected: %" G_GUINT64_FORMAT " > %" G_GUINT64_FORMAT,
- GST_BUFFER_TIMESTAMP (buf) - enc->next_ts, max_diff);
-
- gst_speex_enc_encode (enc, TRUE);
-
- enc->frameno_out = 0;
- enc->start_ts = GST_BUFFER_TIMESTAMP (buf);
- enc->granulepos_offset = gst_util_uint64_scale
- (GST_BUFFER_TIMESTAMP (buf), enc->rate, GST_SECOND);
- }
- }
-
- if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)
- && GST_BUFFER_DURATION_IS_VALID (buf))
- enc->next_ts = GST_BUFFER_TIMESTAMP (buf) + GST_BUFFER_DURATION (buf);
- else
- enc->next_ts = GST_CLOCK_TIME_NONE;
-
- GST_DEBUG_OBJECT (enc, "received buffer of %u bytes",
- gst_buffer_get_size (buf));
-
- /* push buffer to adapter */
- gst_adapter_push (enc->adapter, buf);
- buf = NULL;
-
- ret = gst_speex_enc_encode (enc, FALSE);
+ ret = gst_speex_enc_encode (enc, buf);
done:
-
- if (buf)
- gst_buffer_unref (buf);
-
return ret;
-
- /* ERRORS */
- not_setup:
- {
- GST_ELEMENT_ERROR (enc, CORE, NEGOTIATION, (NULL),
- ("encoder not initialized (input is not audio?)"));
- ret = GST_FLOW_NOT_NEGOTIATED;
- goto done;
- }
-
}