mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-05-07 22:15:28 +03:00
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)
|