Skip to content

Commit

Permalink
Add _or_defaults versions of the format-specific parameters parsing f…
Browse files Browse the repository at this point in the history
…unctions (#426)

* Refactor handling of required format-specific parameters

* Remove potential misleading error message
Since an 'empty' fmtp attribute would appear the same at this abstraction, it's better to rely on reporting omission of specific required format-specific parameters

* Switch if-else branches for consistency between required and optional parameters

* Add _or_defaults versions of the functions that normally throw when required parameters are omitted - these functions still throw if they encounter invalid values
  • Loading branch information
garethsb authored Jan 17, 2025
1 parent 0af3b66 commit 0b4c4ba
Show file tree
Hide file tree
Showing 4 changed files with 57 additions and 22 deletions.
49 changes: 30 additions & 19 deletions Development/nmos/sdp_utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1284,34 +1284,33 @@ namespace nmos
}

// Get additional "video/raw" parameters from the SDP parameters
video_raw_parameters get_video_raw_parameters(const sdp_parameters& sdp_params)
template <typename MissingRequiredParameter>
video_raw_parameters get_video_raw_parameters(const sdp_parameters& sdp_params, MissingRequiredParameter missing = MissingRequiredParameter{})
{
video_raw_parameters params;

if (sdp_params.fmtp.empty()) throw details::sdp_processing_error("missing attribute: fmtp");

// See SMPTE ST 2110-20:2017 Section 7.2 Required Media Type Parameters
// and Section 7.3 Media Type Parameters with default values

const auto sampling = details::find_fmtp(sdp_params.fmtp, sdp::fields::sampling);
if (sdp_params.fmtp.end() == sampling) throw details::sdp_processing_error("missing format parameter: sampling");
params.sampling = sdp::sampling{ sampling->second };
if (sdp_params.fmtp.end() != sampling) params.sampling = sdp::sampling{ sampling->second };
else missing(sdp::fields::sampling);

const auto depth = details::find_fmtp(sdp_params.fmtp, sdp::fields::depth);
if (sdp_params.fmtp.end() == depth) throw details::sdp_processing_error("missing format parameter: depth");
params.depth = utility::istringstreamed<uint32_t>(depth->second);
if (sdp_params.fmtp.end() != depth) params.depth = utility::istringstreamed<uint32_t>(depth->second);
else missing(sdp::fields::depth);

const auto width = details::find_fmtp(sdp_params.fmtp, sdp::fields::width);
if (sdp_params.fmtp.end() == width) throw details::sdp_processing_error("missing format parameter: width");
params.width = utility::istringstreamed<uint32_t>(width->second);
if (sdp_params.fmtp.end() != width) params.width = utility::istringstreamed<uint32_t>(width->second);
else missing(sdp::fields::width);

const auto height = details::find_fmtp(sdp_params.fmtp, sdp::fields::height);
if (sdp_params.fmtp.end() == height) throw details::sdp_processing_error("missing format parameter: height");
params.height = utility::istringstreamed<uint32_t>(height->second);
if (sdp_params.fmtp.end() != height) params.height = utility::istringstreamed<uint32_t>(height->second);
else missing(sdp::fields::height);

const auto exactframerate = details::find_fmtp(sdp_params.fmtp, sdp::fields::exactframerate);
if (sdp_params.fmtp.end() == exactframerate) throw details::sdp_processing_error("missing format parameter: exactframerate");
params.exactframerate = nmos::details::parse_exactframerate(exactframerate->second);
if (sdp_params.fmtp.end() != exactframerate) params.exactframerate = nmos::details::parse_exactframerate(exactframerate->second);
else missing(sdp::fields::exactframerate);

// optional
const auto interlace = details::find_fmtp(sdp_params.fmtp, sdp::fields::interlace);
Expand All @@ -1326,8 +1325,8 @@ namespace nmos
if (sdp_params.fmtp.end() != tcs) params.tcs = sdp::transfer_characteristic_system{ tcs->second };

const auto colorimetry = details::find_fmtp(sdp_params.fmtp, sdp::fields::colorimetry);
if (sdp_params.fmtp.end() == colorimetry) throw details::sdp_processing_error("missing format parameter: colorimetry");
params.colorimetry = sdp::colorimetry{ colorimetry->second };
if (sdp_params.fmtp.end() != colorimetry) params.colorimetry = sdp::colorimetry{ colorimetry->second };
else missing(sdp::fields::colorimetry);

// optional
const auto range = details::find_fmtp(sdp_params.fmtp, sdp::fields::range);
Expand All @@ -1338,12 +1337,12 @@ namespace nmos
if (sdp_params.fmtp.end() != par) params.par = nmos::details::parse_pixel_aspect_ratio(par->second);

const auto pm = details::find_fmtp(sdp_params.fmtp, sdp::fields::packing_mode);
if (sdp_params.fmtp.end() == pm) throw details::sdp_processing_error("missing format parameter: PM");
params.pm = sdp::packing_mode{ pm->second };
if (sdp_params.fmtp.end() != pm) params.pm = sdp::packing_mode{ pm->second };
else missing(sdp::fields::packing_mode);

const auto ssn = details::find_fmtp(sdp_params.fmtp, sdp::fields::smpte_standard_number);
if (sdp_params.fmtp.end() == ssn) throw details::sdp_processing_error("missing format parameter: SSN");
params.ssn = sdp::smpte_standard_number{ ssn->second };
if (sdp_params.fmtp.end() != ssn) params.ssn = sdp::smpte_standard_number{ ssn->second };
else missing(sdp::fields::smpte_standard_number);

// "Senders and Receivers compliant to [ST 2110-20] shall comply with the provisions of SMPTE ST 2110-21."
// See SMPTE ST 2110-20:2017 Section 6.1.1
Expand Down Expand Up @@ -1378,6 +1377,18 @@ namespace nmos
return params;
}

// Get additional "video/raw" parameters from the SDP parameters
video_raw_parameters get_video_raw_parameters(const sdp_parameters& sdp_params)
{
return get_video_raw_parameters<details::throw_missing_fmtp>(sdp_params);
}

// Get additional "video/raw" parameters from the SDP parameters
video_raw_parameters get_video_raw_parameters_or_defaults(const sdp_parameters& sdp_params)
{
return get_video_raw_parameters<>(sdp_params, [](const utility::string_t&) {});
}

// Get additional "audio/L" parameters from the SDP parameters
audio_L_parameters get_audio_L_parameters(const sdp_parameters& sdp_params)
{
Expand Down
10 changes: 10 additions & 0 deletions Development/nmos/sdp_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include <stdexcept>
#include "bst/any.h"
#include "bst/optional.h"
#include "cpprest/basic_utils.h"
#include "sdp/json.h"
#include "sdp/ntp.h"
#include "nmos/did_sdid.h"
Expand Down Expand Up @@ -506,6 +507,7 @@ namespace nmos
sdp_parameters make_video_raw_sdp_parameters(const utility::string_t& session_name, const video_raw_parameters& params, uint64_t payload_type, const std::vector<utility::string_t>& media_stream_ids = {}, const std::vector<sdp_parameters::ts_refclk_t>& ts_refclk = {});
// Get additional "video/raw" parameters from the SDP parameters
video_raw_parameters get_video_raw_parameters(const sdp_parameters& sdp_params);
video_raw_parameters get_video_raw_parameters_or_defaults(const sdp_parameters& sdp_params);

// Construct additional "audio/L" parameters from the IS-04 resources, using default values for unspecified items
audio_L_parameters make_audio_L_parameters(const web::json::value& node, const web::json::value& source, const web::json::value& flow, const web::json::value& sender, bst::optional<double> packet_time);
Expand Down Expand Up @@ -582,6 +584,14 @@ namespace nmos
return std::runtime_error{ "sdp processing error - " + message };
}

struct throw_missing_fmtp
{
void operator()(const utility::string_t& name) const
{
throw details::sdp_processing_error("missing format parameter: " + utility::us2s(name));
}
};

inline sdp_parameters::fmtp_t::const_iterator find_fmtp(const sdp_parameters::fmtp_t& fmtp, const utility::string_t& name)
{
return std::find_if(fmtp.begin(), fmtp.end(), [&](const sdp_parameters::fmtp_t::value_type& param)
Expand Down
19 changes: 16 additions & 3 deletions Development/nmos/video_jxsv.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -186,13 +186,14 @@ namespace nmos
}

// Get additional "video/jxsv" parameters from the SDP parameters
video_jxsv_parameters get_video_jxsv_parameters(const sdp_parameters& sdp_params)
template <typename MissingRequiredParameter>
video_jxsv_parameters get_video_jxsv_parameters(const sdp_parameters& sdp_params, MissingRequiredParameter missing = MissingRequiredParameter{})
{
video_jxsv_parameters params;

const auto packetmode = details::find_fmtp(sdp_params.fmtp, sdp::video_jxsv::fields::packetmode);
if (sdp_params.fmtp.end() == packetmode) throw details::sdp_processing_error("missing format parameter: packetmode");
params.packetmode = (sdp::video_jxsv::packetization_mode)utility::istringstreamed<uint32_t>(packetmode->second);
if (sdp_params.fmtp.end() != packetmode) params.packetmode = (sdp::video_jxsv::packetization_mode)utility::istringstreamed<uint32_t>(packetmode->second);
else missing(sdp::video_jxsv::fields::packetmode);

// optional
const auto transmode = details::find_fmtp(sdp_params.fmtp, sdp::video_jxsv::fields::transmode);
Expand Down Expand Up @@ -286,6 +287,18 @@ namespace nmos
return params;
}

// Get additional "video/jxsv" parameters from the SDP parameters
video_jxsv_parameters get_video_jxsv_parameters(const sdp_parameters& sdp_params)
{
return get_video_jxsv_parameters<details::throw_missing_fmtp>(sdp_params);
}

// Get additional "video/jxsv" parameters from the SDP parameters
video_jxsv_parameters get_video_jxsv_parameters_or_defaults(const sdp_parameters& sdp_params)
{
return get_video_jxsv_parameters<>(sdp_params, [](const utility::string_t&) {});
}

// Calculate the format bit rate (kilobits/second) from the specified frame rate, dimensions and bits per pixel
uint64_t get_video_jxsv_bit_rate(const nmos::rational& grain_rate, uint32_t frame_width, uint32_t frame_height, double bits_per_pixel)
{
Expand Down
1 change: 1 addition & 0 deletions Development/nmos/video_jxsv.h
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,7 @@ namespace nmos
sdp_parameters make_video_jxsv_sdp_parameters(const utility::string_t& session_name, const video_jxsv_parameters& params, uint64_t payload_type, const std::vector<utility::string_t>& media_stream_ids = {}, const std::vector<sdp_parameters::ts_refclk_t>& ts_refclk = {});
// Get additional "video/jxsv" parameters from the SDP parameters
video_jxsv_parameters get_video_jxsv_parameters(const sdp_parameters& sdp_params);
video_jxsv_parameters get_video_jxsv_parameters_or_defaults(const sdp_parameters& sdp_params);

// Construct SDP parameters for "video/jxsv"
inline sdp_parameters make_sdp_parameters(const utility::string_t& session_name, const video_jxsv_parameters& params, uint64_t payload_type, const std::vector<utility::string_t>& media_stream_ids = {}, const std::vector<sdp_parameters::ts_refclk_t>& ts_refclk = {})
Expand Down

0 comments on commit 0b4c4ba

Please sign in to comment.