1 /*
2 * onviftimestamp.c
3 *
4 * Copyright (C) 2014 Axis Communications AB
5 * Author: Guillaume Desmottes <guillaume.desmottes@collabora.com>
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include <gst/check/gstcheck.h>
22 #include <gst/rtp/gstrtpbuffer.h>
23
24 /* For ease of programming we use globals to keep refs for our floating
25 * src and sink pads we create; otherwise we always have to do get_pad,
26 * get_peer, and then remove references in every test function */
27 static GstPad *mysrcpad, *mysinkpad;
28
29 static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
30 GST_PAD_SINK,
31 GST_PAD_ALWAYS,
32 GST_STATIC_CAPS ("application/x-rtp")
33 );
34 static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
35 GST_PAD_SRC,
36 GST_PAD_ALWAYS,
37 GST_STATIC_CAPS ("application/x-rtp")
38 );
39
40 #define NTP_OFFSET (guint64) 1245
41 #define TIMESTAMP 42
42
43 static void
setup_element(GstElement * element)44 setup_element (GstElement * element)
45 {
46 mysrcpad = gst_check_setup_src_pad (element, &srctemplate);
47 mysinkpad = gst_check_setup_sink_pad (element, &sinktemplate);
48 gst_pad_set_active (mysrcpad, TRUE);
49 gst_pad_set_active (mysinkpad, TRUE);
50
51 fail_unless (gst_element_set_state (element,
52 GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
53 "could not set to playing");
54 }
55
56 static void
cleanup_element(GstElement * element)57 cleanup_element (GstElement * element)
58 {
59 fail_unless (gst_element_set_state (element,
60 GST_STATE_NULL) == GST_STATE_CHANGE_SUCCESS, "could not set to null");
61
62 gst_pad_set_active (mysrcpad, FALSE);
63 if (mysinkpad)
64 gst_pad_set_active (mysinkpad, FALSE);
65 gst_check_teardown_src_pad (element);
66 gst_check_teardown_sink_pad (element);
67 gst_check_teardown_element (element);
68 mysrcpad = NULL;
69 mysinkpad = NULL;
70 }
71
72 static guint64
convert_to_ntp(guint64 t)73 convert_to_ntp (guint64 t)
74 {
75 guint64 ntptime;
76
77 /* convert to NTP time. upper 32 bits should contain the seconds
78 * and the lower 32 bits, the fractions of a second. */
79 ntptime = gst_util_uint64_scale (t, (G_GINT64_CONSTANT (1) << 32),
80 GST_SECOND);
81
82 return ntptime;
83 }
84
85 /* Create a copy of @buffer_in having the RTP extension */
86 static GstBuffer *
create_extension_buffer(GstBuffer * buffer_in,gboolean clean_point,gboolean end_contiguous,gboolean discont)87 create_extension_buffer (GstBuffer * buffer_in, gboolean clean_point,
88 gboolean end_contiguous, gboolean discont)
89 {
90 GstBuffer *buffer_out;
91 GstRTPBuffer rtpbuffer_out = GST_RTP_BUFFER_INIT;
92 guint8 *data;
93 guint8 flags = 0;
94
95 buffer_out = gst_buffer_copy (buffer_in);
96
97 fail_unless (gst_rtp_buffer_map (buffer_out, GST_MAP_READWRITE,
98 &rtpbuffer_out));
99
100 /* extension */
101 gst_rtp_buffer_set_extension_data (&rtpbuffer_out, 0xABAC, 3);
102 fail_unless (gst_rtp_buffer_get_extension (&rtpbuffer_out));
103 gst_rtp_buffer_get_extension_data (&rtpbuffer_out, NULL, (gpointer) & data,
104 NULL);
105
106 /* NTP timestamp */
107 GST_WRITE_UINT64_BE (data, convert_to_ntp (buffer_in->pts + NTP_OFFSET));
108
109 /* C E D mbz */
110 if (clean_point)
111 flags |= (1 << 7);
112 if (end_contiguous)
113 flags |= (1 << 6);
114 if (discont)
115 flags |= (1 << 5);
116
117 GST_WRITE_UINT8 (data + 8, flags);
118
119 /* CSeq */
120 GST_WRITE_UINT8 (data + 9, 0x78);
121
122 memset (data + 10, 0, 4);
123
124 gst_rtp_buffer_unmap (&rtpbuffer_out);
125
126 return buffer_out;
127 }
128
129 static GstElement *
setup_rtponvifparse(gboolean set_e_bit)130 setup_rtponvifparse (gboolean set_e_bit)
131 {
132 GstElement *parse;
133
134 GST_DEBUG ("setup_rtponvifparse");
135 parse = gst_check_setup_element ("rtponvifparse");
136
137 setup_element (parse);
138
139 return parse;
140 }
141
142 static void
cleanup_rtponvifparse(GstElement * parse)143 cleanup_rtponvifparse (GstElement * parse)
144 {
145 GST_DEBUG ("cleanup_rtponvifparse");
146
147 cleanup_element (parse);
148 }
149
150 static void
test_parse(gboolean clean_point,gboolean discont)151 test_parse (gboolean clean_point, gboolean discont)
152 {
153 GstElement *parse;
154 GstBuffer *rtp, *buf;
155 GstSegment segment;
156
157 parse = setup_rtponvifparse (FALSE);
158
159 rtp = gst_rtp_buffer_new_allocate (4, 0, 0);
160 buf = create_extension_buffer (rtp, clean_point, FALSE, discont);
161 gst_buffer_unref (rtp);
162
163 /* stream start */
164 fail_unless (gst_pad_push_event (mysrcpad,
165 gst_event_new_stream_start ("test")));
166
167 /* Push a segment */
168 gst_segment_init (&segment, GST_FORMAT_TIME);
169 fail_unless (gst_pad_push_event (mysrcpad, gst_event_new_segment (&segment)));
170
171 /* Push buffer */
172 fail_unless (gst_pad_push (mysrcpad, buf) == GST_FLOW_OK,
173 "failed pushing buffer");
174
175 g_assert_cmpuint (g_list_length (buffers), ==, 1);
176 buf = buffers->data;
177
178 if (clean_point)
179 g_assert (!GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT));
180 else
181 g_assert (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT));
182
183 if (discont)
184 g_assert (GST_BUFFER_IS_DISCONT (buf));
185 else
186 g_assert (!GST_BUFFER_IS_DISCONT (buf));
187
188 g_list_foreach (buffers, (GFunc) gst_mini_object_unref, NULL);
189 g_list_free (buffers);
190 buffers = NULL;
191
192 ASSERT_OBJECT_REFCOUNT (parse, "rtponvifparse", 1);
193 cleanup_rtponvifparse (parse);
194 }
195
GST_START_TEST(test_parse_no_flag)196 GST_START_TEST (test_parse_no_flag)
197 {
198 test_parse (FALSE, FALSE);
199 }
200
201 GST_END_TEST;
202
GST_START_TEST(test_parse_clean_point)203 GST_START_TEST (test_parse_clean_point)
204 {
205 test_parse (TRUE, FALSE);
206 }
207
208 GST_END_TEST;
209
GST_START_TEST(test_parse_discont)210 GST_START_TEST (test_parse_discont)
211 {
212 test_parse (FALSE, TRUE);
213 }
214
215 GST_END_TEST;
216
217 static Suite *
onviftimestamp_suite(void)218 onviftimestamp_suite (void)
219 {
220 Suite *s = suite_create ("onviftimestamp");
221 TCase *tc_chain;
222
223 tc_chain = tcase_create ("parse");
224 suite_add_tcase (s, tc_chain);
225 tcase_add_test (tc_chain, test_parse_no_flag);
226 tcase_add_test (tc_chain, test_parse_clean_point);
227 tcase_add_test (tc_chain, test_parse_discont);
228
229 return s;
230 }
231
232 GST_CHECK_MAIN (onviftimestamp);
233