1 /*
2 * GStreamer AVTP Plugin
3 * Copyright (C) 2019 Intel Corporation
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later
9 * version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the
18 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301 USA
20 */
21
22 #include <avtp.h>
23 #include <avtp_crf.h>
24 #include <avtp_aaf.h>
25 #include <avtp_cvf.h>
26 #include <gst/check/gstcheck.h>
27 #include <gst/check/gstharness.h>
28 #include "../../../ext/avtp/gstavtpcrfutil.h"
29
30 #define STREAM_ID 0xDEADC0DEDEADC0DE
31
32 static GstHarness *
setup_harness(void)33 setup_harness (void)
34 {
35 GstHarness *h;
36
37 h = gst_harness_new_parse
38 ("avtpcrfcheck streamid=0xDEADC0DEDEADC0DE drop_invalid=1");
39
40 if (!h)
41 GST_ERROR ("Cannot create harness!");
42 gst_harness_set_src_caps_str (h, "application/x-avtp");
43 return h;
44 }
45
46 static void
fill_buffer_video_data(struct avtp_stream_pdu * pdu)47 fill_buffer_video_data (struct avtp_stream_pdu *pdu)
48 {
49 const gint DATA_LEN = sizeof (guint32) + 3;
50
51 avtp_cvf_pdu_init (pdu, AVTP_CVF_FORMAT_SUBTYPE_H264);
52 avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_STREAM_ID, STREAM_ID);
53 avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_TV, 1);
54 avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_M, 1);
55 avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_TIMESTAMP, 0);
56 avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_H264_PTV, 1);
57 avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_H264_TIMESTAMP, 0);
58 avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_STREAM_DATA_LEN, DATA_LEN);
59 }
60
61 static void
fill_buffer_audio_data(struct avtp_stream_pdu * pdu)62 fill_buffer_audio_data (struct avtp_stream_pdu *pdu)
63 {
64 const int DATA_LEN = 4;
65
66 avtp_aaf_pdu_init (pdu);
67 avtp_aaf_pdu_set (pdu, AVTP_AAF_FIELD_TV, 1);
68 avtp_aaf_pdu_set (pdu, AVTP_AAF_FIELD_STREAM_ID, 0xDEADC0DEDEADC0DE);
69 avtp_aaf_pdu_set (pdu, AVTP_AAF_FIELD_FORMAT, AVTP_AAF_FORMAT_INT_16BIT);
70 avtp_aaf_pdu_set (pdu, AVTP_AAF_FIELD_NSR, AVTP_AAF_PCM_NSR_48KHZ);
71 avtp_aaf_pdu_set (pdu, AVTP_AAF_FIELD_CHAN_PER_FRAME, 2);
72 avtp_aaf_pdu_set (pdu, AVTP_AAF_FIELD_BIT_DEPTH, 16);
73 avtp_aaf_pdu_set (pdu, AVTP_AAF_FIELD_SP, AVTP_AAF_PCM_SP_NORMAL);
74 avtp_aaf_pdu_set (pdu, AVTP_AAF_FIELD_TIMESTAMP, 0);
75 avtp_aaf_pdu_set (pdu, AVTP_AAF_FIELD_STREAM_DATA_LEN, DATA_LEN);
76 }
77
78 static GstBuffer *
create_input_buffer(GstHarness * h,guint32 subtype)79 create_input_buffer (GstHarness * h, guint32 subtype)
80 {
81 struct avtp_stream_pdu *pdu;
82 GstMapInfo info;
83 GstBuffer *buf;
84 const gint DATA_LEN = sizeof (guint32) + 3;
85
86 buf = gst_harness_create_buffer (h, sizeof (struct avtp_stream_pdu) +
87 DATA_LEN);
88
89 gst_buffer_map (buf, &info, GST_MAP_WRITE);
90 pdu = (struct avtp_stream_pdu *) info.data;
91
92 if (subtype == AVTP_SUBTYPE_AAF)
93 fill_buffer_audio_data (pdu);
94 else
95 fill_buffer_video_data (pdu);
96
97 gst_buffer_unmap (buf, &info);
98
99 return buf;
100 }
101
102 static void
set_buffer_tstamps(GstBuffer * buf,GstClockTime avtp_tstamp,GstClockTime h264_tstamp)103 set_buffer_tstamps (GstBuffer * buf, GstClockTime avtp_tstamp,
104 GstClockTime h264_tstamp)
105 {
106 struct avtp_stream_pdu *pdu;
107 GstMapInfo info;
108 guint32 type;
109 gint r;
110
111 gst_buffer_map (buf, &info, GST_MAP_WRITE);
112 pdu = (struct avtp_stream_pdu *) info.data;
113
114 r = avtp_pdu_get ((struct avtp_common_pdu *) pdu, AVTP_FIELD_SUBTYPE, &type);
115 g_assert (r == 0);
116 if (type == AVTP_SUBTYPE_AAF)
117 avtp_aaf_pdu_set (pdu, AVTP_AAF_FIELD_TIMESTAMP, avtp_tstamp);
118 else if (type == AVTP_SUBTYPE_CVF) {
119 avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_TIMESTAMP, avtp_tstamp);
120 avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_H264_TIMESTAMP, h264_tstamp);
121 }
122 gst_buffer_unmap (buf, &info);
123 }
124
125 static void
test_crf_tstamps(GstHarness * h,GstBuffer * buf,GstClockTime avtp_tstamp,GstClockTime h264_tstamp,guint expected_buffers)126 test_crf_tstamps (GstHarness * h, GstBuffer * buf, GstClockTime avtp_tstamp,
127 GstClockTime h264_tstamp, guint expected_buffers)
128 {
129 set_buffer_tstamps (buf, avtp_tstamp, h264_tstamp);
130 gst_harness_push (h, gst_buffer_copy (buf));
131 fail_unless_equals_uint64 (gst_harness_buffers_received (h),
132 expected_buffers);
133 }
134
GST_START_TEST(test_properties)135 GST_START_TEST (test_properties)
136 {
137 const guint64 streamid = 0xAABBCCDDEEFF0001;
138 const gchar *address = "01:AA:BB:CC:DD:EE";
139 const gchar *ifname = "enp1s0";
140 const gboolean drop_invalid = TRUE;
141 GstElement *element;
142 guint64 val64;
143 gboolean val;
144 gchar *str;
145
146 element = gst_check_setup_element ("avtpcrfcheck");
147
148 g_object_set (G_OBJECT (element), "ifname", ifname, NULL);
149 g_object_get (G_OBJECT (element), "ifname", &str, NULL);
150 fail_unless_equals_string (str, ifname);
151 g_free (str);
152
153 g_object_set (G_OBJECT (element), "address", address, NULL);
154 g_object_get (G_OBJECT (element), "address", &str, NULL);
155 fail_unless_equals_string (str, address);
156 g_free (str);
157
158 g_object_set (G_OBJECT (element), "streamid", streamid, NULL);
159 g_object_get (G_OBJECT (element), "streamid", &val64, NULL);
160 fail_unless (val64 == streamid);
161
162 g_object_set (G_OBJECT (element), "drop-invalid", drop_invalid, NULL);
163 g_object_get (G_OBJECT (element), "drop-invalid", &val, NULL);
164 fail_unless (val == drop_invalid);
165
166 gst_object_unref (element);
167 }
168
169 GST_END_TEST;
170
GST_START_TEST(test_crf_cvf_data)171 GST_START_TEST (test_crf_cvf_data)
172 {
173 GstAvtpCrfBase *avtpcrfbase;
174 GstBuffer *buf;
175 GstHarness *h;
176
177 h = setup_harness ();
178
179 buf = create_input_buffer (h, AVTP_SUBTYPE_CVF);
180 avtpcrfbase = (GstAvtpCrfBase *) gst_harness_find_element (h, "avtpcrfcheck");
181 avtpcrfbase->thread_data.average_period = 3300;
182 avtpcrfbase->thread_data.current_ts = 110000;
183 gst_object_unref (avtpcrfbase);
184
185 test_crf_tstamps (h, buf, 110000, 109204, 1);
186 test_crf_tstamps (h, buf, 113600, 119400, 2);
187 test_crf_tstamps (h, buf, 218000, 119400, 2);
188 test_crf_tstamps (h, buf, 218000, 102000, 2);
189
190 gst_buffer_unref (buf);
191 gst_harness_teardown (h);
192 }
193
194 GST_END_TEST;
195
GST_START_TEST(test_crf_aaf_data)196 GST_START_TEST (test_crf_aaf_data)
197 {
198 GstAvtpCrfBase *avtpcrfbase;
199 GstBuffer *buf;
200 GstHarness *h;
201
202 h = setup_harness ();
203
204 buf = create_input_buffer (h, AVTP_SUBTYPE_AAF);
205 avtpcrfbase = (GstAvtpCrfBase *) gst_harness_find_element (h, "avtpcrfcheck");
206 avtpcrfbase->thread_data.average_period = 3300;
207 avtpcrfbase->thread_data.current_ts = 110000;
208 gst_object_unref (avtpcrfbase);
209
210 test_crf_tstamps (h, buf, 113300, 0, 1);
211 test_crf_tstamps (h, buf, 112900, 0, 2);
212 test_crf_tstamps (h, buf, 210000, 0, 2);
213
214 gst_buffer_unref (buf);
215 gst_harness_teardown (h);
216 }
217
218 GST_END_TEST;
219
GST_START_TEST(test_crf_period_zero)220 GST_START_TEST (test_crf_period_zero)
221 {
222 GstAvtpCrfBase *avtpcrfbase;
223 GstBuffer *buf;
224 GstHarness *h;
225
226 h = setup_harness ();
227
228 buf = create_input_buffer (h, AVTP_SUBTYPE_CVF);
229 avtpcrfbase = (GstAvtpCrfBase *) gst_harness_find_element (h, "avtpcrfcheck");
230 avtpcrfbase->thread_data.average_period = 0.0;
231 avtpcrfbase->thread_data.current_ts = 110;
232 gst_object_unref (avtpcrfbase);
233
234 test_crf_tstamps (h, buf, 112, 110, 1);
235
236 gst_buffer_unref (buf);
237 gst_harness_teardown (h);
238 }
239
240 GST_END_TEST;
241
242 static Suite *
avtpcrfcheck_suite(void)243 avtpcrfcheck_suite (void)
244 {
245 Suite *s = suite_create ("avtpcrfcheck");
246 TCase *tc_chain = tcase_create ("general");
247
248 suite_add_tcase (s, tc_chain);
249 tcase_add_test (tc_chain, test_properties);
250 tcase_add_test (tc_chain, test_crf_cvf_data);
251 tcase_add_test (tc_chain, test_crf_aaf_data);
252 tcase_add_test (tc_chain, test_crf_period_zero);
253
254 return s;
255 }
256
257 GST_CHECK_MAIN (avtpcrfcheck);
258