diff options
Diffstat (limited to 'packages/meshbay-node/tests/test_stream_seek_reports_the_keyframe.py')
| -rw-r--r-- | packages/meshbay-node/tests/test_stream_seek_reports_the_keyframe.py | 51 |
1 files changed, 36 insertions, 15 deletions
diff --git a/packages/meshbay-node/tests/test_stream_seek_reports_the_keyframe.py b/packages/meshbay-node/tests/test_stream_seek_reports_the_keyframe.py index acd2ebb..9aea2b4 100644 --- a/packages/meshbay-node/tests/test_stream_seek_reports_the_keyframe.py +++ b/packages/meshbay-node/tests/test_stream_seek_reports_the_keyframe.py @@ -9,16 +9,24 @@ further along than it did. That was a wrong label while only the scrubber read it. It became a wrong *answer* when subtitles arrived: their cues carry the source's own absolute -timestamps, so the mismatch put every line on screen a GOP before it was -spoken. Measured on a real H264 title, seeking to 600 s, 2650 s and 5000 s -landed on keyframes 0.82 s, 1.56 s and 4.64 s earlier. +timestamps, so the mismatch put every line on screen before it was spoken. -**The assertion is on the decoded picture, not on the number.** A test that -only compared `stream_init["start"]` against an expected keyframe would agree -with the implementation by construction — both would be reading the same -ffprobe. The first frame delivered is decoded and matched against the source -frame at the position the node claims, which is a statement about what was -served rather than about what was computed. +**Where the seek lands is measured, not predicted, and that distinction is +this module's subject.** The first attempt scanned ffprobe's key frames and +took the last one at or before the request. It was wrong twice: Matroska's +Cues index only some keyframes, so the seek backs off to an indexed one that +can be much earlier, and the landing point moves with **which streams are +mapped**, because the container is positioned where every mapped stream has +data. On a real title, one seek answered 4909.863 s from the frame list and +delivered 4907.236 s — 2.65 s of subtitles standing away from the voice, which +is what a viewer reported after the first fix. + +**The assertion is therefore on the decoded picture, not on the number.** A +test comparing `stream_init["start"]` against an expected keyframe would agree +with the implementation by construction, both reading the same probe. The +first frame delivered is decoded and matched against the source frame at the +position the node claims, which is a statement about what was served rather +than about what was computed. """ import shutil @@ -33,7 +41,7 @@ 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, - _keyframe_at_or_before, + _seek_lands_at, ) from conftest import needs_subprocess, one_root @@ -121,17 +129,30 @@ def _frame_md5(path: Path, at: float | None = None) -> str: return hashlib.md5(proc.stdout).hexdigest() +_MAPS = ["-map", "0:v:0", "-map", "0:a:0"] + + @pytest.mark.asyncio -async def test_the_lookup_finds_the_keyframe_the_seek_will_land_on(tmp_path): +async def test_the_probe_measures_where_the_seek_lands(tmp_path): + """Measured with the mapping the stream will use, never predicted. + + A scan of ffprobe's key frames answers a different question: Matroska + indexes only some keyframes, and the landing point also moves with which + audio track is mapped, because the container is positioned where every + mapped stream has data. On a real title those two answers were 4909.863 + and 4907.236 — 2.65 s of subtitles standing away from the voice. + """ clip = tmp_path / "clip.mp4" _make_h264_clip(clip) - assert await _keyframe_at_or_before(clip, _SEEK_TO) == pytest.approx( + assert await _seek_lands_at(clip, _SEEK_TO, _MAPS) == pytest.approx( _EXPECTED_KEYFRAME, abs=0.05) # A position that *is* a keyframe answers itself, not the one before. - assert await _keyframe_at_or_before(clip, 20.0) == pytest.approx(20.0, abs=0.05) - # Before the first one there is nothing earlier to find. - assert await _keyframe_at_or_before(clip, 0) == 0.0 + assert await _seek_lands_at(clip, 20.0, _MAPS) == pytest.approx(20.0, abs=0.05) + # A seek never lands after what was asked for. + for t in (7.0, 15.0, 23.0): + landed = await _seek_lands_at(clip, t, _MAPS) + assert landed is not None and landed <= t + 0.05, (t, landed) @pytest.mark.asyncio |