Compare commits

...
Author SHA1 Message Date
dependabot[bot]andGitHub f3656a5043 Update transformers requirement in /docker/main
Updates the requirements on [transformers](https://github.com/huggingface/transformers) to permit the latest version.
- [Release notes](https://github.com/huggingface/transformers/releases)
- [Commits](https://github.com/huggingface/transformers/compare/v4.45.0...v5.17.0)

---
updated-dependencies:
- dependency-name: transformers
  dependency-version: 5.17.0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-09-24 18:45:21 +00:00
Josh HawkinsandGitHub 9443289112 bump onnxruntime, ruamel, and argcomplete (#24460) 2026-09-24 13:42:58 -05:00
007hacky007andGitHub 40f8ba1f7f Offer the full playback rate list on Safari (#24444)
CI / AMD64 Build (push) Canceled after 0s
CI / AMD64 Smoke Test (push) Canceled after 0s
CI / ARM Build (push) Canceled after 0s
CI / Jetson Jetpack 6 (push) Canceled after 0s
CI / AMD64 Extra Build (push) Canceled after 0s
CI / ARM Extra Build (push) Canceled after 0s
CI / Synaptics Build (push) Canceled after 0s
CI / Assemble and push default build (push) Canceled after 0s
2026-09-24 10:02:06 -05:00
markfrancisonlyandGitHub 397f5253a5 Rate events over at least one second (#24455)
* Rate events over at least one second

EventsPerSecond.eps() divided the event count by the time since start(),
which can be a few milliseconds right after a restart. Frames buffered
during an ffmpeg restart then report as 100+ fps, and the same happens to
the detector fps. Use a window of at least one second.

* Keep sub-second windows consistent

Floor the divisor at the window length when the window is shorter than a
second, so a caller with a sub-second window still gets its true rate.
2026-09-24 06:28:00 -06:00
5 changed files with 39 additions and 12 deletions
+4 -4
View File
@@ -27,7 +27,7 @@ pydantic == 2.10.*
git+https://github.com/fbcotter/py3nvml#egg=py3nvml
pytz == 2025.*
pyzmq == 27.1.*
ruamel.yaml == 0.18.*
ruamel.yaml == 0.19.*
tzlocal == 5.2
requests == 2.33.*
types-requests == 2.32.*
@@ -43,9 +43,9 @@ opencv-contrib-python == 4.11.0.*
scipy == 1.16.*
# OpenVino & ONNX
openvino == 2025.4.*
onnxruntime == 1.22.*
onnxruntime == 1.30.*
# Embeddings
transformers == 4.45.*
transformers == 5.17.*
# Generative AI
google-genai == 1.58.*
ollama == 0.6.*
@@ -58,7 +58,7 @@ pyclipper == 1.4.*
shapely == 2.0.*
rapidfuzz==3.12.*
# HailoRT
argcomplete==2.0.*
argcomplete==3.7.*
contextlib2==0.6.*
future==0.18.*
netaddr==1.3.*
+25
View File
@@ -36,6 +36,31 @@ class TestEventsPerSecond(unittest.TestCase):
clock[0] += 100.0
self.assertEqual(eps.eps(), 0.0)
def test_burst_after_start_is_not_divided_by_a_tiny_window(self) -> None:
eps = EventsPerSecond(last_n_seconds=10)
clock = [1000.0]
with patch("frigate.util.builtin.time.monotonic", side_effect=lambda: clock[0]):
eps.start()
# eleven buffered frames arrive within 100 ms of starting
for _ in range(11):
clock[0] += 0.01
eps.update()
# 11 events over less than a second is at most 11 per second
self.assertLessEqual(eps.eps(), 11.0)
def test_subsecond_window_keeps_its_rate(self) -> None:
eps = EventsPerSecond(last_n_seconds=0.5)
clock = [1000.0]
with patch("frigate.util.builtin.time.monotonic", side_effect=lambda: clock[0]):
eps.start()
# twenty events per second for two seconds
for _ in range(40):
clock[0] += 0.05
eps.update()
# read between events, so none sits exactly on the window edge
clock[0] += 0.01
self.assertAlmostEqual(eps.eps(), 20.0)
if __name__ == "__main__":
unittest.main()
+7 -4
View File
@@ -56,10 +56,13 @@ class EventsPerSecond:
self._start = now
# compute the (approximate) events in the last n seconds
self.expire_timestamps(now)
seconds = min(now - self._start, self._last_n_seconds)
# avoid divide by zero
if seconds == 0:
seconds = 1
# rate over at least one second (or the whole window, if shorter),
# so a burst of events right after start() is not divided by a
# tiny window
seconds = max(
min(now - self._start, self._last_n_seconds),
min(1.0, self._last_n_seconds),
)
return len(self._timestamps) / seconds
# remove aged out timestamps
+2 -2
View File
@@ -1,6 +1,6 @@
import { useCallback, useMemo, useRef, useState } from "react";
import { LuFolderX } from "react-icons/lu";
import { isMobileOnly, isSafari } from "react-device-detect";
import { isMobileOnly } from "react-device-detect";
import { LuPause, LuPlay } from "react-icons/lu";
import {
DropdownMenu,
@@ -54,7 +54,7 @@ const CONTROLS_DEFAULT: VideoControls = {
snapshot: false,
fullscreen: false,
};
const PLAYBACK_RATE_DEFAULT = isSafari ? [0.5, 1, 2] : [0.5, 1, 2, 4, 8, 16];
const PLAYBACK_RATE_DEFAULT = [0.5, 1, 2, 4, 8, 16];
const MIN_ITEMS_WRAP = 6;
type VideoControlsProps = {
+1 -2
View File
@@ -17,7 +17,6 @@ import {
useUserPersistence,
deleteUserNamespacedKey,
} from "@/hooks/use-user-persistence";
import { isSafari } from "react-device-detect";
import {
Select,
SelectContent,
@@ -132,7 +131,7 @@ export default function UiSettingsView() {
const { auth } = useContext(AuthContext);
const username = auth?.user?.username;
const PLAYBACK_RATE_DEFAULT = isSafari ? [0.5, 1, 2] : [0.5, 1, 2, 4, 8, 16];
const PLAYBACK_RATE_DEFAULT = [0.5, 1, 2, 4, 8, 16];
const clearStoredLayouts = useCallback(() => {
if (!config) {