1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
|
"""
A video the browser cannot decode is re-encoded to H264, never refused and
never copied. There are two kinds of those, and both are here.
**A codec string that is real but useless.** A real HEVC/EAC3 WEB-DL streamed
fine over MNP (ffprobe/VLC play it) but the browser reported "Codec not
supported for streaming: hev1.1.6.L93.B0,mp4a.40.2" from
MediaSource.isTypeSupported — Chrome has no HEVC decoder on most non-Apple
platforms. "-c:v copy" on such a codec is not a mux failure the way EAC3 audio
is (test_stream_audio_transcode.py); ffmpeg happily remuxes it, and the browser
is the one that then refuses it, silently, at playback rather than at
stream_init. That is what BROWSER_INCOMPATIBLE_VIDEO_CODECS names.
**No codec string at all.** MPEG-4 Part 2 (Xvid, DivX), MPEG-2, VC-1, WMV and
Theora have no MediaSource decoder anywhere, so `probe_video` maps them to
None — there is nothing to put in `stream_init` for the client to check. Until
2026-09-09 the streaming path read that None as "unsupported" and refused, with
"Unsupported video codec", on files ffmpeg re-encodes in real time. Reported
live against an episode rip in a `.avi` — mpeg4 video, mp3 audio, 720x404 —
which the reporting machine re-encodes at about six times playback speed. The setting
that governs it, `transcode_incompatible_video`, was documented from the start
as covering "HEVC *and other browser-incompatible video codecs*" (draft-v6
§2.11); only HEVC was ever wired up.
These tests spawn real ffmpeg/ffprobe against small synthetic files (lavfi
test sources, ~1s), the same style as test_stream_audio_transcode.py.
"""
import shutil
import subprocess
from pathlib import Path
import pytest
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
from meshbay_common.crypto import generate_gek
from meshbay_common.webcrypto import chunk_key_aes, decrypt_chunk_aes
from meshbay_node.indexer.group_index import GroupIndex
from meshbay_node.transport.webrtc_server import WebRTCPeerSession, _probe_video
from conftest import needs_subprocess, one_root
_HAVE_FFMPEG = shutil.which("ffmpeg") and shutil.which("ffprobe")
_ENCODERS = subprocess.run(["ffmpeg", "-hide_banner", "-encoders"],
capture_output=True).stdout if _HAVE_FFMPEG else b""
# libx265 gates the HEVC cases and only those: an ffmpeg without it still
# encodes MPEG-4 Part 2 (a built-in) and can therefore still prove the half of
# this policy that has no codec string. Marking the whole module on it skipped
# the reported defect on any box without x265.
_HAVE_HEVC_ENCODER = b"libx265" in _ENCODERS
_HAVE_MP3_ENCODER = b"libmp3lame" in _ENCODERS
pytestmark = [
pytest.mark.asyncio,
pytest.mark.skipif(not _HAVE_FFMPEG, reason="ffmpeg/ffprobe not installed"),
needs_subprocess,
]
needs_hevc = pytest.mark.skipif(not _HAVE_HEVC_ENCODER,
reason="ffmpeg built without libx265")
needs_mp3 = pytest.mark.skipif(not _HAVE_MP3_ENCODER,
reason="ffmpeg built without libmp3lame")
def _make_mpeg4_clip(path: Path) -> None:
"""~1s of Xvid-style MPEG-4 Part 2 video + MP3 audio in an AVI.
The same shape as the reported file, down to the container: ffprobe reports
`codec_name: mpeg4`, which is what an Xvid encoder produces and what
`probe_video` has no MSE string for.
"""
subprocess.run(
["ffmpeg", "-hide_banner", "-loglevel", "error", "-y",
"-f", "lavfi", "-i", "testsrc=size=320x240:rate=25:duration=1",
"-f", "lavfi", "-i", "sine=frequency=440:duration=1:sample_rate=48000",
"-c:v", "mpeg4", "-c:a", "libmp3lame",
str(path)],
check=True, capture_output=True,
)
def _make_hevc_clip(path: Path) -> None:
"""~1s of HEVC video + AAC audio — a minimal stand-in for a real HEVC WEB-DL."""
subprocess.run(
["ffmpeg", "-hide_banner", "-loglevel", "error", "-y",
"-f", "lavfi", "-i", "testsrc=size=320x240:rate=25:duration=1",
"-f", "lavfi", "-i", "sine=frequency=440:duration=1:sample_rate=48000",
"-c:v", "libx265", "-preset", "ultrafast", "-c:a", "aac",
str(path)],
check=True, capture_output=True,
)
def _session(video_path: Path, gek: bytes, *, transcode_incompatible_video: bool = True):
import blake3
file_bytes = video_path.read_bytes()
file_id = blake3.blake3(file_bytes).hexdigest()
sk_node = Ed25519PrivateKey.generate()
index = GroupIndex(group_id="g" * 32, sk_node=sk_node, gek=gek)
from meshbay_common.protocol import IndexEntry
index.add_entry(IndexEntry(
id=file_id, name=video_path.name, path=video_path.parent.name,
size=len(file_bytes), type="video", added_at=0))
session = WebRTCPeerSession.__new__(WebRTCPeerSession)
session._ctx = {
"roots": one_root(video_path.parent),
"index": index,
"gek": gek,
"sk_node": sk_node,
"max_concurrent_streams": 4,
"transcode_incompatible_video": transcode_incompatible_video,
}
session._group_id = None
session._user_id = "tester"
session._stream_stopped = False
session._stream_keepalives = 0
session.sent = []
session._send = session.sent.append
session._audit = lambda *a, **k: None
return session, file_id
def _reassemble(sent: list[dict], gek: bytes, file_id: str) -> bytes:
file_hash = bytes.fromhex(file_id)
segments = sorted(
(m for m in sent if m.get("type") == "stream_data"),
key=lambda m: m["segment_index"])
out = b""
for m in segments:
key = chunk_key_aes(gek, file_hash, m["segment_index"])
out += decrypt_chunk_aes(key, m["nonce"], m["ct"])
return out
def _output_video_codec(path: Path) -> str:
probe = subprocess.run(
["ffprobe", "-v", "error", "-select_streams", "v:0",
"-show_entries", "stream=codec_name", "-of", "csv=p=0", str(path)],
check=True, capture_output=True, text=True)
return probe.stdout.strip()
@needs_hevc
async def test_hevc_video_is_transcoded_to_h264_by_default(tmp_path):
clip = tmp_path / "clip.mkv"
_make_hevc_clip(clip)
gek = generate_gek()
session, file_id = _session(clip, gek)
await session._stream_video_inner({"file_id": file_id, "start": 0, "credits": 0})
errors = [m for m in session.sent if m.get("type") == "error"]
assert not errors, f"streaming must not fail: {errors}"
init = next(m for m in session.sent if m.get("type") == "stream_init")
assert init["codec"].startswith("avc1."), (
"the reported codec must be the transcoded H264 string, never the "
f"source's hev1 string a browser cannot decode: {init['codec']}")
remuxed = _reassemble(session.sent, gek, file_id)
out_path = tmp_path / "out.mp4"
out_path.write_bytes(remuxed)
assert _output_video_codec(out_path) == "h264", \
"the bytes on the wire must actually be H264, not just the reported label"
@needs_hevc
async def test_hevc_transcode_can_be_disabled_by_the_operator(tmp_path):
clip = tmp_path / "clip.mkv"
_make_hevc_clip(clip)
gek = generate_gek()
session, file_id = _session(clip, gek, transcode_incompatible_video=False)
await session._stream_video_inner({"file_id": file_id, "start": 0, "credits": 0})
assert not [m for m in session.sent if m.get("type") == "error"]
init = next(m for m in session.sent if m.get("type") == "stream_init")
assert init["codec"].startswith("hev1."), (
"with the fallback disabled, the source is copied as-is and the "
f"original HEVC codec string must be reported unchanged: {init['codec']}")
remuxed = _reassemble(session.sent, gek, file_id)
out_path = tmp_path / "out.mp4"
out_path.write_bytes(remuxed)
assert _output_video_codec(out_path) == "hevc", \
"with the fallback disabled, the wire bytes must still be copied HEVC"
@needs_hevc
async def test_probe_video_reports_raw_codec_name_for_hevc(tmp_path):
clip = tmp_path / "clip.mkv"
_make_hevc_clip(clip)
probe = await _probe_video(str(clip))
assert probe.raw_codec_name == "hevc"
assert probe.codec is not None and probe.codec.startswith("hev1.")
@needs_mp3
async def test_probe_video_reports_no_codec_string_for_mpeg4(tmp_path):
"""The other shape, and the reason the streaming path has to read it as
"re-encode this" rather than as a verdict on the file: there is no MSE
string for MPEG-4 Part 2 because no browser has a decoder to give one to.
The raw name is still reported, which is what the caller decides on."""
clip = tmp_path / "clip.avi"
_make_mpeg4_clip(clip)
probe = await _probe_video(str(clip))
assert probe.raw_codec_name == "mpeg4"
assert probe.codec is None, (
"a codec string for MPEG-4 Part 2 would be one no browser can act on")
assert probe.has_audio is True
assert (probe.width, probe.height) == (320, 240)
@needs_mp3
async def test_a_codec_with_no_mse_string_is_transcoded_not_refused(tmp_path):
"""The reported defect.
An Xvid/MP3 .avi answered "Unsupported video codec" — a refusal, on a file
ffmpeg re-encodes faster than it plays. Nothing about the source changed;
the node simply never reached its own re-encode path.
"""
clip = tmp_path / "clip.avi"
_make_mpeg4_clip(clip)
gek = generate_gek()
session, file_id = _session(clip, gek)
await session._stream_video_inner({"file_id": file_id, "start": 0, "credits": 0})
errors = [m for m in session.sent if m.get("type") == "error"]
assert not errors, (
f"a source with no MSE codec string was refused instead of re-encoded: "
f"{errors}")
init = next(m for m in session.sent if m.get("type") == "stream_init")
assert init["codec"].startswith("avc1."), (
"stream_init must advertise the H264 the client is about to receive; "
f"there is no string for the source and none may be invented: {init['codec']}")
remuxed = _reassemble(session.sent, gek, file_id)
out_path = tmp_path / "out.mp4"
out_path.write_bytes(remuxed)
assert _output_video_codec(out_path) == "h264", (
"the bytes on the wire must actually be H264, not just the label")
@needs_mp3
async def test_the_operator_can_refuse_the_re_encode_and_says_so(tmp_path):
"""`transcode_incompatible_video = false` still means what it says.
HEVC falls back to a copy there (the case above), because there is a codec
string to report. Here there is none, so a copy is not a lesser answer —
it is a stream_init the client refuses before the first byte. The refusal
has to name the setting: "Unsupported video codec" is what sent the last
reader to look at a file that was fine.
"""
clip = tmp_path / "clip.avi"
_make_mpeg4_clip(clip)
gek = generate_gek()
session, file_id = _session(clip, gek, transcode_incompatible_video=False)
await session._stream_video_inner({"file_id": file_id, "start": 0, "credits": 0})
errors = [m for m in session.sent if m.get("type") == "error"]
assert errors, "a stream that cannot be produced must be refused, not started"
detail = errors[0]["detail"]
assert "transcoding" in detail, (
f"the refusal must point at the setting that caused it: {detail!r}")
assert not [m for m in session.sent if m.get("type") == "stream_init"], (
"a stream_init went out with no codec string the client could check")
|