diff options
Diffstat (limited to 'packages/meshbay-node/src')
| -rw-r--r-- | packages/meshbay-node/src/meshbay_node/media_probe.py | 8 | ||||
| -rw-r--r-- | packages/meshbay-node/src/meshbay_node/transport/webrtc_server.py | 49 |
2 files changed, 51 insertions, 6 deletions
diff --git a/packages/meshbay-node/src/meshbay_node/media_probe.py b/packages/meshbay-node/src/meshbay_node/media_probe.py index e0c59e3..ad668fa 100644 --- a/packages/meshbay-node/src/meshbay_node/media_probe.py +++ b/packages/meshbay-node/src/meshbay_node/media_probe.py @@ -43,6 +43,14 @@ async def probe_video( faithfully reports "hev1..." for a source this pipeline cannot actually deliver copied. + **A `None` codec string means "this must be re-encoded", not "this cannot + be played".** Only the four codecs a browser can decode through MediaSource + are mapped; everything else — MPEG-4 Part 2 (Xvid, DivX), MPEG-2, VC-1, + WMV, Theora — has no string to report because there is no browser decoder + to report it to, and the streaming path answers that by re-encoding to + H264. It answered it by refusing until 2026-09-09, which read to the + operator as a broken file rather than as an unwired code path. + width/height come from the same ffprobe call (one extra `-show_entries` field, no second process spawn) — resolution is deliberately never guessed from the filename (docs/mediacenter.md §3.5). diff --git a/packages/meshbay-node/src/meshbay_node/transport/webrtc_server.py b/packages/meshbay-node/src/meshbay_node/transport/webrtc_server.py index 507650a..a0efa83 100644 --- a/packages/meshbay-node/src/meshbay_node/transport/webrtc_server.py +++ b/packages/meshbay-node/src/meshbay_node/transport/webrtc_server.py @@ -5673,8 +5673,13 @@ class WebRTCPeerSession: self._send({"type": "error", "detail": f"Probe failed: {e}"}) return - if not codec_str: - self._send({"type": "error", "detail": "Unsupported video codec"}) + # No video stream at all is the only thing this path cannot serve, and + # it is the only thing refused here. A source with no MSE codec string + # is emphatically not that — it is the case the re-encode below exists + # for, and refusing it here (as "Unsupported video codec") is what this + # fixed. + if not raw_video_codec: + self._send({"type": "error", "detail": "No video stream in this file"}) return # Where to begin. Seeking is a stream restarted somewhere else: the @@ -5713,12 +5718,44 @@ class WebRTCPeerSession: # decode problem as E-AC-3, just without ffmpeg also refusing to mux # it). Transcoding audio is cheap; it does not change the cost model # the transcode-slot semaphore is sized around. - transcode_video = ( - raw_video_codec in BROWSER_INCOMPATIBLE_VIDEO_CODECS - and self._ctx.get("transcode_incompatible_video", True) - ) + # + # Two kinds of source cannot be copied, and both re-encode: + # + # - one whose MSE codec string is real but that no mainstream browser + # decodes — HEVC, BROWSER_INCOMPATIBLE_VIDEO_CODECS; + # - one with **no MSE codec string at all**: MPEG-4 Part 2 (Xvid, + # DivX), MPEG-2, VC-1, WMV, Theora. `stream_init` has to carry a + # string the client puts through MediaSource.isTypeSupported, and + # `probe_video` returns None for these precisely because no browser + # has a MediaSource decoder for them, so there is none to carry. + # This second kind used to be refused outright with "Unsupported + # video codec" — which named the source's problem and not the + # node's answer to it, since ffmpeg re-encodes these in real time on + # any machine that can run this daemon. Reported live against an + # Xvid/MP3 .avi. `transcode_incompatible_video`'s own documentation + # (draft-v6 §2.11) already said "HEVC *and other browser- + # incompatible video codecs*"; only HEVC was ever wired up. + can_copy = (bool(codec_str) + and raw_video_codec not in BROWSER_INCOMPATIBLE_VIDEO_CODECS) + allow_transcode = self._ctx.get("transcode_incompatible_video", True) + transcode_video = not can_copy and allow_transcode + if not can_copy and not allow_transcode and not codec_str: + # The operator turned the fallback off and there is nothing to fall + # back *to*: a stream_init with no codec string is one the client + # refuses before the first byte arrives. Which of the two it is + # matters — "unsupported codec" sends the reader to look at the + # file, and the file is fine. + log.info("stream: %s is %s, which needs a re-encode, and " + "transcode_incompatible_video is off — refusing", + entry.name, raw_video_codec) + self._send({"type": "error", + "detail": "This video needs transcoding, which the " + "operator has turned off"}) + return map_args = ["-map", "0:v:0"] if transcode_video: + log.info("stream: re-encoding %s (%s) to H264", entry.name, + raw_video_codec) # -pix_fmt yuv420p: a 10-bit or 4:4:4 HEVC source (common for HDR # WEB-DLs) fails "-profile:v high" outright otherwise — libx264's # High profile is 8-bit 4:2:0 only. Downsampling loses nothing a |