Skip to content

Commit

Permalink
Fix SMPTE 291 exactframerate field (#346)
Browse files Browse the repository at this point in the history
* Add unit tests for SDP parameters creation/parsing functions for video/raw, audio/L, video/smpte291 and video/SMPTE2022-6

* Fix insertion of exactframerate for video/smpte291
(Thanks to @cmaberto, Cameron Maberto, Apple, for the original bug report.)

* Fix bug generating VPID_Code on Linux due to char_t vs. uint8_t confusion

* Fix SSN for ST2110-40:2023 to be ST2110-40:2021

Although this revision should have been published in 2022 and the SSN should have been updated to match, neither of those things actually happened...

Co-authored-by: jonathan-r-thorpe <[email protected]>

* Update Development/nmos/test/sdp_utils_test.cpp

---------

Co-authored-by: jonathan-r-thorpe <[email protected]>
  • Loading branch information
garethsb and jonathan-r-thorpe authored Nov 2, 2023
1 parent a584f92 commit 4f1844d
Show file tree
Hide file tree
Showing 2 changed files with 331 additions and 2 deletions.
4 changes: 2 additions & 2 deletions Development/nmos/sdp_utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -832,8 +832,8 @@ namespace nmos
{
return sdp_parameters::fmtp_t::value_type{ sdp::fields::DID_SDID, make_fmtp_did_sdid(did_sdid) };
}));
if (0 != params.vpid_code) fmtp.push_back({ sdp::fields::VPID_Code, utility::ostringstreamed(params.vpid_code) });
if (!params.exactframerate) fmtp.push_back({ sdp::fields::exactframerate, nmos::details::make_exactframerate(params.exactframerate) });
if (0 != params.vpid_code) fmtp.push_back({ sdp::fields::VPID_Code, utility::ostringstreamed((uint32_t)params.vpid_code) });
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) });
Expand Down
329 changes: 329 additions & 0 deletions Development/nmos/test/sdp_utils_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -498,3 +498,332 @@ BST_TEST_CASE(testSdpTransportParamsMulticast)
BST_REQUIRE(test_receiver_params == receiver_params);
}
}

namespace
{
typedef std::multimap<utility::string_t, utility::string_t> 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)
{
// a=fmtp:96 colorimetry=BT709; exactframerate=30000/1001; depth=10; TCS=SDR; sampling=YCbCr-4:2:2; width=1920; interlace; TP=2110TPN; PM=2110GPM; height=1080; SSN=ST2110-20:2017
// cf. testSdpRoundtrip in sdp/test/sdp_test.cpp

std::pair<nmos::sdp_parameters, nmos::video_raw_parameters> example{
{
U("example"),
sdp::media_types::video,
{
96,
U("raw"),
90000
},
{
{ U("colorimetry"), U("BT709") },
{ U("exactframerate"), U("30000/1001") },
{ U("depth"), U("10") },
{ U("TCS"), U("SDR") },
{ U("sampling"), U("YCbCr-4:2:2") },
{ U("width"), U("1920") },
{ U("interlace"), {} },
{ U("TP"), U("2110TPN") },
{ U("PM"), U("2110GPM") },
{ U("height"), U("1080") },
{ U("SSN"), U("ST2110-20:2017") }
}
},
{
sdp::samplings::YCbCr_4_2_2,
10,
1920,
1080,
nmos::rates::rate29_97,
true,
false,
sdp::transfer_characteristic_systems::SDR,
sdp::colorimetries::BT709,
{},
{},
sdp::packing_modes::general,
sdp::smpte_standard_numbers::ST2110_20_2017,
sdp::type_parameters::type_N,
{},
{},
{},
{},
{}
}
};

std::pair<nmos::sdp_parameters, nmos::video_raw_parameters> wacky{
{
U("wacky"),
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("37") },
{ U("CMAX"), U("42") },
{ U("MAXUDP"), U("57") },
{ U("TSMODE"), U("SAMP") },
{ U("TSDELAY"), U("82") }
}
},
{
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,
37,
42,
57,
sdp::timestamp_modes::SAMP,
82
}
};

for (auto& test : { example, wacky })
{
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);
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);
}
}

////////////////////////////////////////////////////////////////////////////////////////////
BST_TEST_CASE(testSdpParametersAudioL)
{
std::pair<nmos::sdp_parameters, nmos::audio_L_parameters> example{
{
U("example"),
sdp::media_types::audio,
{
97,
U("L24"),
48000,
8
},
{
{ U("channel-order"), U("SMPTE2110.(51,ST)") }
},
{},
0.125
},
{
8,
24,
48000,
U("SMPTE2110.(51,ST)"), // not testing nmos::make_fmtp_channel_order here
{},
{},
0.125
}
};

std::pair<nmos::sdp_parameters, nmos::audio_L_parameters> wacky{
{
U("wacky"),
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("82") }
},
{},
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,
82,
0.333
}
};

for (auto& test : { example, wacky })
{
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);
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);
}
}

////////////////////////////////////////////////////////////////////////////////////////////
BST_TEST_CASE(testSdpParametersVideoSmpte291)
{
std::pair<nmos::sdp_parameters, nmos::video_smpte291_parameters> example{
{
U("example"),
sdp::media_types::video,
{
100,
U("smpte291"),
90000
},
{
{ U("DID_SDID"), U("{0x41,0x01}") },
{ U("VPID_Code"), U("133") }
}
},
{
{ { 0x41, 0x01 } },
nmos::vpid_codes::vpid_1_5Gbps_1080_line,
{},
{},
{},
{},
{},
{}
}
};

std::pair<nmos::sdp_parameters, nmos::video_smpte291_parameters> wacky{
{
U("wacky"),
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("37") },
{ U("TSMODE"), U("SAMP") },
{ U("TSDELAY"), U("82") }
}
},
{
{ { 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,
37,
sdp::timestamp_modes::SAMP,
82
}
};

for (auto& test : { example, wacky })
{
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);
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);
}
}

////////////////////////////////////////////////////////////////////////////////////////////
BST_TEST_CASE(testSdpParametersVideoSmpte2022_6)
{
std::pair<nmos::sdp_parameters, nmos::video_SMPTE2022_6_parameters> example{
{
U("example"),
sdp::media_types::video,
{
98,
U("SMPTE2022-6"),
27000000
},
{
{ U("TP"), U("2110TPN") }
}
},
{
sdp::type_parameters::type_N,
{}
}
};

std::pair<nmos::sdp_parameters, nmos::video_SMPTE2022_6_parameters> wacky{
{
U("wacky"),
sdp::media_types::video,
{
123,
U("SMPTE2022-6"),
27000000
},
{
{ U("TP"), U("2110TPW") },
{ U("TROFF"), U("37") }
}
},
{
sdp::type_parameters::type_W,
37
}
};

for (auto& test : { example, wacky })
{
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);
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);
}
}

0 comments on commit 4f1844d

Please sign in to comment.