Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions README.en.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ Download the latest version from [github.com/MonkyOrg/Monky/releases/latest](htt

If Windows/macOS shows a security warning, see [Download](https://monkyorg.github.io/Monky/en/download). For checksums and signatures, see [Verify Releases](https://monkyorg.github.io/Monky/en/verificar-releases).

To try it without installing anything, use the web version at [monkyweb.vercel.app](https://monkyweb.vercel.app/). It only joins servers with a secure connection (`wss://`, see [`monky tls`](https://monkyorg.github.io/Monky/en/cli#monky-tls)); hosting a server, the overlay and global shortcuts stay in the app.

## 📚 Documentation

Full usage and hosting manual at **[monkyorg.github.io/Monky/en](https://monkyorg.github.io/Monky/en/)** — installation, getting started, creating a server, hosting on a VPS and troubleshooting. ([Português](https://monkyorg.github.io/Monky/))
Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ Baixe a versão mais recente em [github.com/MonkyOrg/Monky/releases/latest](http

Se o Windows/macOS mostrar aviso de segurança, veja [Download](https://monkyorg.github.io/Monky/download). Para checksums e assinatura, veja [Verificar Releases](https://monkyorg.github.io/Monky/verificar-releases).

Para experimentar sem instalar nada, use a versão web em [monkyweb.vercel.app](https://monkyweb.vercel.app/). Ela só entra em servidores com conexão segura (`wss://`, veja [`monky tls`](https://monkyorg.github.io/Monky/cli#monky-tls)); hospedar servidor, overlay e atalhos globais continuam só no app.

## 📚 Documentação

Manual completo de uso e hospedagem em **[monkyorg.github.io/Monky](https://monkyorg.github.io/Monky/)** — instalação, primeiros passos, criar servidor, hospedar em VPS e solução de problemas. ([English](https://monkyorg.github.io/Monky/en/))
Expand Down
12 changes: 8 additions & 4 deletions apps/client/native/screen-share/src/capture/contract.h
Original file line number Diff line number Diff line change
Expand Up @@ -953,16 +953,20 @@ inline AmfColorNormalization NormalizeAmfBt709(std::span<const std::uint8_t> byt

// A Baseline encoder (AMF and NVENC "baseline", x264) emits no slice groups or redundant pictures, which is
// Constrained Baseline (H.264 A.2.1); some leave constraint_set1 clear. The compatible format (#858) declares it,
// so receivers that admit only Constrained Baseline accept the stream. The flag byte follows profile_idc (never
// zero), so no emulation prevention depends on it. Empty means no rewrite.
// so receivers that admit only Constrained Baseline accept the stream. AMF also sets constraint_set5, which has no
// meaning for Baseline (7.4.2.1.1) but takes the SPS out of WebRTC's Constrained Baseline table, so receivers
// refused it; constraint_set4/5 are cleared. The flag byte follows profile_idc (never zero), so no emulation
// prevention depends on it. Empty means no rewrite.
inline std::vector<std::uint8_t> NormalizeConstrainedBaseline(std::span<const std::uint8_t> bytes,
const VideoConfiguration& video) {
std::vector<std::uint8_t> result;
if (!video.constrainedBaseline) return result;
VisitAnnexB(bytes, [&](std::span<const std::uint8_t> nal, std::size_t begin, std::size_t) {
if ((nal.front() & 0x1fu) != 7 || nal.size() < 4 || nal[1] != 66 || (nal[2] & 0x40u)) return;
if ((nal.front() & 0x1fu) != 7 || nal.size() < 4 || nal[1] != 66) return;
const auto declared = static_cast<std::uint8_t>((nal[2] | 0x40u) & ~0x0cu);
if (declared == nal[2]) return;
if (result.empty()) result.assign(bytes.begin(), bytes.end());
result[begin + 2] = static_cast<std::uint8_t>(result[begin + 2] | 0x40u);
result[begin + 2] = declared;
});
return result;
}
Expand Down
12 changes: 12 additions & 0 deletions apps/client/native/screen-share/src/capture/contractTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -523,6 +523,18 @@ int main(int argc, char** argv) {
TestSpsOptions flagged = plain;
flagged.constraints = 0xc0;
check(NormalizeConstrainedBaseline(ParameterSets(baseline, flagged), baseline).empty());
// AMF baseline sets constraint_set5, which WebRTC receivers refuse as Constrained Baseline.
struct ConstraintFlags { std::uint8_t emitted; std::uint8_t declared; };
constexpr ConstraintFlags amfFlags[]{{0x04, 0x40}, {0x44, 0x40}, {0x48, 0x40}, {0xcc, 0xc0}};
for (const auto& [emitted, declared] : amfFlags) {
TestSpsOptions amf = plain;
amf.constraints = emitted;
const auto emittedSets = ParameterSets(baseline, amf);
const auto declaredSets = NormalizeConstrainedBaseline(emittedSets, baseline);
check(declaredSets.size() == emittedSets.size() && emittedSets[5] == emitted && declaredSets[5] == declared &&
std::equal(declaredSets.begin() + 6, declaredSets.end(), emittedSets.begin() + 6));
check(InspectAnnexB(declaredSets, baseline).sps);
}
check(NormalizeConstrainedBaseline(plainBaseline, mainVideo).empty());
check(NormalizeConstrainedBaseline(ParameterSets(mainVideo), mainVideo).empty());
rejects([&] { InspectAnnexB(plainBaseline, mainVideo); });
Expand Down
4 changes: 3 additions & 1 deletion apps/client/native/screen-share/src/capture/host.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -526,7 +526,9 @@ class Host {
description.AdapterLuid.LowPart;
return;
}
throw ContractError(IsSoftware(arguments_.encoder) ? "ERR_SCREEN_CAPTURE_DEVICE" : "ERR_SCREEN_CAPTURE_ENCODER_UNSUPPORTED",
// A software encoder accepts any real adapter 0, so reaching here means there is none: only the
// software renderer of a virtual machine or a machine without a graphics driver.
throw ContractError(IsSoftware(arguments_.encoder) ? "ERR_SCREEN_CAPTURE_NO_GPU" : "ERR_SCREEN_CAPTURE_ENCODER_UNSUPPORTED",
"The selected encoder is not supported on capture adapter 0; cross-adapter or unrequested software fallback is forbidden");
}
void CheckDevice() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,20 @@ void VerifyAdaptiveDecoderSessions() {
Check(amf_plan && amf_plan->profileLevelId == "4d0433" && amf_info.sps->compatibility == 0x04,
"AMF constrained Main SPS must be admitted without rewriting its original bytes");
Reject([&] { plan(std::nullopt, amf_info, amf_packet); }, "ERR_RTC_NEGOTIATED_SPS");
// AMF baseline (compatible format) also sets constraint_set5; it must still decode as Constrained Baseline.
for (const auto flags : std::initializer_list<std::uint8_t>{0x44, 0x48, 0x4c, 0xc4}) {
auto amf_baseline = small_sps;
amf_baseline[2] = flags;
const auto amf_baseline_packet = ParserPacket(amf_baseline);
const auto amf_baseline_info = policy::InspectAccessUnit(amf_baseline_packet);
const auto amf_baseline_plan = plan(std::nullopt, amf_baseline_info, amf_baseline_packet);
Check(amf_baseline_plan && amf_baseline_info.sps->compatibility == flags &&
amf_baseline_plan->profileLevelId == amf_baseline_info.sps->ProfileLevelId(),
"AMF Constrained Baseline with constraint_set4/5 must be admitted without rewriting its original bytes");
Check(policy::PlanDecoderSession(std::nullopt, amf_baseline_info, amf_baseline_packet,
{screen_video::H264Profile::Main, 51}, 1920, 1080, 8, options).has_value(),
"A Main receiver must admit AMF Constrained Baseline with constraint_set4/5");
}
// A browser's software encoder answers Main SDP with Main-compatible Constrained Baseline (42c0).
const auto browser_plan = policy::PlanDecoderSession(std::nullopt, small_info, smaller,
{screen_video::H264Profile::Main, 51}, 1920, 1080, 8, options);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,11 @@ void ValidateSps(const sv::H264Sps& sps, NegotiatedH264 negotiated,
throw AdapterError("ERR_RTC_NEGOTIATED_SPS",
"Actual SPS violates negotiated profile/level, geometry, or BT.709-limited input");
}
const auto actual = webrtc::ParseH264ProfileLevelId(sps.ProfileLevelId().c_str());
// constraint_set4/5 carry no meaning for Baseline (H.264 7.4.2.1.1), yet AMF sets constraint_set5 and WebRTC's
// table then refuses its Constrained Baseline. Senders that predate clearing it are still admitted.
auto declared = sps;
if (sps.profileIdc == 66) declared.compatibility = static_cast<std::uint8_t>(sps.compatibility & ~0x0cu);
const auto actual = webrtc::ParseH264ProfileLevelId(declared.ProfileLevelId().c_str());
const auto expected = negotiated.profile == sv::H264Profile::Main && !main_compatible_baseline
? webrtc::H264Profile::kProfileMain : webrtc::H264Profile::kProfileConstrainedBaseline;
// Pinned AMF emits this Main SPS byte pattern, outside WebRTC's SDP table.
Expand Down
Loading
Loading