mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-05-07 05:55:27 +03:00
Some checks are pending
CI / AMD64 Build (push) Waiting to run
CI / ARM Build (push) Waiting to run
CI / Jetson Jetpack 6 (push) Waiting to run
CI / AMD64 Extra Build (push) Blocked by required conditions
CI / ARM Extra Build (push) Blocked by required conditions
CI / Synaptics Build (push) Blocked by required conditions
CI / Assemble and push default build (push) Blocked by required conditions
* use ReplayState enum * extract shared ffmpeg progress helper * make start call non-blocking with worker thread * expose replay state on status endpoint and return 202 from start * cancel in-flight ffmpeg when stop is called during preparation * add replay i18n strings for preparing and error states * show status in replay UI * navigate immediately on 202 from debug replay menus and dialog * remove unused * simplify to use Job infrastructure * tests * cleanup and tweaks * fetch schema * update api spec * formatting * fix e2e test * mypy * clean up * formatting * fix * fix test * don't try to show camera image until status reports ready * simplify loading logic * fix race in latest_frame on debug replay shutdown * remove toast when successfully stopping it gets hidden almost immediately
112 lines
3.6 KiB
Python
112 lines
3.6 KiB
Python
"""Tests for the shared ffmpeg progress helper."""
|
|
|
|
import unittest
|
|
from unittest.mock import MagicMock, patch
|
|
|
|
from frigate.util.ffmpeg import inject_progress_flags, run_ffmpeg_with_progress
|
|
|
|
|
|
class TestInjectProgressFlags(unittest.TestCase):
|
|
def test_inserts_flags_before_output_path(self):
|
|
cmd = ["ffmpeg", "-i", "in.mp4", "-c", "copy", "out.mp4"]
|
|
result = inject_progress_flags(cmd)
|
|
self.assertEqual(
|
|
result,
|
|
[
|
|
"ffmpeg",
|
|
"-i",
|
|
"in.mp4",
|
|
"-c",
|
|
"copy",
|
|
"-progress",
|
|
"pipe:2",
|
|
"-nostats",
|
|
"out.mp4",
|
|
],
|
|
)
|
|
|
|
def test_empty_cmd_returns_empty(self):
|
|
self.assertEqual(inject_progress_flags([]), [])
|
|
|
|
|
|
class TestRunFfmpegWithProgress(unittest.TestCase):
|
|
def _make_fake_proc(self, stderr_lines, returncode=0):
|
|
proc = MagicMock()
|
|
proc.stderr = iter(stderr_lines)
|
|
proc.stdin = MagicMock()
|
|
proc.returncode = returncode
|
|
proc.wait = MagicMock()
|
|
return proc
|
|
|
|
def test_emits_percent_from_out_time_us_lines(self):
|
|
captured: list[float] = []
|
|
|
|
def on_progress(percent: float) -> None:
|
|
captured.append(percent)
|
|
|
|
stderr_lines = [
|
|
"out_time_us=1000000\n",
|
|
"out_time_us=5000000\n",
|
|
"progress=end\n",
|
|
]
|
|
proc = self._make_fake_proc(stderr_lines)
|
|
proc.stderr = MagicMock()
|
|
proc.stderr.__iter__ = lambda self: iter(stderr_lines)
|
|
proc.stderr.read = MagicMock(return_value="")
|
|
|
|
with patch("subprocess.Popen", return_value=proc):
|
|
returncode, _stderr = run_ffmpeg_with_progress(
|
|
["ffmpeg", "-i", "in", "out"],
|
|
expected_duration_seconds=10.0,
|
|
on_progress=on_progress,
|
|
use_low_priority=False,
|
|
)
|
|
|
|
self.assertEqual(returncode, 0)
|
|
self.assertEqual(len(captured), 4) # initial 0.0 + two parsed + final 100.0
|
|
self.assertAlmostEqual(captured[0], 0.0)
|
|
self.assertAlmostEqual(captured[1], 10.0)
|
|
self.assertAlmostEqual(captured[2], 50.0)
|
|
self.assertAlmostEqual(captured[3], 100.0)
|
|
|
|
def test_passes_started_process_to_callback(self):
|
|
proc = self._make_fake_proc([])
|
|
proc.stderr = MagicMock()
|
|
proc.stderr.__iter__ = lambda self: iter([])
|
|
proc.stderr.read = MagicMock(return_value="")
|
|
|
|
seen: list = []
|
|
|
|
with patch("subprocess.Popen", return_value=proc):
|
|
run_ffmpeg_with_progress(
|
|
["ffmpeg", "out"],
|
|
expected_duration_seconds=1.0,
|
|
process_started=lambda p: seen.append(p),
|
|
use_low_priority=False,
|
|
)
|
|
|
|
self.assertEqual(seen, [proc])
|
|
|
|
def test_clamps_percent_to_0_100(self):
|
|
captured: list[float] = []
|
|
|
|
def on_progress(percent: float) -> None:
|
|
captured.append(percent)
|
|
|
|
stderr_lines = ["out_time_us=999999999999\n"]
|
|
proc = self._make_fake_proc(stderr_lines)
|
|
proc.stderr = MagicMock()
|
|
proc.stderr.__iter__ = lambda self: iter(stderr_lines)
|
|
proc.stderr.read = MagicMock(return_value="")
|
|
|
|
with patch("subprocess.Popen", return_value=proc):
|
|
run_ffmpeg_with_progress(
|
|
["ffmpeg", "out"],
|
|
expected_duration_seconds=10.0,
|
|
on_progress=on_progress,
|
|
use_low_priority=False,
|
|
)
|
|
|
|
# initial 0.0 then a clamped reading
|
|
self.assertEqual(captured[-1], 100.0)
|