From b2c385fed69db9f5b8366583682f984d6e83f181 Mon Sep 17 00:00:00 2001 From: Simon Lo Date: Wed, 7 Feb 2024 17:06:41 +0000 Subject: [PATCH] Fix tsdelay and troff (#367) * SMPTE ST 2110-10:2022: TSDELAY shall be a positive number or zero SMPTE ST 2110-21:2022: TROFF shall be a positive number or zero * Add testSdpParametersVideoJpegXs and update other sdp parameters tests which are using the optional tsdelay and troff * Prevent GCC 4.8.4 compile error, cast data type for the bst::optional parameters * Bump up boost to 1.83.0 to match with cpprestsdk dependencies * Remove braces around sdp_parameters's bandwidth initializer * Bump cpprestsdk to 2.10.19 * Roll back boost and cpprestsdk, they will be bumped up from another PR * Apply suggestions from code review Co-authored-by: Gareth Sylvester-Bradley <31761158+garethsb@users.noreply.github.com> * Update sdp unit tests with @garethsb suggestions * Remove trailing whitespace --------- Co-authored-by: Gareth Sylvester-Bradley <31761158+garethsb@users.noreply.github.com> --- Development/cmake/NmosCppTest.cmake | 2 + Development/nmos/sdp_utils.cpp | 12 +- Development/nmos/sdp_utils.h | 24 +-- Development/nmos/test/sdp_test_utils.cpp | 31 ++++ Development/nmos/test/sdp_test_utils.h | 11 ++ Development/nmos/test/sdp_utils_test.cpp | 185 ++++++++++++++++----- Development/nmos/test/video_jxsv_test.cpp | 187 ++++++++++++++++++++++ Development/nmos/video_jxsv.cpp | 4 +- Development/nmos/video_jxsv.h | 8 +- 9 files changed, 403 insertions(+), 61 deletions(-) create mode 100644 Development/nmos/test/sdp_test_utils.cpp create mode 100644 Development/nmos/test/sdp_test_utils.h diff --git a/Development/cmake/NmosCppTest.cmake b/Development/cmake/NmosCppTest.cmake index 22d6e6214..16315b18a 100644 --- a/Development/cmake/NmosCppTest.cmake +++ b/Development/cmake/NmosCppTest.cmake @@ -49,11 +49,13 @@ set(NMOS_CPP_TEST_NMOS_TEST_SOURCES nmos/test/jwt_validation_test.cpp nmos/test/paging_utils_test.cpp nmos/test/query_api_test.cpp + nmos/test/sdp_test_utils.cpp nmos/test/sdp_utils_test.cpp nmos/test/system_resources_test.cpp nmos/test/video_jxsv_test.cpp ) set(NMOS_CPP_TEST_NMOS_TEST_HEADERS + nmos/test/sdp_test_utils.h ) set(NMOS_CPP_TEST_PPLX_TEST_SOURCES diff --git a/Development/nmos/sdp_utils.cpp b/Development/nmos/sdp_utils.cpp index c66ea669d..22f693b9a 100644 --- a/Development/nmos/sdp_utils.cpp +++ b/Development/nmos/sdp_utils.cpp @@ -793,11 +793,11 @@ namespace nmos // additional parameters introduced by SMPTE specs since then... if (!params.range.empty()) fmtp.push_back({ sdp::fields::range, params.range.name }); if (0 != params.par) fmtp.push_back({ sdp::fields::pixel_aspect_ratio, nmos::details::make_pixel_aspect_ratio(params.par) }); - if (0 != params.troff) fmtp.push_back({ sdp::fields::TROFF, utility::ostringstreamed(params.troff) }); + if (params.troff) fmtp.push_back({ sdp::fields::TROFF, utility::ostringstreamed(*params.troff) }); if (0 != params.cmax) fmtp.push_back({ sdp::fields::CMAX, utility::ostringstreamed(params.cmax) }); if (0 != params.maxudp) fmtp.push_back({ sdp::fields::max_udp_packet_size, utility::ostringstreamed(params.maxudp) }); if (!params.tsmode.empty()) fmtp.push_back({ sdp::fields::timestamp_mode, params.tsmode.name }); - if (0 != params.tsdelay) fmtp.push_back({ sdp::fields::timestamp_delay, utility::ostringstreamed(params.tsdelay) }); + if (params.tsdelay) fmtp.push_back({ sdp::fields::timestamp_delay, utility::ostringstreamed(*params.tsdelay) }); return{ session_name, sdp::media_types::video, rtpmap, fmtp, {}, {}, {}, {}, media_stream_ids, ts_refclk }; } @@ -814,7 +814,7 @@ namespace nmos sdp_parameters::fmtp_t fmtp = {}; if (!params.channel_order.empty()) fmtp.push_back({ sdp::fields::channel_order, params.channel_order }); if (!params.tsmode.empty()) fmtp.push_back({ sdp::fields::timestamp_mode, params.tsmode.name }); - if (0 != params.tsdelay) fmtp.push_back({ sdp::fields::timestamp_delay, utility::ostringstreamed(params.tsdelay) }); + if (params.tsdelay) fmtp.push_back({ sdp::fields::timestamp_delay, utility::ostringstreamed(*params.tsdelay) }); return{ session_name, sdp::media_types::audio, rtpmap, fmtp, {}, params.packet_time, {}, {}, media_stream_ids, ts_refclk }; } @@ -836,9 +836,9 @@ namespace nmos if (0 != params.exactframerate) fmtp.push_back({ sdp::fields::exactframerate, nmos::details::make_exactframerate(params.exactframerate) }); if (!params.tm.empty()) fmtp.push_back({ sdp::fields::TM, params.tm.name }); if (!params.ssn.empty()) fmtp.push_back({ sdp::fields::smpte_standard_number, params.ssn.name }); - if (0 != params.troff) fmtp.push_back({ sdp::fields::TROFF, utility::ostringstreamed(params.troff) }); + if (params.troff) fmtp.push_back({ sdp::fields::TROFF, utility::ostringstreamed(*params.troff) }); if (!params.tsmode.empty()) fmtp.push_back({ sdp::fields::timestamp_mode, params.tsmode.name }); - if (0 != params.tsdelay) fmtp.push_back({ sdp::fields::timestamp_delay, utility::ostringstreamed(params.tsdelay) }); + if (params.tsdelay) fmtp.push_back({ sdp::fields::timestamp_delay, utility::ostringstreamed(*params.tsdelay) }); return{ session_name, sdp::media_types::video, rtpmap, fmtp, {}, {}, {}, {}, media_stream_ids, ts_refclk }; } @@ -854,7 +854,7 @@ namespace nmos // See https://tools.ietf.org/html/rfc4566#section-6 sdp_parameters::fmtp_t fmtp = {}; if (!params.tp.empty()) fmtp.push_back({ sdp::fields::type_parameter, params.tp.name }); - if (0 != params.troff) fmtp.push_back({ sdp::fields::TROFF, utility::ostringstreamed(params.troff) }); + if (params.troff) fmtp.push_back({ sdp::fields::TROFF, utility::ostringstreamed(*params.troff) }); return{ session_name, sdp::media_types::video, rtpmap, fmtp, {}, {}, {}, {}, media_stream_ids, ts_refclk }; } diff --git a/Development/nmos/sdp_utils.h b/Development/nmos/sdp_utils.h index ef6378886..c4ce30e68 100644 --- a/Development/nmos/sdp_utils.h +++ b/Development/nmos/sdp_utils.h @@ -316,13 +316,13 @@ namespace nmos // additional fmtp parameters from ST 2110-21:2022 sdp::type_parameter tp; - uint32_t troff; // if omitted (zero), assume default + bst::optional troff; // if omitted, assume default uint32_t cmax; // if omitted (zero), assume max defined for tp // additional fmtp parameters from ST 2110-10:2022 uint32_t maxudp; // if omitted (zero), assume the Standard UP Size Limit sdp::timestamp_mode tsmode; // if omitted (empty), assume sdp::timestamp_modes::NEW - uint32_t tsdelay; + bst::optional tsdelay; video_raw_parameters() : depth(), width(), height(), interlace(), segmented(), troff(), cmax(), maxudp(), tsdelay() {} @@ -341,11 +341,11 @@ namespace nmos sdp::packing_mode pm, sdp::smpte_standard_number ssn, sdp::type_parameter tp, - uint32_t troff, + bst::optional troff, uint32_t cmax, uint32_t maxudp, sdp::timestamp_mode tsmode, - uint32_t tsdelay + bst::optional tsdelay ) : sampling(std::move(sampling)) , depth(depth) @@ -393,7 +393,7 @@ namespace nmos // additional fmtp parameters from ST 2110-10:2022 sdp::timestamp_mode tsmode; // if omitted (empty), assume sdp::timestamp_modes::NEW - uint32_t tsdelay; + bst::optional tsdelay; // ptime double packet_time; @@ -406,7 +406,7 @@ namespace nmos uint64_t sample_rate, utility::string_t channel_order, sdp::timestamp_mode tsmode, - uint32_t tsdelay, + bst::optional tsdelay, double packet_time ) : channel_count(channel_count) @@ -442,11 +442,11 @@ namespace nmos sdp::smpte_standard_number ssn; // additional fmtp parameters from ST 2110-21:2022 - uint32_t troff; // if omitted (zero), assume default + bst::optional troff; // if omitted, assume default // additional fmtp parameters from ST 2110-10:2022 sdp::timestamp_mode tsmode; // if omitted (empty), assume sdp::timestamp_modes::NEW - uint32_t tsdelay; + bst::optional tsdelay; video_smpte291_parameters() : vpid_code(), troff(), tsdelay() {} @@ -456,9 +456,9 @@ namespace nmos nmos::rational exactframerate, sdp::transmission_model tm, sdp::smpte_standard_number ssn, - uint32_t troff, + bst::optional troff, sdp::timestamp_mode tsmode, - uint32_t tsdelay + bst::optional tsdelay ) : did_sdids(std::move(did_sdids)) , vpid_code(vpid_code) @@ -482,13 +482,13 @@ namespace nmos { // additional fmtp parameters from ST 2110-21:2017 sdp::type_parameter tp; - uint32_t troff; // if omitted (zero), assume default + bst::optional troff; // if omitted, assume default video_SMPTE2022_6_parameters() : troff() {} video_SMPTE2022_6_parameters( sdp::type_parameter tp, - uint32_t troff + bst::optional troff ) : tp(std::move(tp)) , troff(troff) diff --git a/Development/nmos/test/sdp_test_utils.cpp b/Development/nmos/test/sdp_test_utils.cpp new file mode 100644 index 000000000..f4c141e56 --- /dev/null +++ b/Development/nmos/test/sdp_test_utils.cpp @@ -0,0 +1,31 @@ +#include "nmos/test/sdp_test_utils.h" + +#include "bst/test/test.h" +#include "nmos/sdp_utils.h" + +namespace nmos +{ + typedef std::multimap comparable_fmtp_t; + + inline comparable_fmtp_t comparable_fmtp(const nmos::sdp_parameters::fmtp_t& fmtp) + { + return comparable_fmtp_t{ fmtp.begin(), fmtp.end() }; + } + + void check_sdp_parameters(const nmos::sdp_parameters& lhs, const nmos::sdp_parameters& rhs) + { + BST_REQUIRE_EQUAL(lhs.session_name, rhs.session_name); + BST_REQUIRE_EQUAL(lhs.rtpmap.payload_type, rhs.rtpmap.payload_type); + BST_REQUIRE_EQUAL(lhs.rtpmap.encoding_name, rhs.rtpmap.encoding_name); + BST_REQUIRE_EQUAL(lhs.rtpmap.clock_rate, rhs.rtpmap.clock_rate); + if (0 != lhs.rtpmap.encoding_parameters) + BST_REQUIRE_EQUAL(lhs.rtpmap.encoding_parameters, rhs.rtpmap.encoding_parameters); + else + BST_REQUIRE((0 == rhs.rtpmap.encoding_parameters || 1 == rhs.rtpmap.encoding_parameters)); + BST_REQUIRE_EQUAL(comparable_fmtp(lhs.fmtp), comparable_fmtp(rhs.fmtp)); + BST_REQUIRE_EQUAL(lhs.packet_time, rhs.packet_time); + BST_REQUIRE_EQUAL(lhs.max_packet_time, rhs.max_packet_time); + BST_REQUIRE_EQUAL(lhs.bandwidth.bandwidth_type, rhs.bandwidth.bandwidth_type); + BST_REQUIRE_EQUAL(lhs.bandwidth.bandwidth, rhs.bandwidth.bandwidth); + } +} diff --git a/Development/nmos/test/sdp_test_utils.h b/Development/nmos/test/sdp_test_utils.h new file mode 100644 index 000000000..5de233cf8 --- /dev/null +++ b/Development/nmos/test/sdp_test_utils.h @@ -0,0 +1,11 @@ +#ifndef NMOS_SDP_TEST_UTILS_H +#define NMOS_SDP_TEST_UTILS_H + +namespace nmos +{ + struct sdp_parameters; + + void check_sdp_parameters(const nmos::sdp_parameters& lhs, const nmos::sdp_parameters& rhs); +} + +#endif diff --git a/Development/nmos/test/sdp_utils_test.cpp b/Development/nmos/test/sdp_utils_test.cpp index bcda46828..edf850a23 100644 --- a/Development/nmos/test/sdp_utils_test.cpp +++ b/Development/nmos/test/sdp_utils_test.cpp @@ -9,6 +9,7 @@ #include "nmos/json_fields.h" #include "nmos/media_type.h" #include "nmos/random.h" +#include "nmos/test/sdp_test_utils.h" #include "sdp/sdp.h" //////////////////////////////////////////////////////////////////////////////////////////// @@ -499,31 +500,6 @@ BST_TEST_CASE(testSdpTransportParamsMulticast) } } -namespace -{ - typedef std::multimap comparable_fmtp_t; - - inline comparable_fmtp_t comparable_fmtp(const nmos::sdp_parameters::fmtp_t& fmtp) - { - return comparable_fmtp_t{ fmtp.begin(), fmtp.end() }; - } - - void check_sdp_parameters(const nmos::sdp_parameters& lhs, const nmos::sdp_parameters& rhs) - { - BST_REQUIRE_EQUAL(lhs.session_name, rhs.session_name); - BST_REQUIRE_EQUAL(lhs.rtpmap.payload_type, rhs.rtpmap.payload_type); - BST_REQUIRE_EQUAL(lhs.rtpmap.encoding_name, rhs.rtpmap.encoding_name); - BST_REQUIRE_EQUAL(lhs.rtpmap.clock_rate, rhs.rtpmap.clock_rate); - if (0 != lhs.rtpmap.encoding_parameters) - BST_REQUIRE_EQUAL(lhs.rtpmap.encoding_parameters, rhs.rtpmap.encoding_parameters); - else - BST_REQUIRE((0 == rhs.rtpmap.encoding_parameters || 1 == rhs.rtpmap.encoding_parameters)); - BST_REQUIRE_EQUAL(comparable_fmtp(lhs.fmtp), comparable_fmtp(rhs.fmtp)); - BST_REQUIRE_EQUAL(lhs.packet_time, rhs.packet_time); - BST_REQUIRE_EQUAL(lhs.max_packet_time, rhs.max_packet_time); - } -} - //////////////////////////////////////////////////////////////////////////////////////////// BST_TEST_CASE(testSdpParametersVideoRaw) { @@ -630,12 +606,66 @@ BST_TEST_CASE(testSdpParametersVideoRaw) } }; - for (auto& test : { example, wacky }) + std::pair zero_troff_tsdelay{ + { + U("zero_troff_tsdelay"), + sdp::media_types::video, + { + 123, + U("raw"), + 90000 + }, + { + { U("sampling"), U("UNSPECIFIED") }, + { U("depth"), U("16") }, + { U("width"), U("9999") }, + { U("height"), U("6666") }, + { U("exactframerate"), U("123") }, + { U("interlace"), {} }, + { U("segmented"), {} }, + { U("TCS"), U("ST2115LOGS3") }, + { U("colorimetry"), U("BT2100") }, + { U("RANGE"), U("FULLPROTECT") }, + { U("PAR"), U("12:11") }, + { U("PM"), U("2110BPM") }, + { U("SSN"), U("ST2110-20:2022") }, + { U("TP"), U("2110TPW") }, + { U("TROFF"), U("0") }, + { U("CMAX"), U("42") }, + { U("MAXUDP"), U("57") }, + { U("TSMODE"), U("SAMP") }, + { U("TSDELAY"), U("0") } + } + }, + { + sdp::samplings::UNSPECIFIED, + 16, + 9999, + 6666, + { 123, 1 }, + true, + true, + sdp::transfer_characteristic_systems::ST2115LOGS3, + sdp::colorimetries::BT2100, + sdp::ranges::FULLPROTECT, + { 12, 11 }, + sdp::packing_modes::block, + sdp::smpte_standard_numbers::ST2110_20_2022, + sdp::type_parameters::type_W, + 0U, + 42, + 57, + sdp::timestamp_modes::SAMP, + 0U + } + }; + + for (auto& test : { example, wacky, zero_troff_tsdelay }) { auto made = nmos::make_video_raw_sdp_parameters(test.first.session_name, test.second, test.first.rtpmap.payload_type); - check_sdp_parameters(test.first, made); + nmos::check_sdp_parameters(test.first, made); auto roundtripped = nmos::make_video_raw_sdp_parameters(made.session_name, nmos::get_video_raw_parameters(made), made.rtpmap.payload_type); - check_sdp_parameters(test.first, roundtripped); + nmos::check_sdp_parameters(test.first, roundtripped); } } @@ -697,12 +727,40 @@ BST_TEST_CASE(testSdpParametersAudioL) } }; - for (auto& test : { example, wacky }) + std::pair zero_tsdelay{ + { + U("zero_tsdelay"), + sdp::media_types::audio, + { + 123, + U("L16"), + 96000 + }, + { + { U("channel-order"), U("SMPTE2110.(M,M,M,M,ST,U02)") }, + { U("TSMODE"), U("SAMP") }, + { U("TSDELAY"), U("0") } + }, + {}, + 0.333 + }, + { + 1, + 16, + 96000, + U("SMPTE2110.(M,M,M,M,ST,U02)"), // not testing nmos::make_fmtp_channel_order here + sdp::timestamp_modes::SAMP, + 0U, + 0.333 + } + }; + + for (auto& test : { example, wacky, zero_tsdelay }) { auto made = nmos::make_audio_L_sdp_parameters(test.first.session_name, test.second, test.first.rtpmap.payload_type); - check_sdp_parameters(test.first, made); + nmos::check_sdp_parameters(test.first, made); auto roundtripped = nmos::make_audio_L_sdp_parameters(made.session_name, nmos::get_audio_L_parameters(made), made.rtpmap.payload_type); - check_sdp_parameters(test.first, roundtripped); + nmos::check_sdp_parameters(test.first, roundtripped); } } @@ -768,12 +826,45 @@ BST_TEST_CASE(testSdpParametersVideoSmpte291) } }; - for (auto& test : { example, wacky }) + std::pair zero_troff_tsdelay{ + { + U("zero_troff_tsdelay"), + sdp::media_types::video, + { + 123, + U("smpte291"), + 90000 + }, + { + { U("DID_SDID"), U("{0xAB,0xCD}") }, + { U("DID_SDID"), U("{0xEF,0x01}") }, + { U("VPID_Code"), U("132") }, + { U("exactframerate"), U("60000/1001") }, + { U("TM"), U("CTM") }, + { U("SSN"), U("ST2110-40:2021") }, + { U("TROFF"), U("0") }, + { U("TSMODE"), U("SAMP") }, + { U("TSDELAY"), U("0") } + } + }, + { + { { 0xAB, 0xCD }, { 0xEF, 0x01 } }, + nmos::vpid_codes::vpid_1_5Gbps_720_line, + nmos::rates::rate59_94, + sdp::transmission_models::compatible, + sdp::smpte_standard_numbers::ST2110_40_2023, + 0U, + sdp::timestamp_modes::SAMP, + 0U + } + }; + + for (auto& test : { example, wacky, zero_troff_tsdelay }) { auto made = nmos::make_video_smpte291_sdp_parameters(test.first.session_name, test.second, test.first.rtpmap.payload_type); - check_sdp_parameters(test.first, made); + nmos::check_sdp_parameters(test.first, made); auto roundtripped = nmos::make_video_smpte291_sdp_parameters(made.session_name, nmos::get_video_smpte291_parameters(made), made.rtpmap.payload_type); - check_sdp_parameters(test.first, roundtripped); + nmos::check_sdp_parameters(test.first, roundtripped); } } @@ -819,11 +910,31 @@ BST_TEST_CASE(testSdpParametersVideoSmpte2022_6) } }; - for (auto& test : { example, wacky }) + std::pair zero_troff{ + { + U("zero_troff"), + sdp::media_types::video, + { + 123, + U("SMPTE2022-6"), + 27000000 + }, + { + { U("TP"), U("2110TPW") }, + { U("TROFF"), U("0") } + } + }, + { + sdp::type_parameters::type_W, + 0U + } + }; + + for (auto& test : { example, wacky, zero_troff }) { auto made = nmos::make_video_SMPTE2022_6_sdp_parameters(test.first.session_name, test.second, test.first.rtpmap.payload_type); - check_sdp_parameters(test.first, made); + nmos::check_sdp_parameters(test.first, made); auto roundtripped = nmos::make_video_SMPTE2022_6_sdp_parameters(made.session_name, nmos::get_video_SMPTE2022_6_parameters(made), made.rtpmap.payload_type); - check_sdp_parameters(test.first, roundtripped); + nmos::check_sdp_parameters(test.first, roundtripped); } } diff --git a/Development/nmos/test/video_jxsv_test.cpp b/Development/nmos/test/video_jxsv_test.cpp index fc92ba85a..cfbab508c 100644 --- a/Development/nmos/test/video_jxsv_test.cpp +++ b/Development/nmos/test/video_jxsv_test.cpp @@ -3,6 +3,7 @@ #include "bst/test/test.h" #include "nmos/json_fields.h" +#include "nmos/test/sdp_test_utils.h" #include "sdp/sdp.h" //////////////////////////////////////////////////////////////////////////////////////////// @@ -56,3 +57,189 @@ a=fmtp:112 packetmode=0; profile=High444.12; level=1k-1; sublevel=Sublev3bpp; de BST_CHECK_EQUAL(expected_line, actual_line); } while (!expected.fail() && !actual.fail()); } + +//////////////////////////////////////////////////////////////////////////////////////////// +BST_TEST_CASE(testSdpParametersVideoJpegXs) +{ + std::pair example{ + { + U("example"), + sdp::media_types::video, + { + 112, + U("jxsv"), + 90000 + }, + { + { U("packetmode"), U("0") }, + { U("profile"), U("High444.12") }, + { U("level"), U("1k-1") }, + { U("sublevel"), U("Sublev3bpp") }, + { U("sampling"), U("YCbCr-4:2:2") }, + { U("width"), U("1280") }, + { U("height"), U("720") }, + { U("exactframerate"), U("60000/1001") }, + { U("depth"), U("10") }, + { U("colorimetry"), U("BT709") }, + { U("TCS"), U("SDR") }, + { U("RANGE"), U("FULL") }, + { U("SSN"), U("ST2110-22:2019") }, + { U("TP"), U("2110TPN") } + }, + 116000 + }, + { + sdp::video_jxsv::packetization_mode::codestream, + sdp::video_jxsv::transmission_mode::sequential, + sdp::video_jxsv::profiles::High444_12, + sdp::video_jxsv::levels::Level1k_1, + sdp::video_jxsv::sublevels::Sublev3bpp, + sdp::samplings::YCbCr_4_2_2, + 10, + 1280, + 720, + nmos::rates::rate59_94, + false, + false, + sdp::transfer_characteristic_systems::SDR, + sdp::colorimetries::BT709, + sdp::ranges::FULL, + sdp::smpte_standard_numbers::ST2110_22_2019, + sdp::type_parameters::type_N, + {}, + {}, + {}, + {}, + {}, + 116000 + } + }; + + std::pair wacky{ + { + U("wacky"), + sdp::media_types::video, + { + 123, + U("jxsv"), + 90000 + }, + { + { U("packetmode"), U("1") }, + { U("transmode"), U("0") }, + { U("profile"), U("Light444.12") }, + { U("level"), U("Bayer16k-1") }, + { U("sublevel"), U("Full") }, + { U("sampling"), U("UNSPECIFIED") }, + { U("width"), U("9999") }, + { U("height"), U("6666") }, + { U("exactframerate"), U("123") }, + { U("depth"), U("16") }, + { U("colorimetry"), U("BT2100") }, + { U("TCS"), U("UNSPECIFIED") }, + { U("RANGE"), U("NARROW") }, + { U("SSN"), U("ST2110-20:2022") }, + { U("TP"), U("2110TPW") }, + { U("TROFF"), U("37") }, + { U("CMAX"), U("42") }, + { U("MAXUDP"), U("57") }, + { U("TSMODE"), U("SAMP") }, + { U("TSDELAY"), U("82") } + }, + 200000 + }, + { + sdp::video_jxsv::packetization_mode::slice, + sdp::video_jxsv::transmission_mode::out_of_order, + sdp::video_jxsv::profiles::Light444_12, + sdp::video_jxsv::levels::Bayer16k_1, + sdp::video_jxsv::sublevels::Full, + sdp::samplings::UNSPECIFIED, + 16, + 9999, + 6666, + { 123, 1 }, + false, + false, + sdp::transfer_characteristic_systems::UNSPECIFIED, + sdp::colorimetries::BT2100, + sdp::ranges::NARROW, + sdp::smpte_standard_numbers::ST2110_20_2022, + sdp::type_parameters::type_W, + 37, + 42, + 57, + sdp::timestamp_modes::SAMP, + 82, + 200000 + } + }; + + std::pair zero_troff_tsdelay{ + { + U("zero_troff_tsdelay"), + sdp::media_types::video, + { + 123, + U("jxsv"), + 90000 + }, + { + { U("packetmode"), U("1") }, + { U("transmode"), U("0") }, + { U("profile"), U("Light444.12") }, + { U("level"), U("Bayer16k-1") }, + { U("sublevel"), U("Full") }, + { U("sampling"), U("UNSPECIFIED") }, + { U("width"), U("9999") }, + { U("height"), U("6666") }, + { U("exactframerate"), U("123") }, + { U("depth"), U("16") }, + { U("colorimetry"), U("BT2100") }, + { U("TCS"), U("UNSPECIFIED") }, + { U("RANGE"), U("NARROW") }, + { U("SSN"), U("ST2110-20:2022") }, + { U("TP"), U("2110TPW") }, + { U("TROFF"), U("0") }, + { U("CMAX"), U("42") }, + { U("MAXUDP"), U("57") }, + { U("TSMODE"), U("SAMP") }, + { U("TSDELAY"), U("0") } + }, + 200000 + }, + { + sdp::video_jxsv::packetization_mode::slice, + sdp::video_jxsv::transmission_mode::out_of_order, + sdp::video_jxsv::profiles::Light444_12, + sdp::video_jxsv::levels::Bayer16k_1, + sdp::video_jxsv::sublevels::Full, + sdp::samplings::UNSPECIFIED, + 16, + 9999, + 6666, + { 123, 1 }, + false, + false, + sdp::transfer_characteristic_systems::UNSPECIFIED, + sdp::colorimetries::BT2100, + sdp::ranges::NARROW, + sdp::smpte_standard_numbers::ST2110_20_2022, + sdp::type_parameters::type_W, + 0U, + 42, + 57, + sdp::timestamp_modes::SAMP, + 0U, + 200000 + } + }; + + for (auto& test : { example, wacky, zero_troff_tsdelay }) + { + auto made = nmos::make_video_jxsv_sdp_parameters(test.first.session_name, test.second, test.first.rtpmap.payload_type); + nmos::check_sdp_parameters(test.first, made); + auto roundtripped = nmos::make_video_jxsv_sdp_parameters(made.session_name, nmos::get_video_jxsv_parameters(made), made.rtpmap.payload_type); + nmos::check_sdp_parameters(test.first, roundtripped); + } +} diff --git a/Development/nmos/video_jxsv.cpp b/Development/nmos/video_jxsv.cpp index 05440fecc..bde7df1e2 100644 --- a/Development/nmos/video_jxsv.cpp +++ b/Development/nmos/video_jxsv.cpp @@ -176,11 +176,11 @@ namespace nmos // additional parameters introduced by SMPTE specs since then... if (!params.ssn.empty()) fmtp.push_back({ sdp::fields::smpte_standard_number, params.ssn.name }); if (!params.tp.empty()) fmtp.push_back({ sdp::fields::type_parameter, params.tp.name }); - if (0 != params.troff) fmtp.push_back({ sdp::fields::TROFF, utility::ostringstreamed(params.troff) }); + if (params.troff) fmtp.push_back({ sdp::fields::TROFF, utility::ostringstreamed(*params.troff) }); if (0 != params.cmax) fmtp.push_back({ sdp::fields::CMAX, utility::ostringstreamed(params.cmax) }); if (0 != params.maxudp) fmtp.push_back({ sdp::fields::max_udp_packet_size, utility::ostringstreamed(params.maxudp) }); if (!params.tsmode.empty()) fmtp.push_back({ sdp::fields::timestamp_mode, params.tsmode.name }); - if (0 != params.tsdelay) fmtp.push_back({ sdp::fields::timestamp_delay, utility::ostringstreamed(params.tsdelay) }); + if (params.tsdelay) fmtp.push_back({ sdp::fields::timestamp_delay, utility::ostringstreamed(*params.tsdelay) }); return{ session_name, sdp::media_types::video, rtpmap, fmtp, params.bit_rate, {}, {}, {}, media_stream_ids, ts_refclk }; } diff --git a/Development/nmos/video_jxsv.h b/Development/nmos/video_jxsv.h index c954267d0..90d0b740b 100644 --- a/Development/nmos/video_jxsv.h +++ b/Development/nmos/video_jxsv.h @@ -283,13 +283,13 @@ namespace nmos // additional fmtp parameters from ST 2110-21:2022 sdp::type_parameter tp; - uint32_t troff; // if omitted (zero), assume default + bst::optional troff; // if omitted, assume default uint32_t cmax; // if omitted (zero), assume max defined for tp // additional fmtp parameters from ST 2110-10:2022 uint32_t maxudp; // if omitted (zero), assume the Standard UP Size Limit sdp::timestamp_mode tsmode; // if omitted (empty), assume sdp::timestamp_modes::NEW - uint32_t tsdelay; + bst::optional tsdelay; // bandwidth uint64_t bit_rate; // transport bit rate @@ -314,11 +314,11 @@ namespace nmos sdp::range range, sdp::smpte_standard_number ssn, sdp::type_parameter tp, - uint32_t troff, + bst::optional troff, uint32_t cmax, uint32_t maxudp, sdp::timestamp_mode tsmode, - uint32_t tsdelay, + bst::optional tsdelay, uint64_t bit_rate ) : packetmode(packetmode)