gst/gdp/gstgdppay.c: add crc-header and crc-payload properties don't error out on some things that are recoverable

Original commit message from CVS:
* gst/gdp/gstgdppay.c: (gst_gdp_pay_class_init),
(gst_gdp_pay_init), (gst_gdp_buffer_from_caps),
(gst_gdp_pay_buffer_from_buffer), (gst_gdp_buffer_from_event),
(gst_gdp_pay_reset_streamheader), (gst_gdp_pay_chain),
(gst_gdp_pay_sink_event), (gst_gdp_pay_set_property),
(gst_gdp_pay_get_property):
add crc-header and crc-payload properties
don't error out on some things that are recoverable
* tests/check/elements/gdppay.c: (GST_START_TEST), (gdppay_suite):
add test for crc
This commit is contained in:
Thomas Vander Stichele 2006-06-02 10:28:32 +00:00 committed by Tim-Philipp Müller
parent 1f3890d483
commit ad556efb2a
2 changed files with 195 additions and 20 deletions

View file

@ -19,6 +19,7 @@
/** /**
* SECTION:element-gdppay * SECTION:element-gdppay
* @see_also: gdpdepay
* *
* <refsect2> * <refsect2>
* <para> * <para>
@ -43,12 +44,6 @@ GST_ELEMENT_DETAILS ("GDP Payloader",
"Payloads GStreamer Data Protocol buffers", "Payloads GStreamer Data Protocol buffers",
"Thomas Vander Stichele <thomas at apestaart dot org>"); "Thomas Vander Stichele <thomas at apestaart dot org>");
enum
{
PROP_0,
/* FILL ME */
};
static GstStaticPadTemplate gdp_pay_sink_template = static GstStaticPadTemplate gdp_pay_sink_template =
GST_STATIC_PAD_TEMPLATE ("sink", GST_STATIC_PAD_TEMPLATE ("sink",
GST_PAD_SINK, GST_PAD_SINK,
@ -64,6 +59,16 @@ GST_STATIC_PAD_TEMPLATE ("src",
GST_DEBUG_CATEGORY (gst_gdp_pay_debug); GST_DEBUG_CATEGORY (gst_gdp_pay_debug);
#define GST_CAT_DEFAULT gst_gdp_pay_debug #define GST_CAT_DEFAULT gst_gdp_pay_debug
#define DEFAULT_CRC_HEADER TRUE
#define DEFAULT_CRC_PAYLOAD FALSE
enum
{
PROP_0,
PROP_CRC_HEADER,
PROP_CRC_PAYLOAD,
};
#define _do_init(x) \ #define _do_init(x) \
GST_DEBUG_CATEGORY_INIT (gst_gdp_pay_debug, "gdppay", 0, \ GST_DEBUG_CATEGORY_INIT (gst_gdp_pay_debug, "gdppay", 0, \
"GDP payloader"); "GDP payloader");
@ -76,6 +81,11 @@ static gboolean gst_gdp_pay_sink_event (GstPad * pad, GstEvent * event);
static GstStateChangeReturn gst_gdp_pay_change_state (GstElement * static GstStateChangeReturn gst_gdp_pay_change_state (GstElement *
element, GstStateChange transition); element, GstStateChange transition);
static void gst_gdp_pay_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec);
static void gst_gdp_pay_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
static void gst_gdp_pay_dispose (GObject * gobject); static void gst_gdp_pay_dispose (GObject * gobject);
static void static void
@ -102,8 +112,19 @@ gst_gdp_pay_class_init (GstGDPPayClass * klass)
parent_class = g_type_class_peek_parent (klass); parent_class = g_type_class_peek_parent (klass);
gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_gdp_pay_set_property);
gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_gdp_pay_get_property);
gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_gdp_pay_dispose); gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_gdp_pay_dispose);
gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_gdp_pay_change_state); gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_gdp_pay_change_state);
g_object_class_install_property (gobject_class, PROP_CRC_HEADER,
g_param_spec_boolean ("crc-header", "CRC Header",
"Calculate and store a CRC checksum on the header",
DEFAULT_CRC_HEADER, G_PARAM_READWRITE));
g_object_class_install_property (gobject_class, PROP_CRC_PAYLOAD,
g_param_spec_boolean ("crc-payload", "CRC Payload",
"Calculate and store a CRC checksum on the payload",
DEFAULT_CRC_PAYLOAD, G_PARAM_READWRITE));
} }
static void static void
@ -122,6 +143,10 @@ gst_gdp_pay_init (GstGDPPay * gdppay, GstGDPPayClass * g_class)
gst_element_add_pad (GST_ELEMENT (gdppay), gdppay->srcpad); gst_element_add_pad (GST_ELEMENT (gdppay), gdppay->srcpad);
gdppay->offset = 0; gdppay->offset = 0;
gdppay->crc_header = DEFAULT_CRC_HEADER;
gdppay->crc_payload = DEFAULT_CRC_PAYLOAD;
gdppay->header_flag = gdppay->crc_header | gdppay->crc_payload;
} }
static void static void
@ -157,7 +182,8 @@ gst_gdp_buffer_from_caps (GstGDPPay * this, GstCaps * caps)
guint8 *header, *payload; guint8 *header, *payload;
guint len; guint len;
if (!gst_dp_packet_from_caps (caps, 0, &len, &header, &payload)) { if (!gst_dp_packet_from_caps (caps, this->header_flag, &len, &header,
&payload)) {
GST_WARNING_OBJECT (this, "could not create GDP header from caps"); GST_WARNING_OBJECT (this, "could not create GDP header from caps");
return NULL; return NULL;
} }
@ -182,7 +208,7 @@ gst_gdp_pay_buffer_from_buffer (GstGDPPay * this, GstBuffer * buffer)
guint8 *header; guint8 *header;
guint len; guint len;
if (!gst_dp_header_from_buffer (buffer, 0, &len, &header)) { if (!gst_dp_header_from_buffer (buffer, this->header_flag, &len, &header)) {
GST_WARNING_OBJECT (this, "could not create GDP header from buffer"); GST_WARNING_OBJECT (this, "could not create GDP header from buffer");
return NULL; return NULL;
} }
@ -205,8 +231,10 @@ gst_gdp_buffer_from_event (GstGDPPay * this, GstEvent * event)
guint8 *header, *payload; guint8 *header, *payload;
guint len; guint len;
if (!gst_dp_packet_from_event (event, 0, &len, &header, &payload)) { if (!gst_dp_packet_from_event (event, this->header_flag, &len, &header,
GST_WARNING_OBJECT (this, "could not create GDP header from event"); &payload)) {
GST_WARNING_OBJECT (this, "could not create GDP header from event %s (%d)",
gst_event_type_get_name (event->type), event->type);
return NULL; return NULL;
} }
@ -270,7 +298,7 @@ gst_gdp_pay_reset_streamheader (GstGDPPay * this)
sh = gst_structure_get_value (structure, "streamheader"); sh = gst_structure_get_value (structure, "streamheader");
buffers = g_value_peek_pointer (sh); buffers = g_value_peek_pointer (sh);
GST_DEBUG_OBJECT (this, GST_DEBUG_OBJECT (this,
"Need to serialize %d incoming streamheader buffers on our streamheader", "Need to serialize %d incoming streamheader buffers on ours",
buffers->len); buffers->len);
for (i = 0; i < buffers->len; ++i) { for (i = 0; i < buffers->len; ++i) {
GValue *bufval; GValue *bufval;
@ -390,18 +418,24 @@ gst_gdp_pay_chain (GstPad * pad, GstBuffer * buffer)
outbuffer = gst_gdp_buffer_from_event (this, event); outbuffer = gst_gdp_buffer_from_event (this, event);
gst_event_unref (event); gst_event_unref (event);
/* GDP 0.2 doesn't know about new-segment, so this is not fatal */
if (!outbuffer) { if (!outbuffer) {
GST_ELEMENT_ERROR (this, STREAM, ENCODE, (NULL), GST_ELEMENT_WARNING (this, STREAM, ENCODE, (NULL),
("Could not create GDP buffer from new segment event")); ("Could not create GDP buffer from new segment event"));
/*
ret = GST_FLOW_ERROR; ret = GST_FLOW_ERROR;
goto done; goto done;
} */
} else {
gst_gdp_stamp_buffer (this, outbuffer); gst_gdp_stamp_buffer (this, outbuffer);
GST_BUFFER_TIMESTAMP (outbuffer) = GST_BUFFER_TIMESTAMP (buffer); GST_BUFFER_TIMESTAMP (outbuffer) = GST_BUFFER_TIMESTAMP (buffer);
GST_BUFFER_DURATION (outbuffer) = 0; GST_BUFFER_DURATION (outbuffer) = 0;
GST_DEBUG_OBJECT (this, "Storing buffer %p as new_segment_buf",
outbuffer);
this->new_segment_buf = outbuffer; this->new_segment_buf = outbuffer;
} }
}
/* make sure we've received caps before */ /* make sure we've received caps before */
caps = gst_buffer_get_caps (buffer); caps = gst_buffer_get_caps (buffer);
@ -464,11 +498,14 @@ gst_gdp_pay_sink_event (GstPad * pad, GstEvent * event)
GstFlowReturn flowret; GstFlowReturn flowret;
gboolean ret = TRUE; gboolean ret = TRUE;
GST_DEBUG_OBJECT (this, "received event %s (%d)",
gst_event_type_get_name (event->type), event->type);
/* now turn the event into a buffer */ /* now turn the event into a buffer */
outbuffer = gst_gdp_buffer_from_event (this, event); outbuffer = gst_gdp_buffer_from_event (this, event);
if (!outbuffer) { if (!outbuffer) {
GST_ELEMENT_ERROR (this, STREAM, ENCODE, (NULL), GST_ELEMENT_WARNING (this, STREAM, ENCODE, (NULL),
("Could not create GDP buffer from event")); ("Could not create GDP buffer from received event"));
ret = FALSE; ret = FALSE;
goto done; goto done;
} }
@ -479,9 +516,11 @@ gst_gdp_pay_sink_event (GstPad * pad, GstEvent * event)
/* if we got a new segment, we should put it on our streamheader, /* if we got a new segment, we should put it on our streamheader,
* and not send it on */ * and not send it on */
if (GST_EVENT_TYPE (event) == GST_EVENT_NEWSEGMENT) { if (GST_EVENT_TYPE (event) == GST_EVENT_NEWSEGMENT) {
GST_DEBUG_OBJECT (this, "received new_segment event");
if (this->new_segment_buf) { if (this->new_segment_buf) {
gst_buffer_unref (this->new_segment_buf); gst_buffer_unref (this->new_segment_buf);
} }
GST_DEBUG_OBJECT (this, "Storing buffer %p as new_segment_buf", outbuffer);
this->new_segment_buf = outbuffer; this->new_segment_buf = outbuffer;
gst_gdp_pay_reset_streamheader (this); gst_gdp_pay_reset_streamheader (this);
} else { } else {
@ -506,6 +545,52 @@ done:
return ret; return ret;
} }
static void
gst_gdp_pay_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec)
{
GstGDPPay *this;
g_return_if_fail (GST_IS_GDP_PAY (object));
this = GST_GDP_PAY (object);
switch (prop_id) {
case PROP_CRC_HEADER:
this->crc_header = g_value_get_boolean (value);
this->header_flag = this->crc_header | this->crc_payload;
break;
case PROP_CRC_PAYLOAD:
this->crc_payload = g_value_get_boolean (value);
this->header_flag = this->crc_header | this->crc_payload;
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gst_gdp_pay_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec)
{
GstGDPPay *this;
g_return_if_fail (GST_IS_GDP_PAY (object));
this = GST_GDP_PAY (object);
switch (prop_id) {
case PROP_CRC_HEADER:
g_value_set_boolean (value, this->crc_header);
break;
case PROP_CRC_PAYLOAD:
g_value_set_boolean (value, this->crc_payload);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static GstStateChangeReturn static GstStateChangeReturn
gst_gdp_pay_change_state (GstElement * element, GstStateChange transition) gst_gdp_pay_change_state (GstElement * element, GstStateChange transition)
{ {

View file

@ -86,7 +86,6 @@ cleanup_gdppay (GstElement * gdppay)
gst_check_teardown_element (gdppay); gst_check_teardown_element (gdppay);
} }
GST_START_TEST (test_audio) GST_START_TEST (test_audio)
{ {
GstCaps *caps; GstCaps *caps;
@ -448,6 +447,96 @@ GST_START_TEST (test_first_no_new_segment)
GST_END_TEST; GST_END_TEST;
GST_START_TEST (test_crc)
{
GstCaps *caps;
GstElement *gdppay;
GstBuffer *inbuffer, *outbuffer;
GstEvent *event;
gchar *caps_string;
gint length;
guint16 crc_calculated, crc_read;
gdppay = setup_gdppay ();
g_object_set (gdppay, "crc-header", TRUE, NULL);
fail_unless (gst_element_set_state (gdppay,
GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
"could not set to playing");
GST_DEBUG ("new segment");
event =
gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_TIME, 0, GST_SECOND, 0);
fail_unless (gst_pad_push_event (mysrcpad, event));
/* no buffer should be pushed yet, waiting for caps */
fail_unless_equals_int (g_list_length (buffers), 0);
GST_DEBUG ("first buffer");
inbuffer = gst_buffer_new_and_alloc (4);
caps = gst_caps_from_string (AUDIO_CAPS_STRING);
gst_buffer_set_caps (inbuffer, caps);
caps_string = gst_caps_to_string (caps);
ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
/* pushing gives away my reference */
fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
/* we should have three buffers now */
fail_unless_equals_int (g_list_length (buffers), 3);
/* first buffer is the serialized new_segment event;
* the element also holds a ref to it */
fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
buffers = g_list_remove (buffers, outbuffer);
ASSERT_BUFFER_REFCOUNT (outbuffer, "outbuffer", 2);
/* verify the header checksum */
/* CRC's start at 58 in the header */
crc_calculated = gst_dp_crc (GST_BUFFER_DATA (outbuffer), 58);
crc_read = GST_READ_UINT16_BE (GST_BUFFER_DATA (outbuffer) + 58);
fail_unless_equals_int (crc_calculated, crc_read);
/* change a byte in the header and verify that the checksum now fails */
GST_BUFFER_DATA (outbuffer)[0] = 0xff;
crc_calculated = gst_dp_crc (GST_BUFFER_DATA (outbuffer), 58);
fail_if (crc_calculated == crc_read,
"Introducing a byte error in the header should make the checksum fail");
gst_buffer_unref (outbuffer);
/* second buffer is the serialized caps;
* the element also holds a ref to it */
fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
buffers = g_list_remove (buffers, outbuffer);
ASSERT_BUFFER_REFCOUNT (outbuffer, "outbuffer", 2);
length = GST_DP_HEADER_LENGTH + (strlen (caps_string) + 1);
fail_unless_equals_int (GST_BUFFER_SIZE (outbuffer), length);
gst_buffer_unref (outbuffer);
/* the third buffer is the GDP buffer for our pushed buffer */
fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
buffers = g_list_remove (buffers, outbuffer);
ASSERT_BUFFER_REFCOUNT (outbuffer, "outbuffer", 1);
length = GST_DP_HEADER_LENGTH + 4;
fail_unless_equals_int (GST_BUFFER_SIZE (outbuffer), length);
gst_buffer_unref (outbuffer);
fail_unless (gst_element_set_state (gdppay,
GST_STATE_NULL) == GST_STATE_CHANGE_SUCCESS, "could not set to null");
gst_caps_unref (caps);
g_free (caps_string);
g_list_foreach (buffers, (GFunc) gst_mini_object_unref, NULL);
g_list_free (buffers);
buffers = NULL;
ASSERT_OBJECT_REFCOUNT (gdppay, "gdppay", 1);
gst_object_unref (gdppay);
}
GST_END_TEST;
Suite * Suite *
gdppay_suite (void) gdppay_suite (void)
@ -460,6 +549,7 @@ gdppay_suite (void)
tcase_add_test (tc_chain, test_first_no_caps); tcase_add_test (tc_chain, test_first_no_caps);
tcase_add_test (tc_chain, test_first_no_new_segment); tcase_add_test (tc_chain, test_first_no_new_segment);
tcase_add_test (tc_chain, test_streamheader); tcase_add_test (tc_chain, test_streamheader);
tcase_add_test (tc_chain, test_crc);
return s; return s;
} }