restructure and test, pure python and rust transport both _work_
This commit is contained in:
@@ -86,6 +86,105 @@ class TestRunAsync:
|
||||
assert "tcp://0.0.0.0:4444?listen" in " ".join(cmd)
|
||||
|
||||
|
||||
class TestReceiveRecordRelayAndDetect:
|
||||
"""P0 regression: single-process pipeline with 3 outputs + scene detection."""
|
||||
|
||||
def test_compiles_three_outputs(self, tmp_path):
|
||||
node = ff.receive_record_relay_and_detect(
|
||||
"tcp://0.0.0.0:4444?listen",
|
||||
tmp_path / "rec.mp4",
|
||||
"udp://127.0.0.1:4445",
|
||||
)
|
||||
cmd_str = " ".join(str(c) for c in node.compile())
|
||||
# fMP4 recording
|
||||
assert "rec.mp4" in cmd_str
|
||||
# UDP relay
|
||||
assert "udp://127.0.0.1:4445" in cmd_str
|
||||
# MJPEG pipe (scene detection output)
|
||||
assert "pipe:1" in cmd_str
|
||||
|
||||
def test_fmp4_flags(self, tmp_path):
|
||||
node = ff.receive_record_relay_and_detect(
|
||||
"tcp://0.0.0.0:4444?listen",
|
||||
tmp_path / "rec.mp4",
|
||||
"udp://127.0.0.1:4445",
|
||||
)
|
||||
cmd_str = " ".join(str(c) for c in node.compile())
|
||||
assert "frag_keyframe" in cmd_str
|
||||
assert "empty_moov" in cmd_str
|
||||
|
||||
def test_scene_filter_uses_threshold(self, tmp_path):
|
||||
node = ff.receive_record_relay_and_detect(
|
||||
"tcp://0.0.0.0:4444?listen",
|
||||
tmp_path / "rec.mp4",
|
||||
"udp://127.0.0.1:4445",
|
||||
scene_threshold=0.25,
|
||||
)
|
||||
cmd_str = " ".join(str(c) for c in node.compile())
|
||||
assert "0.25" in cmd_str
|
||||
assert "scene" in cmd_str
|
||||
assert "showinfo" in cmd_str
|
||||
|
||||
def test_flush_expression_included_when_flush_frames_gt_0(self, tmp_path):
|
||||
"""P0 regression: flush trick must be present to push real frame through buffer."""
|
||||
node = ff.receive_record_relay_and_detect(
|
||||
"tcp://0.0.0.0:4444?listen",
|
||||
tmp_path / "rec.mp4",
|
||||
"udp://127.0.0.1:4445",
|
||||
flush_frames=2,
|
||||
)
|
||||
cmd_str = " ".join(str(c) for c in node.compile())
|
||||
# Flush expression: eq(n,prev_selected_n+1)*mod(selected_n,N)
|
||||
assert "prev_selected_n" in cmd_str
|
||||
assert "mod" in cmd_str
|
||||
|
||||
def test_no_flush_expression_when_flush_frames_zero(self, tmp_path):
|
||||
"""P0 regression: flush=0 should produce a clean scene-only filter."""
|
||||
node = ff.receive_record_relay_and_detect(
|
||||
"tcp://0.0.0.0:4444?listen",
|
||||
tmp_path / "rec.mp4",
|
||||
"udp://127.0.0.1:4445",
|
||||
flush_frames=0,
|
||||
)
|
||||
cmd_str = " ".join(str(c) for c in node.compile())
|
||||
assert "prev_selected_n" not in cmd_str
|
||||
|
||||
def test_flush_mod_value_matches_flush_frames(self, tmp_path):
|
||||
"""P0 regression: mod value must be flush_frames+1 to prevent chaining.
|
||||
|
||||
ffmpeg-python escapes commas in filtergraph as \\, so we check the
|
||||
escaped form in the compiled command.
|
||||
"""
|
||||
for n in [1, 2, 3]:
|
||||
node = ff.detect_scenes_from_pipe(flush_frames=n)
|
||||
cmd_str = " ".join(str(c) for c in node.compile())
|
||||
# Commas in filter expressions are escaped as \, in filtergraph
|
||||
assert f"mod(selected_n\\,{n + 1})" in cmd_str
|
||||
|
||||
|
||||
class TestDetectScenesFromPipe:
|
||||
def test_reads_from_stdin(self):
|
||||
node = ff.detect_scenes_from_pipe()
|
||||
cmd_str = " ".join(str(c) for c in node.compile())
|
||||
assert "pipe:0" in cmd_str
|
||||
|
||||
def test_writes_mjpeg_to_stdout(self):
|
||||
node = ff.detect_scenes_from_pipe()
|
||||
cmd_str = " ".join(str(c) for c in node.compile())
|
||||
assert "pipe:1" in cmd_str
|
||||
assert "mjpeg" in cmd_str
|
||||
|
||||
def test_includes_flush_expression(self):
|
||||
node = ff.detect_scenes_from_pipe(flush_frames=2)
|
||||
cmd_str = " ".join(str(c) for c in node.compile())
|
||||
assert "prev_selected_n" in cmd_str
|
||||
|
||||
def test_h264_input_format(self):
|
||||
node = ff.detect_scenes_from_pipe()
|
||||
cmd_str = " ".join(str(c) for c in node.compile())
|
||||
assert "h264" in cmd_str
|
||||
|
||||
|
||||
class TestStopProc:
|
||||
def test_sends_sigint_then_waits(self):
|
||||
proc = MagicMock()
|
||||
|
||||
Reference in New Issue
Block a user