mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-27 12:11:13 +00:00
sirendec: rewrite sirendec
Add setcaps and event functions. Add state change functions to clean variables. Use adapter. Add timestamps and duration on outgoing buffers. Add DISCONT handling.
This commit is contained in:
parent
ef999c5df7
commit
d557572e66
2 changed files with 181 additions and 59 deletions
|
@ -40,6 +40,8 @@
|
||||||
GST_DEBUG_CATEGORY (sirendec_debug);
|
GST_DEBUG_CATEGORY (sirendec_debug);
|
||||||
#define GST_CAT_DEFAULT (sirendec_debug)
|
#define GST_CAT_DEFAULT (sirendec_debug)
|
||||||
|
|
||||||
|
#define FRAME_DURATION (20 * GST_MSECOND)
|
||||||
|
|
||||||
/* elementfactory information */
|
/* elementfactory information */
|
||||||
static const GstElementDetails gst_siren_dec_details =
|
static const GstElementDetails gst_siren_dec_details =
|
||||||
GST_ELEMENT_DETAILS ("Siren Decoder element",
|
GST_ELEMENT_DETAILS ("Siren Decoder element",
|
||||||
|
@ -75,11 +77,15 @@ enum
|
||||||
ARG_0,
|
ARG_0,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static void gst_siren_dec_finalize (GObject * object);
|
||||||
|
|
||||||
|
static GstStateChangeReturn
|
||||||
|
gst_siren_change_state (GstElement * element, GstStateChange transition);
|
||||||
|
|
||||||
|
static gboolean gst_siren_dec_sink_setcaps (GstPad * pad, GstCaps * caps);
|
||||||
|
static gboolean gst_siren_dec_sink_event (GstPad * pad, GstEvent * event);
|
||||||
static GstFlowReturn gst_siren_dec_chain (GstPad * pad, GstBuffer * buf);
|
static GstFlowReturn gst_siren_dec_chain (GstPad * pad, GstBuffer * buf);
|
||||||
|
|
||||||
static void gst_siren_dec_dispose (GObject * object);
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
_do_init (GType type)
|
_do_init (GType type)
|
||||||
{
|
{
|
||||||
|
@ -113,7 +119,9 @@ gst_siren_dec_class_init (GstSirenDecClass * klass)
|
||||||
|
|
||||||
GST_DEBUG ("Initializing Class");
|
GST_DEBUG ("Initializing Class");
|
||||||
|
|
||||||
gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_siren_dec_dispose);
|
gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_siren_dec_finalize);
|
||||||
|
|
||||||
|
gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_siren_change_state);
|
||||||
|
|
||||||
GST_DEBUG ("Class Init done");
|
GST_DEBUG ("Class Init done");
|
||||||
}
|
}
|
||||||
|
@ -128,102 +136,215 @@ gst_siren_dec_init (GstSirenDec * dec, GstSirenDecClass * klass)
|
||||||
dec->sinkpad = gst_pad_new_from_static_template (&sinktemplate, "sink");
|
dec->sinkpad = gst_pad_new_from_static_template (&sinktemplate, "sink");
|
||||||
dec->srcpad = gst_pad_new_from_static_template (&srctemplate, "src");
|
dec->srcpad = gst_pad_new_from_static_template (&srctemplate, "src");
|
||||||
|
|
||||||
|
gst_pad_set_setcaps_function (dec->sinkpad,
|
||||||
|
GST_DEBUG_FUNCPTR (gst_siren_dec_sink_setcaps));
|
||||||
|
gst_pad_set_event_function (dec->sinkpad,
|
||||||
|
GST_DEBUG_FUNCPTR (gst_siren_dec_sink_event));
|
||||||
gst_pad_set_chain_function (dec->sinkpad,
|
gst_pad_set_chain_function (dec->sinkpad,
|
||||||
GST_DEBUG_FUNCPTR (gst_siren_dec_chain));
|
GST_DEBUG_FUNCPTR (gst_siren_dec_chain));
|
||||||
|
|
||||||
gst_element_add_pad (GST_ELEMENT (dec), dec->sinkpad);
|
gst_element_add_pad (GST_ELEMENT (dec), dec->sinkpad);
|
||||||
gst_element_add_pad (GST_ELEMENT (dec), dec->srcpad);
|
gst_element_add_pad (GST_ELEMENT (dec), dec->srcpad);
|
||||||
|
|
||||||
dec->srccaps = gst_static_pad_template_get_caps (&srctemplate);
|
dec->adapter = gst_adapter_new ();
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (dec, "Init done");
|
GST_DEBUG_OBJECT (dec, "Init done");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gst_siren_dec_dispose (GObject * object)
|
gst_siren_dec_finalize (GObject * object)
|
||||||
{
|
{
|
||||||
GstSirenDec *dec = GST_SIREN_DEC (object);
|
GstSirenDec *dec = GST_SIREN_DEC (object);
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (dec, "Disposing");
|
GST_DEBUG_OBJECT (dec, "Finalize");
|
||||||
|
|
||||||
if (dec->decoder) {
|
|
||||||
Siren7_CloseDecoder (dec->decoder);
|
Siren7_CloseDecoder (dec->decoder);
|
||||||
dec->decoder = NULL;
|
g_object_unref (dec->adapter);
|
||||||
|
|
||||||
|
G_OBJECT_CLASS (parent_class)->finalize (object);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dec->srccaps) {
|
static gboolean
|
||||||
gst_caps_unref (dec->srccaps);
|
gst_siren_dec_sink_setcaps (GstPad * pad, GstCaps * caps)
|
||||||
dec->srccaps = NULL;
|
{
|
||||||
|
GstSirenDec *dec;
|
||||||
|
gboolean res;
|
||||||
|
GstCaps *outcaps;
|
||||||
|
|
||||||
|
dec = GST_SIREN_DEC (GST_PAD_PARENT (pad));
|
||||||
|
|
||||||
|
outcaps = gst_static_pad_template_get_caps (&srctemplate);
|
||||||
|
res = gst_pad_set_caps (dec->srcpad, outcaps);
|
||||||
|
gst_caps_unref (outcaps);
|
||||||
|
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
G_OBJECT_CLASS (parent_class)->dispose (object);
|
static gboolean
|
||||||
|
gst_siren_dec_sink_event (GstPad * pad, GstEvent * event)
|
||||||
|
{
|
||||||
|
GstSirenDec *dec;
|
||||||
|
gboolean res;
|
||||||
|
|
||||||
|
dec = GST_SIREN_DEC (GST_PAD_PARENT (pad));
|
||||||
|
|
||||||
|
switch (GST_EVENT_TYPE (event)) {
|
||||||
|
case GST_EVENT_EOS:
|
||||||
|
gst_adapter_clear (dec->adapter);
|
||||||
|
res = gst_pad_push_event (dec->srcpad, event);
|
||||||
|
break;
|
||||||
|
case GST_EVENT_FLUSH_STOP:
|
||||||
|
gst_adapter_clear (dec->adapter);
|
||||||
|
res = gst_pad_push_event (dec->srcpad, event);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
res = gst_pad_push_event (dec->srcpad, event);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
static GstFlowReturn
|
static GstFlowReturn
|
||||||
gst_siren_dec_chain (GstPad * pad, GstBuffer * buf)
|
gst_siren_dec_chain (GstPad * pad, GstBuffer * buf)
|
||||||
{
|
{
|
||||||
GstSirenDec *dec = GST_SIREN_DEC (gst_pad_get_parent_element (pad));
|
GstSirenDec *dec;
|
||||||
GstFlowReturn ret = GST_FLOW_OK;
|
GstFlowReturn ret = GST_FLOW_OK;
|
||||||
GstBuffer *decoded = NULL;
|
GstBuffer *out_buf;
|
||||||
guint in_offset = 0;
|
guint8 *in_data, *out_data;
|
||||||
guint out_offset = 0;
|
guint8 *to_free = NULL;
|
||||||
gint decode_ret = 0;
|
guint i, size, num_frames;
|
||||||
guint size = 0;
|
gint out_size, in_size;
|
||||||
|
gint decode_ret;
|
||||||
|
gboolean discont;
|
||||||
|
GstClockTime timestamp;
|
||||||
|
guint64 distance;
|
||||||
|
|
||||||
GST_LOG_OBJECT (dec, "Decoding buffer of size %d", GST_BUFFER_SIZE (buf));
|
dec = GST_SIREN_DEC (GST_PAD_PARENT (pad));
|
||||||
|
|
||||||
size = GST_BUFFER_SIZE (buf) * 16;
|
discont = GST_BUFFER_IS_DISCONT (buf);
|
||||||
size -= size % 640;
|
if (discont) {
|
||||||
|
GST_DEBUG_OBJECT (dec, "received DISCONT, flush adapter");
|
||||||
if (size == 0) {
|
gst_adapter_clear (dec->adapter);
|
||||||
GST_LOG_OBJECT (dec, "Got buffer smaller than framesize: %u < 40",
|
dec->discont = TRUE;
|
||||||
GST_BUFFER_SIZE (buf));
|
|
||||||
return GST_FLOW_OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (GST_BUFFER_SIZE (buf) % 40 != 0)
|
gst_adapter_push (dec->adapter, buf);
|
||||||
GST_LOG_OBJECT (dec, "Got buffer with size not a multiple for frame size,"
|
|
||||||
" ignoring last %u bytes", GST_BUFFER_SIZE (buf) % 40);
|
|
||||||
|
|
||||||
ret = gst_pad_alloc_buffer_and_set_caps (dec->srcpad,
|
size = gst_adapter_available (dec->adapter);
|
||||||
GST_BUFFER_OFFSET (buf) * 16, size, dec->srccaps, &decoded);
|
|
||||||
|
GST_LOG_OBJECT (dec, "Received buffer of size %u with adapter of size : %u",
|
||||||
|
GST_BUFFER_SIZE (buf), size);
|
||||||
|
|
||||||
|
/* process 40 input bytes into 640 output bytes */
|
||||||
|
num_frames = size / 40;
|
||||||
|
|
||||||
|
if (num_frames == 0)
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
/* this is the input/output size */
|
||||||
|
in_size = num_frames * 40;
|
||||||
|
out_size = num_frames * 640;
|
||||||
|
|
||||||
|
GST_LOG_OBJECT (dec, "we have %u frames, %u in, %u out", num_frames, in_size,
|
||||||
|
out_size);
|
||||||
|
|
||||||
|
/* get a buffer */
|
||||||
|
ret = gst_pad_alloc_buffer_and_set_caps (dec->srcpad, -1,
|
||||||
|
out_size, GST_PAD_CAPS (dec->srcpad), &out_buf);
|
||||||
if (ret != GST_FLOW_OK)
|
if (ret != GST_FLOW_OK)
|
||||||
|
goto alloc_failed;
|
||||||
|
|
||||||
|
/* get the timestamp for the output buffer */
|
||||||
|
timestamp = gst_adapter_prev_timestamp (dec->adapter, &distance);
|
||||||
|
|
||||||
|
/* add the amount of time taken by the distance, each frame is 20ms */
|
||||||
|
if (timestamp != -1)
|
||||||
|
timestamp += (distance / 40) * FRAME_DURATION;
|
||||||
|
|
||||||
|
GST_LOG_OBJECT (dec,
|
||||||
|
"timestamp %" GST_TIME_FORMAT ", distance %" G_GUINT64_FORMAT,
|
||||||
|
GST_TIME_ARGS (timestamp), distance);
|
||||||
|
|
||||||
|
/* get the input data for all the frames */
|
||||||
|
to_free = in_data = gst_adapter_take (dec->adapter, in_size);
|
||||||
|
out_data = GST_BUFFER_DATA (out_buf);
|
||||||
|
|
||||||
|
for (i = 0; i < num_frames; i++) {
|
||||||
|
GST_LOG_OBJECT (dec, "Decoding frame %u/%u", i, num_frames);
|
||||||
|
|
||||||
|
/* decode 40 input bytes to 640 output bytes */
|
||||||
|
decode_ret = Siren7_DecodeFrame (dec->decoder, in_data, out_data);
|
||||||
|
if (decode_ret != 0)
|
||||||
|
goto decode_error;
|
||||||
|
|
||||||
|
/* move to next frame */
|
||||||
|
out_data += 640;
|
||||||
|
in_data += 40;
|
||||||
|
}
|
||||||
|
|
||||||
|
GST_LOG_OBJECT (dec, "Finished decoding");
|
||||||
|
|
||||||
|
/* mark discont */
|
||||||
|
if (dec->discont) {
|
||||||
|
GST_BUFFER_FLAG_SET (out_buf, GST_BUFFER_FLAG_DISCONT);
|
||||||
|
dec->discont = FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
GST_BUFFER_TIMESTAMP (out_buf) = timestamp;
|
||||||
|
GST_BUFFER_DURATION (out_buf) = num_frames * FRAME_DURATION;
|
||||||
|
|
||||||
|
ret = gst_pad_push (dec->srcpad, out_buf);
|
||||||
|
|
||||||
|
done:
|
||||||
|
if (to_free)
|
||||||
|
g_free (to_free);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
GST_BUFFER_TIMESTAMP (decoded) = GST_BUFFER_TIMESTAMP (buf);
|
/* ERRORS */
|
||||||
|
alloc_failed:
|
||||||
while ((in_offset + 40 <= GST_BUFFER_SIZE (buf)) && ret == GST_FLOW_OK) {
|
{
|
||||||
|
GST_DEBUG_OBJECT (dec, "failed to pad_alloc buffer: %d (%d)", ret,
|
||||||
GST_LOG_OBJECT (dec, "Decoding frame");
|
gst_flow_get_name (ret));
|
||||||
|
goto done;
|
||||||
decode_ret = Siren7_DecodeFrame (dec->decoder,
|
}
|
||||||
GST_BUFFER_DATA (buf) + in_offset,
|
decode_error:
|
||||||
GST_BUFFER_DATA (decoded) + out_offset);
|
{
|
||||||
if (decode_ret != 0) {
|
GST_ELEMENT_ERROR (dec, STREAM, DECODE, (NULL),
|
||||||
GST_ERROR_OBJECT (dec, "Siren7_DecodeFrame returned %d", decode_ret);
|
("Error decoding frame: %d", decode_ret));
|
||||||
ret = GST_FLOW_ERROR;
|
ret = GST_FLOW_ERROR;
|
||||||
|
gst_buffer_unref (out_buf);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
in_offset += 40;
|
static GstStateChangeReturn
|
||||||
out_offset += 640;
|
gst_siren_change_state (GstElement * element, GstStateChange transition)
|
||||||
|
{
|
||||||
|
GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
|
||||||
|
GstSirenDec *dec = GST_SIREN_DEC (element);
|
||||||
|
|
||||||
|
switch (transition) {
|
||||||
|
case GST_STATE_CHANGE_READY_TO_PAUSED:
|
||||||
|
dec->discont = FALSE;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
GST_LOG_OBJECT (dec, "Finished decoding : %d", out_offset);
|
ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
|
||||||
if (out_offset != GST_BUFFER_SIZE (decoded)) {
|
|
||||||
GST_ERROR_OBJECT (dec,
|
switch (transition) {
|
||||||
"didn't decode enough : offfset (%d) != BUFFER_SIZE (%d)",
|
case GST_STATE_CHANGE_PAUSED_TO_READY:
|
||||||
out_offset, GST_BUFFER_SIZE (decoded));
|
gst_adapter_clear (dec->adapter);
|
||||||
return GST_FLOW_ERROR;
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = gst_pad_push (dec->srcpad, decoded);
|
|
||||||
|
|
||||||
gst_object_unref (dec);
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
gboolean
|
gboolean
|
||||||
gst_siren_dec_plugin_init (GstPlugin * plugin)
|
gst_siren_dec_plugin_init (GstPlugin * plugin)
|
||||||
{
|
{
|
||||||
|
|
|
@ -53,10 +53,11 @@ struct _GstSirenDec
|
||||||
/* Protected by stream lock */
|
/* Protected by stream lock */
|
||||||
SirenDecoder decoder;
|
SirenDecoder decoder;
|
||||||
|
|
||||||
|
GstAdapter *adapter;
|
||||||
|
gboolean discont;
|
||||||
|
|
||||||
GstPad *sinkpad;
|
GstPad *sinkpad;
|
||||||
GstPad *srcpad;
|
GstPad *srcpad;
|
||||||
|
|
||||||
GstCaps *srccaps;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct _GstSirenDecClass
|
struct _GstSirenDecClass
|
||||||
|
|
Loading…
Reference in a new issue