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 <gst/check/gstcheck.h>
23 #include <gst/check/gstharness.h>
24
25 #include <avtp.h>
26 #include <avtp_cvf.h>
27
28 #define AVTP_CVF_H264_HEADER_SIZE (sizeof(struct avtp_stream_pdu) + sizeof(guint32))
29 #define STREAM_ID 0xAABBCCDDEEFF0001
30
31 /* Simple codec data, with only the NAL size len, no SPS/PPS. */
32 static GstCaps *
generate_caps(guint8 nal_size_len)33 generate_caps (guint8 nal_size_len)
34 {
35 GstBuffer *codec_data;
36 GstMapInfo map;
37 GstCaps *caps;
38
39 /* 7 is the minimal codec_data size, when no SPS/PPS is sent */
40 codec_data = gst_buffer_new_allocate (NULL, 7, NULL);
41 gst_buffer_map (codec_data, &map, GST_MAP_READWRITE);
42
43 memset (map.data, 0, map.size);
44 map.data[0] = 1; /* version */
45 map.data[4] = (nal_size_len - 1) | 0xfc; /* Other 6 bits are 1 */
46 map.data[5] = 0xe0; /* first 3 bits are 1 */
47
48 gst_buffer_unmap (codec_data, &map);
49
50 caps = gst_caps_new_simple ("video/x-h264",
51 "stream-format", G_TYPE_STRING, "avc",
52 "alignment", G_TYPE_STRING, "au",
53 "codec_data", GST_TYPE_BUFFER, codec_data, NULL);
54 gst_buffer_unref (codec_data);
55
56 return caps;
57 }
58
59 static void
fill(guint8 * buf,gsize size)60 fill (guint8 * buf, gsize size)
61 {
62 guint8 i = 0;
63
64 while (size--)
65 *buf++ = i++;
66 }
67
68 static gboolean
check_nal_filling(GstBuffer * buffer,guint8 first)69 check_nal_filling (GstBuffer * buffer, guint8 first)
70 {
71 GstMapInfo map;
72 gint i;
73 gsize offset = AVTP_CVF_H264_HEADER_SIZE + 1;
74 gboolean result = TRUE;
75
76 gst_buffer_map (buffer, &map, GST_MAP_READ);
77 if ((map.data[AVTP_CVF_H264_HEADER_SIZE] & 0x1f) == 28)
78 offset++; /* Fragmented NALs have 2 bytes header */
79
80 for (i = offset; i < map.size; i++) {
81 if (map.data[i] != first++) {
82 result = FALSE;
83 break;
84 }
85 }
86
87 gst_buffer_unmap (buffer, &map);
88
89 return result;
90 }
91
92 static void
add_nal(GstBuffer * buffer,gsize size,guint type,gsize offset)93 add_nal (GstBuffer * buffer, gsize size, guint type, gsize offset)
94 {
95 GstMapInfo map;
96
97 gst_buffer_map (buffer, &map, GST_MAP_READWRITE);
98
99 map.data[offset] = map.data[offset + 1] = 0;
100 map.data[offset + 2] = size >> 8;
101 map.data[offset + 3] = size & 0xff;
102 map.data[offset + 4] = type & 0x1f;
103 fill (&map.data[offset + 5], size - 1);
104
105 gst_buffer_unmap (buffer, &map);
106 }
107
108 /* This function assumes that NAL size len is 2 */
109 static void
add_nal_2(GstBuffer * buffer,gsize size,guint type,gsize offset)110 add_nal_2 (GstBuffer * buffer, gsize size, guint type, gsize offset)
111 {
112 GstMapInfo map;
113
114 gst_buffer_map (buffer, &map, GST_MAP_READWRITE);
115
116 map.data[offset] = size >> 8;
117 map.data[offset + 1] = size & 0xff;
118 map.data[offset + 2] = type & 0x1f;
119 fill (&map.data[offset + 3], size - 1);
120
121 gst_buffer_unmap (buffer, &map);
122 }
123
124 static gboolean
compare_h264_avtpdu(struct avtp_stream_pdu * pdu,GstBuffer * buffer)125 compare_h264_avtpdu (struct avtp_stream_pdu *pdu, GstBuffer * buffer)
126 {
127 GstMapInfo map;
128 gboolean result;
129
130 gst_buffer_map (buffer, &map, GST_MAP_READ);
131 /* buffer must have at least the header size */
132 if (map.size < AVTP_CVF_H264_HEADER_SIZE)
133 return FALSE;
134
135 result = memcmp (map.data, pdu, AVTP_CVF_H264_HEADER_SIZE) == 0;
136
137 gst_buffer_unmap (buffer, &map);
138
139 return result;
140 }
141
GST_START_TEST(test_payloader_spread_ts)142 GST_START_TEST (test_payloader_spread_ts)
143 {
144 GstHarness *h;
145 GstBuffer *in, *out;
146 gint i, total_fragments, max_interval_frames;
147 guint64 first_tx_time, final_dts, measurement_interval = 250000;
148
149 /* Create the harness for the avtpcvfpay */
150 h = gst_harness_new_parse
151 ("avtpcvfpay streamid=0xAABBCCDDEEFF0001 mtt=2000000 tu=125000 processing-deadline=0 mtu=128 measurement-interval=250000 max-interval-frames=3");
152 gst_harness_set_src_caps (h, generate_caps (4));
153
154 /* A 980 bytes NAL with mtu=128 should generate 10 fragments */
155 in = gst_harness_create_buffer (h, 980 + 4);
156 add_nal (in, 980, 7, 0);
157 GST_BUFFER_DTS (in) = final_dts = 1000000;
158 GST_BUFFER_PTS (in) = 2000000;
159
160 /* We now push the buffer, and check if we got ten from the avtpcvfpay */
161 gst_harness_push (h, in);
162 fail_unless_equals_int (gst_harness_buffers_received (h), 10);
163
164 /* Using max-interval-frames=3, we'll need 4 measurement intervals to send
165 * all fragments, with last one just about current DTS, and others
166 * progressively before that.
167 *
168 * So we should have something like:
169 *
170 * | 1st | 2nd | 3rd | 4th | Intervals
171 * | 1 2 3 | 4 5 6 | 7 8 9 | 10 | AVTPDUs in each interval (sharing same DTS/PTS)
172 *
173 * And PTS/DTS should increment by a
174 * measurement-interval / max-interval-frames for each AVTPDU.
175 */
176 i = 0;
177 total_fragments = 10;
178 max_interval_frames = 3;
179 first_tx_time =
180 final_dts -
181 (measurement_interval / max_interval_frames) * (total_fragments - 1);
182 for (i = 0; i < 10; i++) {
183 out = gst_harness_pull (h);
184 fail_unless_equals_uint64 (GST_BUFFER_DTS (out), first_tx_time);
185 gst_buffer_unref (out);
186
187 first_tx_time += measurement_interval / max_interval_frames;
188 }
189
190
191 gst_harness_teardown (h);
192 }
193
194 GST_END_TEST;
195
GST_START_TEST(test_payloader_downstream_eos)196 GST_START_TEST (test_payloader_downstream_eos)
197 {
198 GstHarness *h;
199 GstBuffer *in;
200
201 /* Create the harness for the avtpcvfpay */
202 h = gst_harness_new_parse
203 ("avtpcvfpay streamid=0xAABBCCDDEEFF0001 mtt=1000000 tu=1000000 processing-deadline=0 ! fakesink num-buffers=1");
204 gst_harness_set_src_caps (h, generate_caps (4));
205
206 /* Buffer must have the nal len (4 bytes) and the nal (4 bytes) */
207 in = gst_harness_create_buffer (h, 8);
208 add_nal (in, 4, 1, 0);
209 GST_BUFFER_DTS (in) = 1000000;
210 GST_BUFFER_PTS (in) = 2000000;
211
212 fail_unless_equals_int (gst_harness_push (h, in), GST_FLOW_EOS);
213
214 gst_harness_teardown (h);
215 }
216
217 GST_END_TEST;
218
GST_START_TEST(test_payloader_zero_sized_nal)219 GST_START_TEST (test_payloader_zero_sized_nal)
220 {
221 GstHarness *h;
222 GstBuffer *in;
223 GstMapInfo map;
224
225 /* Create the harness for the avtpcvfpay */
226 h = gst_harness_new_parse
227 ("avtpcvfpay streamid=0xAABBCCDDEEFF0001 mtt=1000000 tu=1000000 processing-deadline=0");
228 gst_harness_set_src_caps (h, generate_caps (4));
229
230 /* We have the buffer with the nal size (4 bytes) and the nal (4 bytes), but
231 * nal size will be zero */
232 in = gst_harness_create_buffer (h, 8);
233 GST_BUFFER_DTS (in) = 1000000;
234 GST_BUFFER_PTS (in) = 2000000;
235
236 gst_buffer_map (in, &map, GST_MAP_READWRITE);
237 map.data[0] = map.data[1] = map.data[2] = map.data[3] = 0; /* Set NAL size to 0 */
238 map.data[4] = 1; /* Some dummy vcl NAL type */
239 gst_buffer_unmap (in, &map);
240
241 gst_harness_push (h, in);
242
243 /* No buffer shuld come out */
244 fail_unless_equals_int (gst_harness_buffers_received (h), 0);
245
246 gst_harness_teardown (h);
247 }
248
249 GST_END_TEST;
250
GST_START_TEST(test_payloader_no_codec_data)251 GST_START_TEST (test_payloader_no_codec_data)
252 {
253 GstHarness *h;
254 GstCaps *caps;
255 GstBuffer *in;
256
257 /* Caps without codec_data */
258 caps = gst_caps_new_simple ("video/x-h264",
259 "stream-format", G_TYPE_STRING, "avc",
260 "alignment", G_TYPE_STRING, "au", NULL);
261
262 /* Create the harness for the avtpcvfpay */
263 h = gst_harness_new_parse
264 ("avtpcvfpay streamid=0xAABBCCDDEEFF0001 mtt=1000000 tu=1000000 processing-deadline=0");
265 gst_harness_set_src_caps (h, caps);
266
267 /* No buffer should come out when we send input */
268 in = gst_harness_create_buffer (h, 8);
269 add_nal (in, 4, 1, 0);
270 GST_BUFFER_DTS (in) = 1000000;
271 GST_BUFFER_PTS (in) = 2000000;
272
273 gst_harness_push (h, in);
274 fail_unless_equals_int (gst_harness_buffers_received (h), 0);
275
276 gst_harness_teardown (h);
277 }
278
279 GST_END_TEST;
280
GST_START_TEST(test_payloader_invalid_caps)281 GST_START_TEST (test_payloader_invalid_caps)
282 {
283 GstBuffer *codec_data;
284 GstElement *element;
285 GstPad *sinkpad;
286 GstMapInfo map;
287 GstCaps *caps;
288 GstHarness *h;
289
290 /* 7 is the minimal codec_data size, when no SPS/PPS is sent */
291 codec_data = gst_buffer_new_allocate (NULL, 7, NULL);
292 gst_buffer_map (codec_data, &map, GST_MAP_READWRITE);
293
294 memset (map.data, 0, map.size);
295 map.data[0] = 0; /* version */
296 map.data[4] = 0x03 | 0xfc; /* Other 6 bits are 1 */
297 map.data[5] = 0xe0; /* first 3 bits are 1 */
298
299 gst_buffer_unmap (codec_data, &map);
300
301 caps = gst_caps_new_simple ("video/x-h264",
302 "stream-format", G_TYPE_STRING, "avc",
303 "alignment", G_TYPE_STRING, "au",
304 "codec_data", GST_TYPE_BUFFER, codec_data, NULL);
305 gst_buffer_unref (codec_data);
306
307 /* Create the harness for the avtpcvfpay */
308 h = gst_harness_new_parse
309 ("avtpcvfpay streamid=0xAABBCCDDEEFF0001 mtt=1000000 tu=1000000");
310 element = gst_harness_find_element (h, "avtpcvfpay");
311 sinkpad = gst_element_get_static_pad (element, "sink");
312
313 /* 'codec_data' caps has invalid version */
314 gst_harness_push_event (h, gst_event_new_caps (caps));
315 fail_unless (gst_pad_get_current_caps (sinkpad) == NULL);
316 gst_caps_unref (caps);
317
318 /* Send a 'codec_data' too small */
319 codec_data = gst_buffer_new_allocate (NULL, 6, NULL);
320 caps = gst_caps_new_simple ("video/x-h264",
321 "stream-format", G_TYPE_STRING, "avc",
322 "alignment", G_TYPE_STRING, "au",
323 "codec_data", GST_TYPE_BUFFER, codec_data, NULL);
324 gst_buffer_unref (codec_data);
325
326 gst_harness_push_event (h, gst_event_new_caps (caps));
327 fail_unless (gst_pad_get_current_caps (sinkpad) == NULL);
328 gst_caps_unref (caps);
329
330 gst_object_unref (sinkpad);
331 gst_object_unref (element);
332 gst_harness_teardown (h);
333 }
334
335 GST_END_TEST;
336
GST_START_TEST(test_payloader_incomplete_nal)337 GST_START_TEST (test_payloader_incomplete_nal)
338 {
339 GstHarness *h;
340 GstBuffer *in, *out;
341 GstMapInfo map;
342 struct avtp_stream_pdu *pdu = alloca (AVTP_CVF_H264_HEADER_SIZE);
343 const gint DATA_LEN = sizeof (guint32) + 3;
344
345 /* Create the 'expected' header */
346 avtp_cvf_pdu_init (pdu, AVTP_CVF_FORMAT_SUBTYPE_H264);
347 avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_STREAM_ID, STREAM_ID);
348 avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_TV, 1);
349 avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_M, 1);
350 avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_TIMESTAMP, 3000000);
351 avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_H264_PTV, 1);
352 avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_H264_TIMESTAMP, 4000000);
353 avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_STREAM_DATA_LEN, DATA_LEN);
354
355 /* Create the harness for the avtpcvfpay */
356 h = gst_harness_new_parse
357 ("avtpcvfpay streamid=0xAABBCCDDEEFF0001 mtt=1000000 tu=1000000 processing-deadline=0");
358 gst_harness_set_src_caps (h, generate_caps (4));
359
360 /* Buffer must have the nal len (4 bytes) and the nal (3 bytes) */
361 in = gst_harness_create_buffer (h, 7);
362 GST_BUFFER_DTS (in) = 1000000;
363 GST_BUFFER_PTS (in) = 2000000;
364
365 gst_buffer_map (in, &map, GST_MAP_READWRITE);
366 map.data[0] = map.data[1] = map.data[2] = 0;
367 map.data[3] = 8; /* Lie that NAL size is 8, when buffer is only 7 (so NAL is 3) */
368 map.data[4] = 1; /* Some dummy vcl NAL type */
369 map.data[5] = 0x0;
370 map.data[6] = 0x1;
371 gst_buffer_unmap (in, &map);
372
373 out = gst_harness_push_and_pull (h, in);
374
375 /* avtpcvfpay will happily payload the three byte nal. Now, we check it */
376 fail_unless (compare_h264_avtpdu (pdu, out) == TRUE);
377 fail_unless (check_nal_filling (out, 0) == TRUE);
378
379 gst_buffer_unref (out);
380 gst_harness_teardown (h);
381 }
382
383 GST_END_TEST;
384
GST_START_TEST(test_payloader_properties)385 GST_START_TEST (test_payloader_properties)
386 {
387 GstHarness *h;
388 GstElement *element;
389 guint mtu, mtt, tu, max_interval_frames;
390 guint64 streamid, processing_deadline, measurement_interval;
391
392 /* Create the harness for the avtpcvfpay */
393 h = gst_harness_new_parse
394 ("avtpcvfpay streamid=0xAABBCCDDEEFF0001 mtt=1000000 tu=2000000 mtu=100 processing-deadline=5000 measurement-interval=125000 max-interval-frames=3");
395
396 /* Check if all properties were properly set up */
397 element = gst_harness_find_element (h, "avtpcvfpay");
398 g_object_get (G_OBJECT (element), "mtt", &mtt, NULL);
399 fail_unless_equals_uint64 (mtt, 1000000);
400
401 g_object_get (G_OBJECT (element), "mtu", &mtu, NULL);
402 fail_unless_equals_uint64 (mtu, 100);
403
404 g_object_get (G_OBJECT (element), "tu", &tu, NULL);
405 fail_unless_equals_uint64 (tu, 2000000);
406
407 g_object_get (G_OBJECT (element), "streamid", &streamid, NULL);
408 fail_unless_equals_uint64 (streamid, 0xAABBCCDDEEFF0001);
409
410 g_object_get (G_OBJECT (element), "processing-deadline", &processing_deadline,
411 NULL);
412 fail_unless_equals_uint64 (processing_deadline, 5000);
413
414 g_object_get (G_OBJECT (element), "measurement-interval",
415 &measurement_interval, NULL);
416 fail_unless_equals_uint64 (measurement_interval, 125000);
417
418 g_object_get (G_OBJECT (element), "max-interval-frames",
419 &max_interval_frames, NULL);
420 fail_unless_equals_uint64 (max_interval_frames, 3);
421
422 gst_object_unref (element);
423 gst_harness_teardown (h);
424 }
425
426 GST_END_TEST;
GST_START_TEST(test_payloader_single_and_fragment_edge)427 GST_START_TEST (test_payloader_single_and_fragment_edge)
428 {
429 GstHarness *h;
430 GstBuffer *in, *out;
431 struct avtp_stream_pdu *pdu = alloca (AVTP_CVF_H264_HEADER_SIZE);
432 const gint DATA_LEN_1 = sizeof (guint32) + 100;
433 const gint DATA_LEN_2 = sizeof (guint32) + 100;
434 const gint DATA_LEN_3 = sizeof (guint32) + 4;
435
436 /* Create the 'expected' header */
437 avtp_cvf_pdu_init (pdu, AVTP_CVF_FORMAT_SUBTYPE_H264);
438 avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_STREAM_ID, STREAM_ID);
439 avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_TV, 1);
440 avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_TIMESTAMP, 3000000);
441 avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_H264_PTV, 1);
442 avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_H264_TIMESTAMP, 4000000);
443
444 /* Create the harness for the avtpcvfpay. Setting mtu=128 ensures that
445 * NAL units will be broken roughly at 100 bytes. More details below. */
446 h = gst_harness_new_parse
447 ("avtpcvfpay streamid=0xAABBCCDDEEFF0001 mtt=1000000 tu=1000000 mtu=128 processing-deadline=0");
448 gst_harness_set_src_caps (h, generate_caps (4));
449
450 /* Create a buffer to contain the multiple NAL units. This buffer
451 * will hold two NAL units, with 100 and 101 bytes, each preceded
452 * by a 4 bytes header */
453 in = gst_harness_create_buffer (h, 100 + 101 + 2 * 4);
454 add_nal (in, 100, 7, 0);
455 add_nal (in, 101, 1, 104);
456 GST_BUFFER_DTS (in) = 1000000;
457 GST_BUFFER_PTS (in) = 2000000;
458
459 /* We now push the buffer, and check if we get three from the avtpcvfpay */
460 gst_harness_push (h, in);
461 fail_unless (gst_harness_buffers_received (h) == 3);
462
463 out = gst_harness_pull (h);
464 avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_STREAM_DATA_LEN, DATA_LEN_1);
465 fail_unless (compare_h264_avtpdu (pdu, out) == TRUE);
466 gst_buffer_unref (out);
467
468 out = gst_harness_pull (h);
469 avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_STREAM_DATA_LEN, DATA_LEN_2);
470 avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_SEQ_NUM, 1);
471 avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_TV, 0);
472 avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_TIMESTAMP, 0);
473 fail_unless (compare_h264_avtpdu (pdu, out) == TRUE);
474 gst_buffer_unref (out);
475
476 /* DATA_LEN_3 is 4 because only 98 bytes from the original NAL unit are
477 * sent on the first buffer (due 2 bytes header), and the two remaining
478 * bytes are preceded by the 2 bytes header. Note that the first byte of
479 * the NAL is stripped before the fragmentation (see comment on
480 * test_payloader_single_and_fragment below for more details). */
481 out = gst_harness_pull (h);
482 avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_STREAM_DATA_LEN, DATA_LEN_3);
483 avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_SEQ_NUM, 2);
484 avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_TV, 1);
485 avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_M, 1);
486 avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_TIMESTAMP, 3000000);
487 fail_unless (compare_h264_avtpdu (pdu, out) == TRUE);
488 gst_buffer_unref (out);
489 gst_harness_teardown (h);
490 }
491
492 GST_END_TEST;
493
GST_START_TEST(test_payloader_single_and_fragment)494 GST_START_TEST (test_payloader_single_and_fragment)
495 {
496 GstHarness *h;
497 GstBuffer *in, *out;
498 struct avtp_stream_pdu *pdu = alloca (AVTP_CVF_H264_HEADER_SIZE);
499 const gint DATA_LEN_1 = sizeof (guint32) + 4;
500 const gint DATA_LEN_2 = sizeof (guint32) + 100;
501 const gint DATA_LEN_3 = sizeof (guint32) + 100;
502 const gint DATA_LEN_4 = sizeof (guint32) + 55;
503
504 /* Create the 'expected' header */
505 avtp_cvf_pdu_init (pdu, AVTP_CVF_FORMAT_SUBTYPE_H264);
506 avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_STREAM_ID, STREAM_ID);
507 avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_TV, 1);
508 avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_TIMESTAMP, 4000000);
509 avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_H264_PTV, 1);
510 avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_H264_TIMESTAMP, 5000000);
511
512 /* Create the harness for the avtpcvfpay. Setting mtu=128 ensures that
513 * NAL units will be broken roughly at 100 bytes. More details below. */
514 h = gst_harness_new_parse
515 ("avtpcvfpay streamid=0xAABBCCDDEEFF0001 mtt=1000000 tu=1000000 processing-deadline=1000000 mtu=128");
516 gst_harness_set_src_caps (h, generate_caps (4));
517
518 /* Create a buffer to contain the multiple NAL units. This buffer
519 * will hold two NAL units, with 4 and 250 bytes, each preceded
520 * by a 4 bytes header */
521 in = gst_harness_create_buffer (h, 4 + 250 + 2 * 4);
522 add_nal (in, 4, 7, 0);
523 add_nal (in, 250, 1, 8);
524 GST_BUFFER_DTS (in) = 1000000;
525 GST_BUFFER_PTS (in) = 2000000;
526
527 /* We now push the buffer, and check if we get four from the avtpcvfpay */
528 gst_harness_push (h, in);
529 fail_unless (gst_harness_buffers_received (h) == 4);
530
531 out = gst_harness_pull (h);
532 avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_STREAM_DATA_LEN, DATA_LEN_1);
533 fail_unless (compare_h264_avtpdu (pdu, out) == TRUE);
534 fail_unless (check_nal_filling (out, 0) == TRUE);
535 gst_buffer_unref (out);
536
537 out = gst_harness_pull (h);
538 avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_STREAM_DATA_LEN, DATA_LEN_2);
539 avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_SEQ_NUM, 1);
540 avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_TV, 0);
541 avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_TIMESTAMP, 0);
542 fail_unless (compare_h264_avtpdu (pdu, out) == TRUE);
543 fail_unless (check_nal_filling (out, 0) == TRUE);
544 gst_buffer_unref (out);
545
546 out = gst_harness_pull (h);
547 avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_STREAM_DATA_LEN, DATA_LEN_3);
548 avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_SEQ_NUM, 2);
549 avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_TV, 0);
550 avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_TIMESTAMP, 0);
551 fail_unless (compare_h264_avtpdu (pdu, out) == TRUE);
552 fail_unless (check_nal_filling (out, 98) == TRUE);
553 gst_buffer_unref (out);
554
555 /* For those wondering why DATA_LEN_4 is 55 and not 50 - or why
556 * comment above states that NAL units are broken "roughly" at 100 bytes:
557 * With mtu=128, there are only 100 bytes left for NAL units, so anything
558 * bigger will be broken. But AVTP NAL units fragments have a header with
559 * two bytes, so NAL units will use only 98 bytes. This leaves the last
560 * fragment with 54 bytes. However, instead of being 56 (54 bytes plus
561 * 2 bytes header), it is 55 (53 bytes plus 2 bytes header) due to the
562 * fact that the first byte of the NAL unit (the NAL unit header) is
563 * in fact stripped from the NAL unit before the fragmentation. */
564 out = gst_harness_pull (h);
565 avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_STREAM_DATA_LEN, DATA_LEN_4);
566 avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_SEQ_NUM, 3);
567 avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_TV, 1);
568 avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_M, 1);
569 avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_TIMESTAMP, 4000000);
570 fail_unless (compare_h264_avtpdu (pdu, out) == TRUE);
571 fail_unless (check_nal_filling (out, 196) == TRUE);
572 gst_buffer_unref (out);
573 gst_harness_teardown (h);
574 }
575
576 GST_END_TEST;
577
GST_START_TEST(test_payloader_multiple_single_2)578 GST_START_TEST (test_payloader_multiple_single_2)
579 {
580 GstHarness *h;
581 GstBuffer *in, *out;
582 struct avtp_stream_pdu *pdu = alloca (AVTP_CVF_H264_HEADER_SIZE);
583 const gint DATA_LEN_1 = sizeof (guint32) + 32;
584 const gint DATA_LEN_2 = sizeof (guint32) + 16;
585 const gint DATA_LEN_3 = sizeof (guint32) + 8;
586
587 /* Create the 'expected' header */
588 avtp_cvf_pdu_init (pdu, AVTP_CVF_FORMAT_SUBTYPE_H264);
589 avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_STREAM_ID, STREAM_ID);
590 avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_TV, 1);
591 avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_TIMESTAMP, 3000000);
592 avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_H264_PTV, 1);
593 avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_H264_TIMESTAMP, 4000000);
594
595 /* Create the harness for the avtpcvfpay */
596 h = gst_harness_new_parse
597 ("avtpcvfpay streamid=0xAABBCCDDEEFF0001 mtt=1000000 tu=1000000 processing-deadline=0");
598 gst_harness_set_src_caps (h, generate_caps (2));
599
600 /* Create a buffer to contain the multiple NAL units. This buffer
601 * will hold three NAL units, with 32, 16 and 8 bytes, each preceded
602 * by a 2 bytes header */
603 in = gst_harness_create_buffer (h, 32 + 16 + 8 + 4 * 2);
604 add_nal_2 (in, 32, 7, 0);
605 add_nal_2 (in, 16, 7, 34);
606 add_nal_2 (in, 8, 1, 52);
607 GST_BUFFER_DTS (in) = 1000000;
608 GST_BUFFER_PTS (in) = 2000000;
609
610 /* We now push the buffer, and check if we get three from the avtpcvfpay */
611 gst_harness_push (h, in);
612 fail_unless (gst_harness_buffers_received (h) == 3);
613
614 out = gst_harness_pull (h);
615 avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_STREAM_DATA_LEN, DATA_LEN_1);
616 fail_unless (compare_h264_avtpdu (pdu, out) == TRUE);
617 fail_unless (check_nal_filling (out, 0) == TRUE);
618 gst_buffer_unref (out);
619
620 out = gst_harness_pull (h);
621 avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_STREAM_DATA_LEN, DATA_LEN_2);
622 avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_SEQ_NUM, 1);
623 fail_unless (compare_h264_avtpdu (pdu, out) == TRUE);
624 fail_unless (check_nal_filling (out, 0) == TRUE);
625 gst_buffer_unref (out);
626
627 out = gst_harness_pull (h);
628 avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_STREAM_DATA_LEN, DATA_LEN_3);
629 avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_SEQ_NUM, 2);
630 avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_M, 1);
631 fail_unless (compare_h264_avtpdu (pdu, out) == TRUE);
632 fail_unless (check_nal_filling (out, 0) == TRUE);
633 gst_buffer_unref (out);
634 gst_harness_teardown (h);
635 }
636
637 GST_END_TEST;
638
GST_START_TEST(test_payloader_multiple_single)639 GST_START_TEST (test_payloader_multiple_single)
640 {
641 GstHarness *h;
642 GstBuffer *in, *out;
643 struct avtp_stream_pdu *pdu = alloca (AVTP_CVF_H264_HEADER_SIZE);
644 const gint DATA_LEN_1 = sizeof (guint32) + 32;
645 const gint DATA_LEN_2 = sizeof (guint32) + 16;
646 const gint DATA_LEN_3 = sizeof (guint32) + 8;
647
648 /* Create the 'expected' header */
649 avtp_cvf_pdu_init (pdu, AVTP_CVF_FORMAT_SUBTYPE_H264);
650 avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_STREAM_ID, STREAM_ID);
651 avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_TV, 1);
652 avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_TIMESTAMP, 3000000);
653 avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_H264_PTV, 1);
654 avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_H264_TIMESTAMP, 4000000);
655
656 /* Create the harness for the avtpcvfpay */
657 h = gst_harness_new_parse
658 ("avtpcvfpay streamid=0xAABBCCDDEEFF0001 mtt=1000000 tu=1000000 processing-deadline=0");
659 gst_harness_set_src_caps (h, generate_caps (4));
660
661 /* Create a buffer to contain the multiple NAL units. This buffer
662 * will hold three NAL units, with 32, 16 and 8 bytes, each preceded
663 * by a 4 bytes header */
664 in = gst_harness_create_buffer (h, 32 + 16 + 8 + 4 * 4);
665 add_nal (in, 32, 7, 0);
666 add_nal (in, 16, 7, 36);
667 add_nal (in, 8, 1, 56);
668 GST_BUFFER_DTS (in) = 1000000;
669 GST_BUFFER_PTS (in) = 2000000;
670
671 /* We now push the buffer, and check if we get three from the avtpcvfpay */
672 gst_harness_push (h, in);
673 fail_unless (gst_harness_buffers_received (h) == 3);
674
675 out = gst_harness_pull (h);
676 avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_STREAM_DATA_LEN, DATA_LEN_1);
677 fail_unless (compare_h264_avtpdu (pdu, out) == TRUE);
678 fail_unless (check_nal_filling (out, 0) == TRUE);
679 gst_buffer_unref (out);
680
681 out = gst_harness_pull (h);
682 avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_STREAM_DATA_LEN, DATA_LEN_2);
683 avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_SEQ_NUM, 1);
684 fail_unless (compare_h264_avtpdu (pdu, out) == TRUE);
685 fail_unless (check_nal_filling (out, 0) == TRUE);
686 gst_buffer_unref (out);
687
688 out = gst_harness_pull (h);
689 avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_STREAM_DATA_LEN, DATA_LEN_3);
690 avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_SEQ_NUM, 2);
691 avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_M, 1);
692 fail_unless (compare_h264_avtpdu (pdu, out) == TRUE);
693 fail_unless (check_nal_filling (out, 0) == TRUE);
694 gst_buffer_unref (out);
695 gst_harness_teardown (h);
696 }
697
698 GST_END_TEST;
699
GST_START_TEST(test_payloader_single)700 GST_START_TEST (test_payloader_single)
701 {
702 GstHarness *h;
703 GstBuffer *in, *out;
704 struct avtp_stream_pdu *pdu = alloca (AVTP_CVF_H264_HEADER_SIZE);
705 const gint DATA_LEN = sizeof (guint32) + 4;
706
707 /* Create the 'expected' header */
708 avtp_cvf_pdu_init (pdu, AVTP_CVF_FORMAT_SUBTYPE_H264);
709 avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_STREAM_ID, STREAM_ID);
710 avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_TV, 1);
711 avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_M, 1);
712 avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_TIMESTAMP, 3000000);
713 avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_H264_PTV, 1);
714 avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_H264_TIMESTAMP, 4000000);
715 avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_STREAM_DATA_LEN, DATA_LEN);
716
717 /* Create the harness for the avtpcvfpay */
718 h = gst_harness_new_parse
719 ("avtpcvfpay streamid=0xAABBCCDDEEFF0001 mtt=1000000 tu=1000000 processing-deadline=0");
720 gst_harness_set_src_caps (h, generate_caps (4));
721
722 /* Buffer must have the nal len (4 bytes) and the nal (4 bytes) */
723 in = gst_harness_create_buffer (h, 8);
724 add_nal (in, 4, 1, 0);
725 GST_BUFFER_DTS (in) = 1000000;
726 GST_BUFFER_PTS (in) = 2000000;
727
728 out = gst_harness_push_and_pull (h, in);
729 fail_unless (compare_h264_avtpdu (pdu, out) == TRUE);
730 gst_buffer_unref (out);
731
732 /* Now test if, when nal_type is not vcl (not between 1 and 5), M is not set.
733 * Also, as we're using the same element, seqnum should increase by one */
734 avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_M, 0);
735 avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_SEQ_NUM, 1);
736
737 in = gst_harness_create_buffer (h, 8);
738 add_nal (in, 4, 6, 0);
739 GST_BUFFER_DTS (in) = 1000000;
740 GST_BUFFER_PTS (in) = 2000000;
741
742 out = gst_harness_push_and_pull (h, in);
743 fail_unless (compare_h264_avtpdu (pdu, out) == TRUE);
744 fail_unless (check_nal_filling (out, 0) == TRUE);
745 gst_buffer_unref (out);
746 gst_harness_teardown (h);
747 }
748
749 GST_END_TEST;
750
751 static Suite *
avtpcvfpay_suite(void)752 avtpcvfpay_suite (void)
753 {
754 Suite *s = suite_create ("avtpcvfpay");
755 TCase *tc_chain = tcase_create ("general");
756
757 suite_add_tcase (s, tc_chain);
758 tcase_add_test (tc_chain, test_payloader_single);
759 tcase_add_test (tc_chain, test_payloader_multiple_single);
760 tcase_add_test (tc_chain, test_payloader_multiple_single_2);
761 tcase_add_test (tc_chain, test_payloader_single_and_fragment);
762 tcase_add_test (tc_chain, test_payloader_single_and_fragment_edge);
763 tcase_add_test (tc_chain, test_payloader_incomplete_nal);
764 tcase_add_test (tc_chain, test_payloader_invalid_caps);
765 tcase_add_test (tc_chain, test_payloader_properties);
766 tcase_add_test (tc_chain, test_payloader_no_codec_data);
767 tcase_add_test (tc_chain, test_payloader_zero_sized_nal);
768 tcase_add_test (tc_chain, test_payloader_downstream_eos);
769 tcase_add_test (tc_chain, test_payloader_spread_ts);
770
771 return s;
772 }
773
774 GST_CHECK_MAIN (avtpcvfpay);
775