diff --git a/gst/onvif/Makefile.am b/gst/onvif/Makefile.am index 9d0223bd42..2aa779bf38 100644 --- a/gst/onvif/Makefile.am +++ b/gst/onvif/Makefile.am @@ -2,7 +2,8 @@ plugin_LTLIBRARIES = libgstrtponvif.la libgstrtponvif_la_SOURCES = \ gstrtponvif.c \ - gstrtponviftimestamp.c gstrtponviftimestamp.h + gstrtponviftimestamp.c gstrtponviftimestamp.h \ + gstrtponvifparse.c gstonvifparse.h libgstrtponvif_la_CFLAGS = $(GST_PLUGINS_BAD_CFLAGS) $(GST_PLUGINS_BASE_CFLAGS) \ $(GST_BASE_CFLAGS) $(GST_CFLAGS) libgstrtponvif_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) \ diff --git a/gst/onvif/gstrtponvif.c b/gst/onvif/gstrtponvif.c index 8f24d94fb7..c6742327de 100644 --- a/gst/onvif/gstrtponvif.c +++ b/gst/onvif/gstrtponvif.c @@ -25,6 +25,7 @@ #include #include "gstrtponviftimestamp.h" +#include "gstrtponvifparse.h" static gboolean plugin_init (GstPlugin * plugin) @@ -32,6 +33,9 @@ plugin_init (GstPlugin * plugin) if (!gst_element_register (plugin, "rtponviftimestamp", GST_RANK_NONE, GST_TYPE_RTP_ONVIF_TIMESTAMP)) return FALSE; + if (!gst_element_register (plugin, "rtponvifparse", GST_RANK_NONE, + GST_TYPE_RTP_ONVIF_PARSE)) + return FALSE; return TRUE; } diff --git a/gst/onvif/gstrtponvifparse.c b/gst/onvif/gstrtponvifparse.c new file mode 100644 index 0000000000..f48ac07499 --- /dev/null +++ b/gst/onvif/gstrtponvifparse.c @@ -0,0 +1,150 @@ +/* + * gstrtponviftimestamp-parse.c + * + * Copyright (C) 2014 Axis Communications AB + * Author: Guillaume Desmottes + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include + +#include + +#include "gstrtponvifparse.h" + +static GstFlowReturn gst_rtp_onvif_parse_chain (GstPad * pad, + GstObject * parent, GstBuffer * buf); + +static GstStaticPadTemplate sink_template_factory = +GST_STATIC_PAD_TEMPLATE ("sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS ("application/x-rtp") + ); + +static GstStaticPadTemplate src_template_factory = +GST_STATIC_PAD_TEMPLATE ("src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS ("application/x-rtp") + ); + +G_DEFINE_TYPE (GstRtpOnvifParse, gst_rtp_onvif_parse, GST_TYPE_ELEMENT); + +static void +gst_rtp_onvif_parse_class_init (GstRtpOnvifParseClass * klass) +{ + GstElementClass *gstelement_class; + + gstelement_class = GST_ELEMENT_CLASS (klass); + + /* register pads */ + gst_element_class_add_pad_template (gstelement_class, + gst_static_pad_template_get (&sink_template_factory)); + gst_element_class_add_pad_template (gstelement_class, + gst_static_pad_template_get (&src_template_factory)); + + gst_element_class_set_static_metadata (gstelement_class, + "ONVIF NTP timestamps RTP extension", "Effect/RTP", + "Add absolute timestamps and flags of recorded data in a playback " + "session", "Guillaume Desmottes "); +} + +static void +gst_rtp_onvif_parse_init (GstRtpOnvifParse * self) +{ + self->sinkpad = + gst_pad_new_from_static_template (&sink_template_factory, "sink"); + gst_pad_set_chain_function (self->sinkpad, gst_rtp_onvif_parse_chain); + gst_element_add_pad (GST_ELEMENT (self), self->sinkpad); + GST_PAD_SET_PROXY_CAPS (self->sinkpad); + + self->srcpad = + gst_pad_new_from_static_template (&src_template_factory, "src"); + gst_element_add_pad (GST_ELEMENT (self), self->srcpad); +} + +#define EXTENSION_ID 0xABAC +#define EXTENSION_SIZE 3 + +static gboolean +handle_buffer (GstRtpOnvifParse * self, GstBuffer * buf) +{ + GstRTPBuffer rtp = GST_RTP_BUFFER_INIT; + guint8 *data; + guint16 bits; + guint wordlen; + guint8 flags; + /* + guint64 timestamp; + guint8 cseq; + */ + + if (!gst_rtp_buffer_map (buf, GST_MAP_READ, &rtp)) { + GST_ELEMENT_ERROR (self, STREAM, FAILED, + ("Failed to map RTP buffer"), (NULL)); + return FALSE; + } + + /* Check if the ONVIF RTP extension is present in the packet */ + if (!gst_rtp_buffer_get_extension_data (&rtp, &bits, (gpointer) & data, + &wordlen)) + goto out; + + if (bits != EXTENSION_ID || wordlen != EXTENSION_SIZE) + goto out; + + /* timestamp = GST_READ_UINT64_BE (data); TODO */ + flags = GST_READ_UINT8 (data + 8); + /* cseq = GST_READ_UINT8 (data + 9); TODO */ + + /* C */ + if (flags & (1 << 7)) + GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DELTA_UNIT); + else + GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT); + + /* E */ + /* if (flags & (1 << 6)); TODO */ + + /* D */ + if (flags & (1 << 5)) + GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT); + else + GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT); + +out: + gst_rtp_buffer_unmap (&rtp); + return TRUE; +} + +static GstFlowReturn +gst_rtp_onvif_parse_chain (GstPad * pad, GstObject * parent, GstBuffer * buf) +{ + GstRtpOnvifParse *self = GST_RTP_ONVIF_PARSE (parent); + + if (!handle_buffer (self, buf)) { + gst_buffer_unref (buf); + return GST_FLOW_ERROR; + } + + return gst_pad_push (self->srcpad, buf); +} diff --git a/gst/onvif/gstrtponvifparse.h b/gst/onvif/gstrtponvifparse.h new file mode 100644 index 0000000000..437b1abcf1 --- /dev/null +++ b/gst/onvif/gstrtponvifparse.h @@ -0,0 +1,62 @@ +/* + * gstrtponviftimestamp-parse.h + * + * Copyright (C) 2014 Axis Communications AB + * Author: Guillaume Desmottes + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + */ + +#ifndef __GST_RTP_ONVIF_PARSE_H__ +#define __GST_RTP_ONVIF_PARSE_H__ + + +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#define GST_TYPE_RTP_ONVIF_PARSE \ + (gst_rtp_onvif_parse_get_type()) +#define GST_RTP_ONVIF_PARSE(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_ONVIF_PARSE,GstRtpOnvifParse)) +#define GST_RTP_ONVIF_PARSE_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_ONVIF_PARSE,GstRtpOnvifParseClass)) +#define GST_IS_RTP_ONVIF_PARSE(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_ONVIF_PARSE)) +#define GST_IS_RTP_ONVIF_PARSE_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_ONVIF_PARSE)) + +typedef struct _GstRtpOnvifParse GstRtpOnvifParse; +typedef struct _GstRtpOnvifParseClass GstRtpOnvifParseClass; + +struct _GstRtpOnvifParse { + GstElement element; + + /* pads */ + GstPad *sinkpad,*srcpad; +}; + +struct _GstRtpOnvifParseClass { + GstElementClass parent_class; +}; + +GType gst_rtp_onvif_parse_get_type(void); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __GST_RTP_ONVIF_PARSE_H__ */ diff --git a/tests/check/elements/rtponvif.c b/tests/check/elements/rtponvif.c index 99a98e8c8e..47f3387bc5 100644 --- a/tests/check/elements/rtponvif.c +++ b/tests/check/elements/rtponvif.c @@ -326,12 +326,101 @@ GST_START_TEST (test_apply_e_bit) GST_END_TEST; +static GstElement * +setup_rtponvifparse (gboolean set_e_bit) +{ + GstElement *parse; + + GST_DEBUG ("setup_rtponvifparse"); + parse = gst_check_setup_element ("rtponvifparse"); + + setup_element (parse); + + return parse; +} + +static void +cleanup_rtponvifparse (GstElement * parse) +{ + GST_DEBUG ("cleanup_rtponvifparse"); + + cleanup_element (parse); +} + +static void +test_parse (gboolean clean_point, gboolean discont) +{ + GstElement *parse; + GstBuffer *rtp, *buf; + GstSegment segment; + + parse = setup_rtponvifparse (FALSE); + + rtp = gst_rtp_buffer_new_allocate (4, 0, 0); + buf = create_extension_buffer (rtp, clean_point, FALSE, discont); + gst_buffer_unref (rtp); + + /* stream start */ + fail_unless (gst_pad_push_event (mysrcpad, + gst_event_new_stream_start ("test"))); + + /* Push a segment */ + gst_segment_init (&segment, GST_FORMAT_TIME); + fail_unless (gst_pad_push_event (mysrcpad, gst_event_new_segment (&segment))); + + /* Push buffer */ + fail_unless (gst_pad_push (mysrcpad, buf) == GST_FLOW_OK, + "failed pushing buffer"); + + g_assert_cmpuint (g_list_length (buffers), ==, 1); + buf = buffers->data; + + if (clean_point) + g_assert (!GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT)); + else + g_assert (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT)); + + if (discont) + g_assert (GST_BUFFER_IS_DISCONT (buf)); + else + g_assert (!GST_BUFFER_IS_DISCONT (buf)); + + g_list_foreach (buffers, (GFunc) gst_mini_object_unref, NULL); + g_list_free (buffers); + buffers = NULL; + + ASSERT_OBJECT_REFCOUNT (parse, "rtponvifparse", 1); + cleanup_rtponvifparse (parse); +} + +GST_START_TEST (test_parse_no_flag) +{ + test_parse (FALSE, FALSE); +} + +GST_END_TEST; + +GST_START_TEST (test_parse_clean_point) +{ + test_parse (TRUE, FALSE); +} + +GST_END_TEST; + +GST_START_TEST (test_parse_discont) +{ + test_parse (FALSE, TRUE); +} + +GST_END_TEST; + static Suite * onviftimestamp_suite (void) { Suite *s = suite_create ("onviftimestamp"); - TCase *tc_chain = tcase_create ("apply"); + TCase *tc_chain; + tc_chain = tcase_create ("apply"); suite_add_tcase (s, tc_chain); tcase_add_test (tc_chain, test_apply_discont); tcase_add_test (tc_chain, test_apply_not_discont); @@ -339,6 +428,12 @@ onviftimestamp_suite (void) tcase_add_test (tc_chain, test_apply_no_e_bit); tcase_add_test (tc_chain, test_apply_e_bit); + tc_chain = tcase_create ("parse"); + suite_add_tcase (s, tc_chain); + tcase_add_test (tc_chain, test_parse_no_flag); + tcase_add_test (tc_chain, test_parse_clean_point); + tcase_add_test (tc_chain, test_parse_discont); + return s; }