From b34acc0c8cbe4b8f27c24034b9279964caee158e Mon Sep 17 00:00:00 2001 From: Ederson de Souza Date: Mon, 25 Mar 2019 17:23:49 -0700 Subject: [PATCH] tests: Add AVTP CVF payloader tests In these tests, some specially crafted buffers are sent to the payloader, simulating some scenarios and checking what comes out from it. --- tests/check/Makefile.am | 6 +- tests/check/elements/avtpcvfpay.c | 648 ++++++++++++++++++++++++++++++ tests/check/meson.build | 1 + 3 files changed, 653 insertions(+), 2 deletions(-) create mode 100644 tests/check/elements/avtpcvfpay.c diff --git a/tests/check/Makefile.am b/tests/check/Makefile.am index 8df7237162..5060b614fc 100644 --- a/tests/check/Makefile.am +++ b/tests/check/Makefile.am @@ -40,7 +40,7 @@ check_assrender = endif if USE_AVTP -check_avtp = elements/avtpaafpay elements/avtpaafdepay elements/avtpsink elements/avtpsrc +check_avtp = elements/avtpaafpay elements/avtpaafdepay elements/avtpcvfpay elements/avtpsink elements/avtpsrc else check_avtp = endif @@ -287,7 +287,6 @@ check_PROGRAMS = \ elements/h263parse \ elements/h264parse \ elements/mpegtsmux \ - elements/mpegvideoparse \ elements/mpeg4videoparse \ elements/mxfdemux \ elements/mxfmux \ @@ -510,6 +509,9 @@ elements_avtpaafpay_LDADD = $(GST_PLUGINS_BASE_LIBS) $(GST_BASE_LIBS) $(LDADD) $ elements_avtpaafdepay_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(AM_CFLAGS) $(AVTP_CFLAGS) elements_avtpaafdepay_LDADD = $(GST_PLUGINS_BASE_LIBS) $(GST_BASE_LIBS) $(LDADD) $(AVTP_LIBS) +elements_avtpcvfpay_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(AM_CFLAGS) $(AVTP_CFLAGS) +elements_avtpcvfpay_LDADD = $(GST_PLUGINS_BASE_LIBS) $(GST_BASE_LIBS) $(LDADD) $(AVTP_LIBS) + elements_avtpsink_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(AM_CFLAGS) elements_avtpsink_LDADD = $(GST_PLUGINS_BASE_LIBS) $(GST_BASE_LIBS) $(LDADD) diff --git a/tests/check/elements/avtpcvfpay.c b/tests/check/elements/avtpcvfpay.c new file mode 100644 index 0000000000..9f92ba83d0 --- /dev/null +++ b/tests/check/elements/avtpcvfpay.c @@ -0,0 +1,648 @@ +/* + * GStreamer AVTP Plugin + * Copyright (C) 2019 Intel Corporation + * + * 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, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#include +#include + +#include +#include + +#define AVTP_CVF_H264_HEADER_SIZE (sizeof(struct avtp_stream_pdu) + sizeof(guint32)) +#define STREAM_ID 0xAABBCCDDEEFF0001 + +/* Simple codec data, with only the NAL size len, no SPS/PPS. */ +static GstCaps * +generate_caps (guint8 nal_size_len) +{ + GstBuffer *codec_data; + GstMapInfo map; + GstCaps *caps; + + /* 7 is the minimal codec_data size, when no SPS/PPS is sent */ + codec_data = gst_buffer_new_allocate (NULL, 7, NULL); + gst_buffer_map (codec_data, &map, GST_MAP_READWRITE); + + memset (map.data, 0, map.size); + map.data[0] = 1; /* version */ + map.data[4] = (nal_size_len - 1) | 0xfc; /* Other 6 bits are 1 */ + map.data[5] = 0xe0; /* first 3 bits are 1 */ + + gst_buffer_unmap (codec_data, &map); + + caps = gst_caps_new_simple ("video/x-h264", + "stream-format", G_TYPE_STRING, "avc", + "alignment", G_TYPE_STRING, "au", + "codec_data", GST_TYPE_BUFFER, codec_data, NULL); + gst_buffer_unref (codec_data); + + return caps; +} + +static void +fill (guint8 * buf, gsize size) +{ + guint8 i = 0; + + while (size--) + *buf++ = i++; +} + +static gboolean +check_nal_filling (GstBuffer * buffer, guint8 first) +{ + GstMapInfo map; + gint i; + gsize offset = AVTP_CVF_H264_HEADER_SIZE + 1; + gboolean result = TRUE; + + gst_buffer_map (buffer, &map, GST_MAP_READ); + if ((map.data[AVTP_CVF_H264_HEADER_SIZE] & 0x1f) == 28) + offset++; /* Fragmented NALs have 2 bytes header */ + + for (i = offset; i < map.size; i++) { + if (map.data[i] != first++) { + result = FALSE; + break; + } + } + + return result; +} + +static void +add_nal (GstBuffer * buffer, gsize size, guint type, gsize offset) +{ + GstMapInfo map; + + gst_buffer_map (buffer, &map, GST_MAP_READWRITE); + + map.data[offset] = map.data[offset + 1] = 0; + map.data[offset + 2] = size >> 8; + map.data[offset + 3] = size & 0xff; + map.data[offset + 4] = type & 0x1f; + fill (&map.data[offset + 5], size - 1); + + gst_buffer_unmap (buffer, &map); +} + +/* This function assumes that NAL size len is 2 */ +static void +add_nal_2 (GstBuffer * buffer, gsize size, guint type, gsize offset) +{ + GstMapInfo map; + + gst_buffer_map (buffer, &map, GST_MAP_READWRITE); + + map.data[offset] = size >> 8; + map.data[offset + 1] = size & 0xff; + map.data[offset + 2] = type & 0x1f; + fill (&map.data[offset + 3], size - 1); + + gst_buffer_unmap (buffer, &map); +} + +static gboolean +compare_h264_avtpdu (struct avtp_stream_pdu *pdu, GstBuffer * buffer) +{ + GstMapInfo map; + gboolean result; + + gst_buffer_map (buffer, &map, GST_MAP_READ); + /* buffer must have at least the header size */ + if (map.size < AVTP_CVF_H264_HEADER_SIZE) + return FALSE; + + result = memcmp (map.data, pdu, AVTP_CVF_H264_HEADER_SIZE) == 0; + + gst_buffer_unmap (buffer, &map); + + return result; +} + +GST_START_TEST (test_payloader_no_codec_data) +{ + GstHarness *h; + GstCaps *caps; + GstBuffer *in; + + /* Caps without codec_data */ + caps = gst_caps_new_simple ("video/x-h264", + "stream-format", G_TYPE_STRING, "avc", + "alignment", G_TYPE_STRING, "au", NULL); + + /* Create the harness for the avtpcvfpay */ + h = gst_harness_new_parse + ("avtpcvfpay streamid=0xAABBCCDDEEFF0001 mtt=1000000 tu=1000000 processing-deadline=0"); + gst_harness_set_src_caps (h, caps); + + /* No buffer should come out when we send input */ + in = gst_harness_create_buffer (h, 8); + add_nal (in, 4, 1, 0); + GST_BUFFER_DTS (in) = 1000000; + GST_BUFFER_PTS (in) = 2000000; + + gst_harness_push (h, in); + fail_unless_equals_int (gst_harness_buffers_received (h), 0); + + gst_harness_teardown (h); +} + +GST_END_TEST; + +GST_START_TEST (test_payloader_invalid_caps) +{ + GstBuffer *codec_data; + GstElement *element; + GstPad *sinkpad; + GstMapInfo map; + GstCaps *caps; + GstHarness *h; + + /* 7 is the minimal codec_data size, when no SPS/PPS is sent */ + codec_data = gst_buffer_new_allocate (NULL, 7, NULL); + gst_buffer_map (codec_data, &map, GST_MAP_READWRITE); + + memset (map.data, 0, map.size); + map.data[0] = 0; /* version */ + map.data[4] = 0x03 | 0xfc; /* Other 6 bits are 1 */ + map.data[5] = 0xe0; /* first 3 bits are 1 */ + + gst_buffer_unmap (codec_data, &map); + + caps = gst_caps_new_simple ("video/x-h264", + "stream-format", G_TYPE_STRING, "avc", + "alignment", G_TYPE_STRING, "au", + "codec_data", GST_TYPE_BUFFER, codec_data, NULL); + gst_buffer_unref (codec_data); + + /* Create the harness for the avtpcvfpay */ + h = gst_harness_new_parse + ("avtpcvfpay streamid=0xAABBCCDDEEFF0001 mtt=1000000 tu=1000000"); + element = gst_harness_find_element (h, "avtpcvfpay"); + sinkpad = gst_element_get_static_pad (element, "sink"); + + /* 'codec_data' caps has invalid version */ + gst_harness_push_event (h, gst_event_new_caps (caps)); + fail_unless (gst_pad_get_current_caps (sinkpad) == NULL); + gst_caps_unref (caps); + + /* Send a 'codec_data' too small */ + codec_data = gst_buffer_new_allocate (NULL, 6, NULL); + caps = gst_caps_new_simple ("video/x-h264", + "stream-format", G_TYPE_STRING, "avc", + "alignment", G_TYPE_STRING, "au", + "codec_data", GST_TYPE_BUFFER, codec_data, NULL); + gst_buffer_unref (codec_data); + + gst_harness_push_event (h, gst_event_new_caps (caps)); + fail_unless (gst_pad_get_current_caps (sinkpad) == NULL); + gst_caps_unref (caps); + + gst_harness_teardown (h); +} + +GST_END_TEST; + +GST_START_TEST (test_payloader_incomplete_nal) +{ + GstHarness *h; + GstBuffer *in, *out; + GstMapInfo map; + struct avtp_stream_pdu *pdu = alloca (AVTP_CVF_H264_HEADER_SIZE); + const gint DATA_LEN = sizeof (guint32) + 3; + + /* Create the 'expected' header */ + avtp_cvf_pdu_init (pdu, AVTP_CVF_FORMAT_SUBTYPE_H264); + avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_STREAM_ID, STREAM_ID); + avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_TV, 1); + avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_M, 1); + avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_TIMESTAMP, 3000000); + avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_H264_PTV, 1); + avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_H264_TIMESTAMP, 4000000); + avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_STREAM_DATA_LEN, DATA_LEN); + + /* Create the harness for the avtpcvfpay */ + h = gst_harness_new_parse + ("avtpcvfpay streamid=0xAABBCCDDEEFF0001 mtt=1000000 tu=1000000 processing-deadline=0"); + gst_harness_set_src_caps (h, generate_caps (4)); + + /* Buffer must have the nal len (4 bytes) and the nal (3 bytes) */ + in = gst_harness_create_buffer (h, 7); + GST_BUFFER_DTS (in) = 1000000; + GST_BUFFER_PTS (in) = 2000000; + + gst_buffer_map (in, &map, GST_MAP_READWRITE); + map.data[0] = map.data[1] = map.data[2] = 0; + map.data[3] = 8; /* Lie that NAL size is 8, when buffer is only 7 (so NAL is 3) */ + map.data[4] = 1; /* Some dummy vcl NAL type */ + map.data[5] = 0x0; + map.data[6] = 0x1; + + out = gst_harness_push_and_pull (h, in); + + /* avtpcvfpay will happily payload the three byte nal. Now, we check it */ + fail_unless (compare_h264_avtpdu (pdu, out) == TRUE); + fail_unless (check_nal_filling (out, 0) == TRUE); + + gst_buffer_unref (out); + gst_harness_teardown (h); +} + +GST_END_TEST; + +GST_START_TEST (test_payloader_properties) +{ + GstHarness *h; + GstElement *element; + guint mtu, mtt, tu; + guint64 streamid, processing_deadline; + + /* Create the harness for the avtpcvfpay */ + h = gst_harness_new_parse + ("avtpcvfpay streamid=0xAABBCCDDEEFF0001 mtt=1000000 tu=2000000 mtu=100 processing-deadline=5000"); + + /* Check if all properties were properly set up */ + element = gst_harness_find_element (h, "avtpcvfpay"); + g_object_get (G_OBJECT (element), "mtt", &mtt, NULL); + fail_unless_equals_uint64 (mtt, 1000000); + + g_object_get (G_OBJECT (element), "mtu", &mtu, NULL); + fail_unless_equals_uint64 (mtu, 100); + + g_object_get (G_OBJECT (element), "tu", &tu, NULL); + fail_unless_equals_uint64 (tu, 2000000); + + g_object_get (G_OBJECT (element), "streamid", &streamid, NULL); + fail_unless_equals_uint64 (streamid, 0xAABBCCDDEEFF0001); + + g_object_get (G_OBJECT (element), "processing-deadline", &processing_deadline, + NULL); + fail_unless_equals_uint64 (processing_deadline, 5000); + + gst_harness_teardown (h); +} + +GST_END_TEST; +GST_START_TEST (test_payloader_single_and_fragment_edge) +{ + GstHarness *h; + GstBuffer *in, *out; + struct avtp_stream_pdu *pdu = alloca (AVTP_CVF_H264_HEADER_SIZE); + const gint DATA_LEN_1 = sizeof (guint32) + 100; + const gint DATA_LEN_2 = sizeof (guint32) + 100; + const gint DATA_LEN_3 = sizeof (guint32) + 4; + + /* Create the 'expected' header */ + avtp_cvf_pdu_init (pdu, AVTP_CVF_FORMAT_SUBTYPE_H264); + avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_STREAM_ID, STREAM_ID); + avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_TV, 1); + avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_TIMESTAMP, 3000000); + avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_H264_PTV, 1); + avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_H264_TIMESTAMP, 4000000); + + /* Create the harness for the avtpcvfpay. Setting mtu=128 ensures that + * NAL units will be broken roughly at 100 bytes. More details below. */ + h = gst_harness_new_parse + ("avtpcvfpay streamid=0xAABBCCDDEEFF0001 mtt=1000000 tu=1000000 mtu=128 processing-deadline=0"); + gst_harness_set_src_caps (h, generate_caps (4)); + + /* Create a buffer to contain the multiple NAL units. This buffer + * will hold two NAL units, with 100 and 101 bytes, each preceded + * by a 4 bytes header */ + in = gst_harness_create_buffer (h, 100 + 101 + 2 * 4); + add_nal (in, 100, 7, 0); + add_nal (in, 101, 1, 104); + GST_BUFFER_DTS (in) = 1000000; + GST_BUFFER_PTS (in) = 2000000; + + /* We now push the buffer, and check if we get three from the avtpcvfpay */ + gst_harness_push (h, in); + fail_unless (gst_harness_buffers_received (h) == 3); + + out = gst_harness_pull (h); + avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_STREAM_DATA_LEN, DATA_LEN_1); + fail_unless (compare_h264_avtpdu (pdu, out) == TRUE); + gst_buffer_unref (out); + + out = gst_harness_pull (h); + avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_STREAM_DATA_LEN, DATA_LEN_2); + avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_SEQ_NUM, 1); + avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_TV, 0); + avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_TIMESTAMP, 0); + fail_unless (compare_h264_avtpdu (pdu, out) == TRUE); + gst_buffer_unref (out); + + /* DATA_LEN_3 is 4 because only 98 bytes from the original NAL unit are + * sent on the first buffer (due 2 bytes header), and the two remaining + * bytes are preceded by the 2 bytes header. Note that the first byte of + * the NAL is stripped before the fragmentation (see comment on + * test_payloader_single_and_fragment below for more details). */ + out = gst_harness_pull (h); + avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_STREAM_DATA_LEN, DATA_LEN_3); + avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_SEQ_NUM, 2); + avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_TV, 1); + avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_M, 1); + avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_TIMESTAMP, 3000000); + fail_unless (compare_h264_avtpdu (pdu, out) == TRUE); + gst_buffer_unref (out); + gst_harness_teardown (h); +} + +GST_END_TEST; + +GST_START_TEST (test_payloader_single_and_fragment) +{ + GstHarness *h; + GstBuffer *in, *out; + struct avtp_stream_pdu *pdu = alloca (AVTP_CVF_H264_HEADER_SIZE); + const gint DATA_LEN_1 = sizeof (guint32) + 4; + const gint DATA_LEN_2 = sizeof (guint32) + 100; + const gint DATA_LEN_3 = sizeof (guint32) + 100; + const gint DATA_LEN_4 = sizeof (guint32) + 55; + + /* Create the 'expected' header */ + avtp_cvf_pdu_init (pdu, AVTP_CVF_FORMAT_SUBTYPE_H264); + avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_STREAM_ID, STREAM_ID); + avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_TV, 1); + avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_TIMESTAMP, 4000000); + avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_H264_PTV, 1); + avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_H264_TIMESTAMP, 5000000); + + /* Create the harness for the avtpcvfpay. Setting mtu=128 ensures that + * NAL units will be broken roughly at 100 bytes. More details below. */ + h = gst_harness_new_parse + ("avtpcvfpay streamid=0xAABBCCDDEEFF0001 mtt=1000000 tu=1000000 processing-deadline=1000000 mtu=128"); + gst_harness_set_src_caps (h, generate_caps (4)); + + /* Create a buffer to contain the multiple NAL units. This buffer + * will hold two NAL units, with 4 and 250 bytes, each preceded + * by a 4 bytes header */ + in = gst_harness_create_buffer (h, 4 + 250 + 2 * 4); + add_nal (in, 4, 7, 0); + add_nal (in, 250, 1, 8); + GST_BUFFER_DTS (in) = 1000000; + GST_BUFFER_PTS (in) = 2000000; + + /* We now push the buffer, and check if we get four from the avtpcvfpay */ + gst_harness_push (h, in); + fail_unless (gst_harness_buffers_received (h) == 4); + + out = gst_harness_pull (h); + avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_STREAM_DATA_LEN, DATA_LEN_1); + fail_unless (compare_h264_avtpdu (pdu, out) == TRUE); + fail_unless (check_nal_filling (out, 0) == TRUE); + gst_buffer_unref (out); + + out = gst_harness_pull (h); + avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_STREAM_DATA_LEN, DATA_LEN_2); + avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_SEQ_NUM, 1); + avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_TV, 0); + avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_TIMESTAMP, 0); + fail_unless (compare_h264_avtpdu (pdu, out) == TRUE); + fail_unless (check_nal_filling (out, 0) == TRUE); + gst_buffer_unref (out); + + out = gst_harness_pull (h); + avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_STREAM_DATA_LEN, DATA_LEN_3); + avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_SEQ_NUM, 2); + avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_TV, 0); + avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_TIMESTAMP, 0); + fail_unless (compare_h264_avtpdu (pdu, out) == TRUE); + fail_unless (check_nal_filling (out, 98) == TRUE); + gst_buffer_unref (out); + + /* For those wondering why DATA_LEN_4 is 55 and not 50 - or why + * comment above states that NAL units are broken "rougly" at 100 bytes: + * With mtu=128, there are only 100 bytes left for NAL units, so anything + * bigger will be broken. But AVTP NAL units fragments have a header with + * two bytes, so NAL units will use only 98 bytes. This leaves the last + * fragment with 54 bytes. However, instead of being 56 (54 bytes plus + * 2 bytes header), it is 55 (53 bytes plus 2 bytes header) due to the + * fact that the first byte of the NAL unit (the NAL unit header) is + * in fact stripped from the NAL unit before the fragmentation. */ + out = gst_harness_pull (h); + avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_STREAM_DATA_LEN, DATA_LEN_4); + avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_SEQ_NUM, 3); + avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_TV, 1); + avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_M, 1); + avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_TIMESTAMP, 4000000); + fail_unless (compare_h264_avtpdu (pdu, out) == TRUE); + fail_unless (check_nal_filling (out, 196) == TRUE); + gst_buffer_unref (out); + gst_harness_teardown (h); +} + +GST_END_TEST; + +GST_START_TEST (test_payloader_multiple_single_2) +{ + GstHarness *h; + GstBuffer *in, *out; + struct avtp_stream_pdu *pdu = alloca (AVTP_CVF_H264_HEADER_SIZE); + const gint DATA_LEN_1 = sizeof (guint32) + 32; + const gint DATA_LEN_2 = sizeof (guint32) + 16; + const gint DATA_LEN_3 = sizeof (guint32) + 8; + + /* Create the 'expected' header */ + avtp_cvf_pdu_init (pdu, AVTP_CVF_FORMAT_SUBTYPE_H264); + avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_STREAM_ID, STREAM_ID); + avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_TV, 1); + avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_TIMESTAMP, 3000000); + avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_H264_PTV, 1); + avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_H264_TIMESTAMP, 4000000); + + /* Create the harness for the avtpcvfpay */ + h = gst_harness_new_parse + ("avtpcvfpay streamid=0xAABBCCDDEEFF0001 mtt=1000000 tu=1000000 processing-deadline=0"); + gst_harness_set_src_caps (h, generate_caps (2)); + + /* Create a buffer to contain the multiple NAL units. This buffer + * will hold three NAL units, with 32, 16 and 8 bytes, each preceded + * by a 2 bytes header */ + in = gst_harness_create_buffer (h, 32 + 16 + 8 + 4 * 2); + add_nal_2 (in, 32, 7, 0); + add_nal_2 (in, 16, 7, 34); + add_nal_2 (in, 8, 1, 52); + GST_BUFFER_DTS (in) = 1000000; + GST_BUFFER_PTS (in) = 2000000; + + /* We now push the buffer, and check if we get three from the avtpcvfpay */ + gst_harness_push (h, in); + fail_unless (gst_harness_buffers_received (h) == 3); + + out = gst_harness_pull (h); + avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_STREAM_DATA_LEN, DATA_LEN_1); + fail_unless (compare_h264_avtpdu (pdu, out) == TRUE); + fail_unless (check_nal_filling (out, 0) == TRUE); + gst_buffer_unref (out); + + out = gst_harness_pull (h); + avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_STREAM_DATA_LEN, DATA_LEN_2); + avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_SEQ_NUM, 1); + fail_unless (compare_h264_avtpdu (pdu, out) == TRUE); + fail_unless (check_nal_filling (out, 0) == TRUE); + gst_buffer_unref (out); + + out = gst_harness_pull (h); + avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_STREAM_DATA_LEN, DATA_LEN_3); + avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_SEQ_NUM, 2); + avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_M, 1); + fail_unless (compare_h264_avtpdu (pdu, out) == TRUE); + fail_unless (check_nal_filling (out, 0) == TRUE); + gst_buffer_unref (out); + gst_harness_teardown (h); +} + +GST_END_TEST; + +GST_START_TEST (test_payloader_multiple_single) +{ + GstHarness *h; + GstBuffer *in, *out; + struct avtp_stream_pdu *pdu = alloca (AVTP_CVF_H264_HEADER_SIZE); + const gint DATA_LEN_1 = sizeof (guint32) + 32; + const gint DATA_LEN_2 = sizeof (guint32) + 16; + const gint DATA_LEN_3 = sizeof (guint32) + 8; + + /* Create the 'expected' header */ + avtp_cvf_pdu_init (pdu, AVTP_CVF_FORMAT_SUBTYPE_H264); + avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_STREAM_ID, STREAM_ID); + avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_TV, 1); + avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_TIMESTAMP, 3000000); + avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_H264_PTV, 1); + avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_H264_TIMESTAMP, 4000000); + + /* Create the harness for the avtpcvfpay */ + h = gst_harness_new_parse + ("avtpcvfpay streamid=0xAABBCCDDEEFF0001 mtt=1000000 tu=1000000 processing-deadline=0"); + gst_harness_set_src_caps (h, generate_caps (4)); + + /* Create a buffer to contain the multiple NAL units. This buffer + * will hold three NAL units, with 32, 16 and 8 bytes, each preceded + * by a 4 bytes header */ + in = gst_harness_create_buffer (h, 32 + 16 + 8 + 4 * 4); + add_nal (in, 32, 7, 0); + add_nal (in, 16, 7, 36); + add_nal (in, 8, 1, 56); + GST_BUFFER_DTS (in) = 1000000; + GST_BUFFER_PTS (in) = 2000000; + + /* We now push the buffer, and check if we get three from the avtpcvfpay */ + gst_harness_push (h, in); + fail_unless (gst_harness_buffers_received (h) == 3); + + out = gst_harness_pull (h); + avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_STREAM_DATA_LEN, DATA_LEN_1); + fail_unless (compare_h264_avtpdu (pdu, out) == TRUE); + fail_unless (check_nal_filling (out, 0) == TRUE); + gst_buffer_unref (out); + + out = gst_harness_pull (h); + avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_STREAM_DATA_LEN, DATA_LEN_2); + avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_SEQ_NUM, 1); + fail_unless (compare_h264_avtpdu (pdu, out) == TRUE); + fail_unless (check_nal_filling (out, 0) == TRUE); + gst_buffer_unref (out); + + out = gst_harness_pull (h); + avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_STREAM_DATA_LEN, DATA_LEN_3); + avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_SEQ_NUM, 2); + avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_M, 1); + fail_unless (compare_h264_avtpdu (pdu, out) == TRUE); + fail_unless (check_nal_filling (out, 0) == TRUE); + gst_buffer_unref (out); + gst_harness_teardown (h); +} + +GST_END_TEST; + +GST_START_TEST (test_payloader_single) +{ + GstHarness *h; + GstBuffer *in, *out; + struct avtp_stream_pdu *pdu = alloca (AVTP_CVF_H264_HEADER_SIZE); + const gint DATA_LEN = sizeof (guint32) + 4; + + /* Create the 'expected' header */ + avtp_cvf_pdu_init (pdu, AVTP_CVF_FORMAT_SUBTYPE_H264); + avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_STREAM_ID, STREAM_ID); + avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_TV, 1); + avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_M, 1); + avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_TIMESTAMP, 3000000); + avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_H264_PTV, 1); + avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_H264_TIMESTAMP, 4000000); + avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_STREAM_DATA_LEN, DATA_LEN); + + /* Create the harness for the avtpcvfpay */ + h = gst_harness_new_parse + ("avtpcvfpay streamid=0xAABBCCDDEEFF0001 mtt=1000000 tu=1000000 processing-deadline=0"); + gst_harness_set_src_caps (h, generate_caps (4)); + + /* Buffer must have the nal len (4 bytes) and the nal (4 bytes) */ + in = gst_harness_create_buffer (h, 8); + add_nal (in, 4, 1, 0); + GST_BUFFER_DTS (in) = 1000000; + GST_BUFFER_PTS (in) = 2000000; + + out = gst_harness_push_and_pull (h, in); + fail_unless (compare_h264_avtpdu (pdu, out) == TRUE); + gst_buffer_unref (out); + + /* Now test if, when nal_type is not vcl (not between 1 and 5), M is not set. + * Also, as we're using the same element, seqnum should increase by one */ + avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_M, 0); + avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_SEQ_NUM, 1); + + in = gst_harness_create_buffer (h, 8); + add_nal (in, 4, 6, 0); + GST_BUFFER_DTS (in) = 1000000; + GST_BUFFER_PTS (in) = 2000000; + + out = gst_harness_push_and_pull (h, in); + fail_unless (compare_h264_avtpdu (pdu, out) == TRUE); + fail_unless (check_nal_filling (out, 0) == TRUE); + gst_buffer_unref (out); + gst_harness_teardown (h); +} + +GST_END_TEST; + +static Suite * +avtpcvfpay_suite (void) +{ + Suite *s = suite_create ("avtpcvfpay"); + TCase *tc_chain = tcase_create ("general"); + + suite_add_tcase (s, tc_chain); + tcase_add_test (tc_chain, test_payloader_single); + tcase_add_test (tc_chain, test_payloader_multiple_single); + tcase_add_test (tc_chain, test_payloader_multiple_single_2); + tcase_add_test (tc_chain, test_payloader_single_and_fragment); + tcase_add_test (tc_chain, test_payloader_single_and_fragment_edge); + tcase_add_test (tc_chain, test_payloader_incomplete_nal); + tcase_add_test (tc_chain, test_payloader_invalid_caps); + tcase_add_test (tc_chain, test_payloader_properties); + tcase_add_test (tc_chain, test_payloader_no_codec_data); + + return s; +} + +GST_CHECK_MAIN (avtpcvfpay); diff --git a/tests/check/meson.build b/tests/check/meson.build index 60a64eba69..7027f916c2 100644 --- a/tests/check/meson.build +++ b/tests/check/meson.build @@ -72,6 +72,7 @@ if host_machine.system() != 'windows' [['elements/assrender.c'], not ass_dep.found(), [ass_dep]], [['elements/avtpaafpay.c'], not avtp_dep.found(), [avtp_dep]], [['elements/avtpaafdepay.c'], not avtp_dep.found(), [avtp_dep]], + [['elements/avtpcvfpay.c'], not avtp_dep.found(), [avtp_dep]], [['elements/avtpsink.c'], not avtp_dep.found(), [avtp_dep]], [['elements/avtpsrc.c'], not avtp_dep.found(), [avtp_dep]], [['elements/ccconverter.c']],