AMWA NMOS IS-05 1.2-dev / MXL Support#483
Conversation
jonathan-r-thorpe
commented
Mar 5, 2026
- Prototype used to demonstrate MXL integration with NMOS
…e and use "auto" in /staged)
…id-auto Add support for "auto" to MXL sender flow_id transport parameter
…nnections Renamed flow_id to mxl_flow_id in MXL sender and receiver connections
garethsb
left a comment
There was a problem hiding this comment.
Forgot to submit this last week, sorry...
| //"senders": ["v", "a"], | ||
| //"receivers": [], | ||
| //"senders": ["v", "a", "d"], | ||
| //"receivers": ["v", "a", "d"], |
There was a problem hiding this comment.
Some of the comment examples in this file show what the equivalent of the default would be, some show interesting non-default examples. This was the latter (only create senders, don't create any receivers), now it's the former. Change made intentionally?
|
|
||
| // video_type: media type of video flows, e.g. "video/raw" or "video/jxsv", see nmos::media_types | ||
| //"video_type": "video/jxsv", | ||
| // video_type: media type of video flows, e.g. "video/raw", "video/jxsv", or "video/v210" for MXL Senders and Receivers, see nmos::media_types |
There was a problem hiding this comment.
| // video_type: media type of video flows, e.g. "video/raw", "video/jxsv", or "video/v210" for MXL Senders and Receivers, see nmos::media_types | |
| // video_type: media type of video flows, e.g. "video/raw", "video/jxsv" for ST 2110 senders and receivers | |
| // or "video/v210" for MXL senders and receivers, see nmos::media_types |
|
|
||
| // senders, receivers: controls which kinds of sender and receiver are instantiated by the example node | ||
| // the values must be an array of unique strings identifying the kinds of 'port', like ["v", "a", "d"], see impl::ports | ||
| // for MXL Senders and Receivers, the values must be ["xv", "xa", "xd"] |
There was a problem hiding this comment.
Although in docs we normally Title Case the NMOS keywords, that seems not to be the case in this file. Let's not end up with a mix anyway?
| // for MXL Senders and Receivers, the values must be ["xv", "xa", "xd"] | |
| // for MXL senders and receivers, the values must be like ["xv", "xa", "xd"] |
| // BCP-007-03: PATCH /staged for MXL receivers must not contain transport_file. | ||
| // See https://specs.amwa.tv/bcp-007-03/branches/publish-auto-null/docs/NMOS-With-MXL.html |
There was a problem hiding this comment.
@jonathan-r-thorpe I think this is a mistake in the spec? Given that the response schema requires that transport_file is present, I think it should be valid to stage:
"transport_file": {
"type": null,
"data": null
}There was a problem hiding this comment.
The BCP-007-03 spec is ambiguous on this so I'll raise it as an issue on the spec.
BCP-007-03 says PATCH /staged for MXL receivers is “not expected to contain” transport_file, and that controllers “MUST NOT provide” the attribute — which I read as prohibiting the key entirely. That’s stricter than the IS-05 stage schema, as you point out. I think this might become moot if the position on transport_file changes in the spec...
| { | ||
| namespace is05_schemas | ||
| { | ||
| namespace v1_2_x |
There was a problem hiding this comment.
| namespace v1_2_x | |
| namespace v1_2_dev |
| const nmos::id mxl_domain_id = model.settings.has_field(impl::fields::mxl_domain_id) | ||
| ? impl::fields::mxl_domain_id(model.settings) | ||
| : nmos::make_repeatable_id(seed_id, U("/x-nmos/mxl/domain")); |
There was a problem hiding this comment.
Does it make sense to provide a default for this? Doing so seems to imply it would be reasonable for a media function to create its own domain?
| // add optional grain_rate | ||
| flow.data[nmos::fields::grain_rate] = nmos::make_rational(frame_rate); |
There was a problem hiding this comment.
Given MXL moves us even further from SDI than ST 2022-6 and ST 2110, maybe we drop the (video) grain rate on audio?
| flow = nmos::make_raw_audio_flow(flow_id, source_id, device_id, 48000, 32, model.settings); | ||
| flow.data[nmos::fields::media_type] = value::string(U("audio/float32")); |
There was a problem hiding this comment.
⬇️ Maybe we should use make_audio_flow or have another overload of make_raw_audio_flow, so we don't have to rewrite the media_type?
| if (nmos::media_types::video_raw == video_type) | ||
| { | ||
| const auto interlace_modes = nmos::interlace_modes::progressive != interlace_mode | ||
| ? std::vector<utility::string_t>{ nmos::interlace_modes::interlaced_bff.name, nmos::interlace_modes::interlaced_tff.name, nmos::interlace_modes::interlaced_psf.name } | ||
| : std::vector<utility::string_t>{ nmos::interlace_modes::progressive.name }; | ||
| receiver.data[nmos::fields::caps][nmos::fields::constraint_sets] = value_of({ | ||
| value_of({ | ||
| { nmos::caps::format::grain_rate, nmos::make_caps_rational_constraint({ frame_rate }) }, | ||
| { nmos::caps::format::frame_width, nmos::make_caps_integer_constraint({ frame_width }) }, | ||
| { nmos::caps::format::frame_height, nmos::make_caps_integer_constraint({ frame_height }) }, | ||
| { nmos::caps::format::interlace_mode, nmos::make_caps_string_constraint(interlace_modes) }, | ||
| { nmos::caps::format::color_sampling, nmos::make_caps_string_constraint({ sampling.name }) } | ||
| }) | ||
| }); | ||
| } | ||
| else if (nmos::media_types::video_jxsv == video_type) | ||
| { | ||
| const auto max_format_bit_rate = nmos::get_video_jxsv_bit_rate(frame_rate, frame_width, frame_height, max_bits_per_pixel); | ||
| const auto max_transport_bit_rate = uint64_t(transport_bit_rate_factor * max_format_bit_rate / 1e3 + 0.5) * 1000; | ||
|
|
||
| receiver.data[nmos::fields::caps][nmos::fields::constraint_sets] = value_of({ | ||
| value_of({ | ||
| { nmos::caps::format::profile, nmos::make_caps_string_constraint({ profile.name }) }, | ||
| { nmos::caps::format::level, nmos::make_caps_string_constraint({ level.name }) }, | ||
| { nmos::caps::format::sublevel, nmos::make_caps_string_constraint({ nmos::sublevels::Sublev3bpp.name, nmos::sublevels::Sublev4bpp.name }) }, | ||
| { nmos::caps::format::bit_rate, nmos::make_caps_integer_constraint({}, nmos::no_minimum<int64_t>(), (int64_t)max_format_bit_rate) }, | ||
| { nmos::caps::transport::bit_rate, nmos::make_caps_integer_constraint({}, nmos::no_minimum<int64_t>(), (int64_t)max_transport_bit_rate) }, | ||
| { nmos::caps::transport::packet_transmission_mode, nmos::make_caps_string_constraint({ nmos::packet_transmission_modes::codestream.name }) } | ||
| }) | ||
| }); | ||
| } |
There was a problem hiding this comment.
Needs fixing to work with video/v210 and maybe video/v210a.
| } | ||
| else if (impl::ports::mxl_audio == port) | ||
| { | ||
| receiver = nmos::make_receiver(receiver_id, device_id, nmos::transports::mxl, {}, nmos::formats::audio, { nmos::media_type{ U("audio/float32") } }, model.settings); |
There was a problem hiding this comment.
We should add an nmos::media_types::audio_float32 constant? (And the MXL video ones too.)