From 551258b2c4f1d25c5151ef403147f5b5dd6d778d Mon Sep 17 00:00:00 2001 From: Vedang Patel Date: Mon, 14 Oct 2019 13:56:36 -0700 Subject: [PATCH] tests: Add tests for CRF Synchronizer element This adds tests to validate whether the avtpcrfsync element applies the adjustment correctly. Also, the infrastructure to include additional source files while compiling is added. This change is exactly the same as the one in gst-plugins-good. --- tests/check/elements/avtpcrfsync.c | 364 +++++++++++++++++++++++++++++++++++++ tests/check/meson.build | 5 +- 2 files changed, 368 insertions(+), 1 deletion(-) create mode 100644 tests/check/elements/avtpcrfsync.c diff --git a/tests/check/elements/avtpcrfsync.c b/tests/check/elements/avtpcrfsync.c new file mode 100644 index 0000000..6990d6c --- /dev/null +++ b/tests/check/elements/avtpcrfsync.c @@ -0,0 +1,364 @@ +/* + * 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 "../../../ext/avtp/gstavtpcrfsync.c" +#undef GST_CAT_DEFAULT + +#include +#include +#include +#include +#include +#include +#include "../../../ext/avtp/gstavtpcrfutil.h" + +#define STREAM_ID 0xDEADC0DEDEADC0DE + +struct buffer_tstamps +{ + GstClockTime buf_pts; + GstClockTime buf_dts; + GstClockTime avtp_ts; + GstClockTime h264_ts; +}; + +static GstHarness * +setup_harness (void) +{ + GstHarness *h; + + h = gst_harness_new_parse ("avtpcrfsync streamid=0xDEADC0DEDEADC0DE"); + gst_harness_set_src_caps_str (h, "application/x-avtp"); + + return h; +} + +static void +fill_buffer_video_data (struct avtp_stream_pdu *pdu) +{ + const gint DATA_LEN = sizeof (guint32) + 3; + + 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, 0); + avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_H264_PTV, 1); + avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_H264_TIMESTAMP, 0); + avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_STREAM_DATA_LEN, DATA_LEN); +} + +static void +fill_buffer_audio_data (struct avtp_stream_pdu *pdu) +{ + const int DATA_LEN = 4; + + avtp_aaf_pdu_init (pdu); + avtp_aaf_pdu_set (pdu, AVTP_AAF_FIELD_TV, 1); + avtp_aaf_pdu_set (pdu, AVTP_AAF_FIELD_STREAM_ID, 0xDEADC0DEDEADC0DE); + avtp_aaf_pdu_set (pdu, AVTP_AAF_FIELD_FORMAT, AVTP_AAF_FORMAT_INT_16BIT); + avtp_aaf_pdu_set (pdu, AVTP_AAF_FIELD_NSR, AVTP_AAF_PCM_NSR_48KHZ); + avtp_aaf_pdu_set (pdu, AVTP_AAF_FIELD_CHAN_PER_FRAME, 2); + avtp_aaf_pdu_set (pdu, AVTP_AAF_FIELD_BIT_DEPTH, 16); + avtp_aaf_pdu_set (pdu, AVTP_AAF_FIELD_SP, AVTP_AAF_PCM_SP_NORMAL); + avtp_aaf_pdu_set (pdu, AVTP_AAF_FIELD_TIMESTAMP, 0); + avtp_aaf_pdu_set (pdu, AVTP_AAF_FIELD_STREAM_DATA_LEN, DATA_LEN); +} + +static GstBuffer * +create_input_buffer (GstHarness * h, guint32 subtype) +{ + struct avtp_stream_pdu *pdu; + GstMapInfo info; + GstBuffer *buf; + const gint DATA_LEN = sizeof (guint32) + 3; + + buf = gst_harness_create_buffer (h, sizeof (struct avtp_stream_pdu) + + DATA_LEN); + + gst_buffer_map (buf, &info, GST_MAP_WRITE); + pdu = (struct avtp_stream_pdu *) info.data; + + if (subtype == AVTP_SUBTYPE_AAF) + fill_buffer_audio_data (pdu); + else if (subtype == AVTP_SUBTYPE_CVF) + fill_buffer_video_data (pdu); + + gst_buffer_unmap (buf, &info); + + return buf; +} + +static void +set_buffer_tstamps (GstBuffer * buf, struct buffer_tstamps *orig) +{ + struct avtp_stream_pdu *pdu; + GstMapInfo info; + guint32 type; + + gst_buffer_map (buf, &info, GST_MAP_WRITE); + pdu = (struct avtp_stream_pdu *) info.data; + + GST_BUFFER_PTS (buf) = orig->buf_pts; + GST_BUFFER_DTS (buf) = orig->buf_dts; + + avtp_pdu_get ((struct avtp_common_pdu *) pdu, AVTP_FIELD_SUBTYPE, &type); + if (type == AVTP_SUBTYPE_AAF) + avtp_aaf_pdu_set (pdu, AVTP_AAF_FIELD_TIMESTAMP, orig->avtp_ts); + else if (type == AVTP_SUBTYPE_CVF) { + avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_TIMESTAMP, orig->avtp_ts); + avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_H264_TIMESTAMP, orig->h264_ts); + } + gst_buffer_unmap (buf, &info); +} + +static void +validate_tstamps (GstAvtpCrfBase * avtpcrfbase, GstBuffer * buf, + struct buffer_tstamps *expected) +{ + GstClockTime tstamp; + struct avtp_stream_pdu *pdu; + GstMapInfo info; + int res; + + gst_buffer_map (buf, &info, GST_MAP_READ); + pdu = (struct avtp_stream_pdu *) info.data; + + fail_unless_equals_uint64 (GST_BUFFER_PTS (buf), expected->buf_pts); + fail_unless_equals_uint64 (GST_BUFFER_DTS (buf), expected->buf_dts); + + tstamp = get_avtp_tstamp (avtpcrfbase, pdu); + fail_unless_equals_uint64 (tstamp, expected->avtp_ts); + + if (h264_tstamp_valid (pdu)) { + res = avtp_cvf_pdu_get (pdu, AVTP_CVF_FIELD_H264_TIMESTAMP, &tstamp); + fail_unless (res == 0); + fail_unless_equals_uint64 (tstamp, expected->h264_ts); + } + + gst_buffer_unmap (buf, &info); +} + +static void +test_crf_tstamps (GstHarness * h, GstBuffer * buf, struct buffer_tstamps *orig, + struct buffer_tstamps *expected) +{ + GstAvtpCrfBase *avtpcrfbase; + GstBuffer *bufout; + + avtpcrfbase = (GstAvtpCrfBase *) gst_harness_find_element (h, "avtpcrfsync"); + set_buffer_tstamps (buf, orig); + + bufout = gst_harness_push_and_pull (h, buf); + + validate_tstamps (avtpcrfbase, bufout, expected); +} + +GST_START_TEST (test_properties) +{ + const guint64 streamid = 0xAABBCCDDEEFF0001; + const gchar *address = "01:AA:BB:CC:DD:EE"; + const gchar *ifname = "enp1s0"; + GstElement *element; + guint64 val64; + gchar *str; + + element = gst_check_setup_element ("avtpcrfsync"); + + g_object_set (G_OBJECT (element), "ifname", ifname, NULL); + g_object_get (G_OBJECT (element), "ifname", &str, NULL); + fail_unless_equals_string (str, ifname); + g_free (str); + + g_object_set (G_OBJECT (element), "address", address, NULL); + g_object_get (G_OBJECT (element), "address", &str, NULL); + fail_unless_equals_string (str, address); + g_free (str); + + g_object_set (G_OBJECT (element), "streamid", streamid, NULL); + g_object_get (G_OBJECT (element), "streamid", &val64, NULL); + fail_unless_equals_uint64_hex (val64, streamid); +} + +GST_END_TEST; + +GST_START_TEST (test_set_avtp_tstamp) +{ + GstAvtpCrfSync *avtpcrfsync = g_object_new (GST_TYPE_AVTP_CRF_SYNC, NULL); + struct avtp_stream_pdu pdu; + GstClockTime tstamp; + int res; + + avtp_aaf_pdu_init (&pdu); + avtp_aaf_pdu_set (&pdu, AVTP_AAF_FIELD_TV, 1); + set_avtp_tstamp (avtpcrfsync, &pdu, 12345); + res = avtp_aaf_pdu_get (&pdu, AVTP_AAF_FIELD_TIMESTAMP, &tstamp); + fail_unless (res == 0); + fail_unless_equals_uint64 (tstamp, 12345); + + avtp_cvf_pdu_init (&pdu, AVTP_CVF_FORMAT_SUBTYPE_H264); + avtp_cvf_pdu_set (&pdu, AVTP_CVF_FIELD_TV, 1); + set_avtp_tstamp (avtpcrfsync, &pdu, 12345); + res = avtp_cvf_pdu_get (&pdu, AVTP_CVF_FIELD_TIMESTAMP, &tstamp); + fail_unless (res == 0); + fail_unless_equals_uint64 (tstamp, 12345); +} + +GST_END_TEST; + +GST_START_TEST (test_set_avtp_mr_bit) +{ + GstAvtpCrfSync *avtpcrfsync = g_object_new (GST_TYPE_AVTP_CRF_SYNC, NULL); + struct avtp_stream_pdu pdu; + guint64 mr_bit; + int res; + + avtp_aaf_pdu_init (&pdu); + set_avtp_mr_bit (avtpcrfsync, &pdu, 1); + res = avtp_aaf_pdu_get (&pdu, AVTP_AAF_FIELD_MR, &mr_bit); + fail_unless (res == 0); + fail_unless_equals_uint64 (mr_bit, 1); + + avtp_cvf_pdu_init (&pdu, AVTP_CVF_FORMAT_SUBTYPE_H264); + set_avtp_mr_bit (avtpcrfsync, &pdu, 1); + res = avtp_cvf_pdu_get (&pdu, AVTP_CVF_FIELD_MR, &mr_bit); + fail_unless (res == 0); + fail_unless_equals_uint64 (mr_bit, 1); +} + +GST_END_TEST; + +GST_START_TEST (test_crf_cvf_data) +{ + struct buffer_tstamps orig, expected; + GstAvtpCrfBase *avtpcrfbase; + GstBuffer *buf; + GstHarness *h; + + h = setup_harness (); + + buf = create_input_buffer (h, AVTP_SUBTYPE_CVF); + avtpcrfbase = (GstAvtpCrfBase *) gst_harness_find_element (h, "avtpcrfsync"); + avtpcrfbase->thread_data.average_period = 3300; + avtpcrfbase->thread_data.current_ts = 110000; + + orig = (struct buffer_tstamps) { + .buf_pts = 103000,.buf_dts = 100000,.avtp_ts = 110000,.h264_ts = 108000}; + expected = (struct buffer_tstamps) { + .buf_pts = 104204,.buf_dts = 100000,.avtp_ts = 110000,.h264_ts = 109204}; + test_crf_tstamps (h, buf, &orig, &expected); + + orig = (struct buffer_tstamps) { + .buf_pts = 107000,.buf_dts = 105000,.avtp_ts = 113000,.h264_ts = 118500}; + expected = (struct buffer_tstamps) { + .buf_pts = 108400,.buf_dts = 105300,.avtp_ts = 113300,.h264_ts = 119900}; + test_crf_tstamps (h, buf, &orig, &expected); + + /* test for invalid DTS */ + orig = (struct buffer_tstamps) { + .buf_pts = 107000,.buf_dts = GST_CLOCK_TIME_NONE,.avtp_ts = + 113000,.h264_ts = 118500}; + expected = (struct buffer_tstamps) { + .buf_pts = 108400,.buf_dts = GST_CLOCK_TIME_NONE,.avtp_ts = + 113300,.h264_ts = 119900}; + test_crf_tstamps (h, buf, &orig, &expected); + + gst_harness_teardown (h); +} + +GST_END_TEST; + +GST_START_TEST (test_crf_aaf_data) +{ + struct buffer_tstamps orig, expected; + GstAvtpCrfBase *avtpcrfbase; + GstBuffer *buf; + GstHarness *h; + + h = setup_harness (); + + buf = create_input_buffer (h, AVTP_SUBTYPE_AAF); + avtpcrfbase = (GstAvtpCrfBase *) gst_harness_find_element (h, "avtpcrfsync"); + avtpcrfbase->thread_data.average_period = 3300; + avtpcrfbase->thread_data.current_ts = 110000; + + orig = (struct buffer_tstamps) { + .buf_pts = 108000,.buf_dts = 0,.avtp_ts = 110000,.h264_ts = 0}; + expected = (struct buffer_tstamps) { + .buf_pts = 108000,.buf_dts = 0,.avtp_ts = 110000,.h264_ts = 0}; + test_crf_tstamps (h, buf, &orig, &expected); + + orig = (struct buffer_tstamps) { + .buf_pts = 110000,.buf_dts = 0,.avtp_ts = 113000,.h264_ts = 0}; + expected = (struct buffer_tstamps) { + .buf_pts = 110300,.buf_dts = 0,.avtp_ts = 113300,.h264_ts = 0}; + test_crf_tstamps (h, buf, &orig, &expected); + + gst_harness_teardown (h); +} + +GST_END_TEST; + +GST_START_TEST (test_crf_period_zero) +{ + struct buffer_tstamps orig, expected; + GstAvtpCrfBase *avtpcrfbase; + GstBuffer *buf; + GstHarness *h; + + h = setup_harness (); + + buf = create_input_buffer (h, AVTP_SUBTYPE_CVF); + avtpcrfbase = (GstAvtpCrfBase *) gst_harness_find_element (h, "avtpcrfsync"); + avtpcrfbase->thread_data.average_period = 0.0; + avtpcrfbase->thread_data.current_ts = 110; + + orig = (struct buffer_tstamps) { + .buf_pts = 100,.buf_dts = 105,.avtp_ts = 112,.h264_ts = 110}; + expected = (struct buffer_tstamps) { + .buf_pts = 100,.buf_dts = 105,.avtp_ts = 112,.h264_ts = 110}; + test_crf_tstamps (h, buf, &orig, &expected); + + gst_harness_teardown (h); +} + +GST_END_TEST; + +static Suite * +avtpcrfsync_suite (void) +{ + Suite *s = suite_create ("avtpcrfsync"); + TCase *tc_chain = tcase_create ("general"); + + GST_DEBUG_CATEGORY_INIT (avtpcrfsync_debug, "avtpcrfsync", 0, + "CRF Synchronizer"); + + suite_add_tcase (s, tc_chain); + tcase_add_test (tc_chain, test_properties); + tcase_add_test (tc_chain, test_set_avtp_tstamp); + tcase_add_test (tc_chain, test_set_avtp_mr_bit); + tcase_add_test (tc_chain, test_crf_cvf_data); + tcase_add_test (tc_chain, test_crf_aaf_data); + tcase_add_test (tc_chain, test_crf_period_zero); + + return s; +} + +GST_CHECK_MAIN (avtpcrfsync); diff --git a/tests/check/meson.build b/tests/check/meson.build index 1502350..8640a57 100644 --- a/tests/check/meson.build +++ b/tests/check/meson.build @@ -81,6 +81,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/avtpcrfsync.c'], not avtp_dep.found(), [avtp_dep], ['../../ext/avtp/gstavtpcrfutil.c', '../../ext/avtp/gstavtpcrfbase.c']], [['elements/avtpcvfpay.c'], not avtp_dep.found(), [avtp_dep]], [['elements/avtpcvfdepay.c'], not avtp_dep.found(), [avtp_dep]], [['elements/avtpsink.c'], not avtp_dep.found(), [avtp_dep]], @@ -158,8 +159,10 @@ foreach t : base_tests skip_test = t.get(1) endif + extra_sources = t.get(3, [ ]) + if not skip_test - exe = executable(test_name, fnames, + exe = executable(test_name, fnames, extra_sources, include_directories : [configinc], c_args : gst_plugins_bad_args + test_defines, cpp_args : gst_plugins_bad_args + test_defines, -- 2.7.4