mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-03-10 02:29:19 +03:00
docs: add shm calulator
This commit is contained in:
parent
352d271fe4
commit
73fe8f97d4
@ -3,6 +3,8 @@ id: installation
|
|||||||
title: Installation
|
title: Installation
|
||||||
---
|
---
|
||||||
|
|
||||||
|
import ShmCalculator from '@site/src/components/ShmCalculator'
|
||||||
|
|
||||||
Frigate is a Docker container that can be run on any Docker host including as a [Home Assistant Add-on](https://www.home-assistant.io/addons/). Note that the Home Assistant Add-on is **not** the same thing as the integration. The [integration](/integrations/home-assistant) is required to integrate Frigate into Home Assistant, whether you are running Frigate as a standalone Docker container or as a Home Assistant Add-on.
|
Frigate is a Docker container that can be run on any Docker host including as a [Home Assistant Add-on](https://www.home-assistant.io/addons/). Note that the Home Assistant Add-on is **not** the same thing as the integration. The [integration](/integrations/home-assistant) is required to integrate Frigate into Home Assistant, whether you are running Frigate as a standalone Docker container or as a Home Assistant Add-on.
|
||||||
|
|
||||||
:::tip
|
:::tip
|
||||||
@ -77,20 +79,7 @@ The default shm size of **128MB** is fine for setups with **2 cameras** detectin
|
|||||||
|
|
||||||
The Frigate container also stores logs in shm, which can take up to **40MB**, so make sure to take this into account in your math as well.
|
The Frigate container also stores logs in shm, which can take up to **40MB**, so make sure to take this into account in your math as well.
|
||||||
|
|
||||||
You can calculate the **minimum** shm size for each camera with the following formula using the resolution specified for detect:
|
<ShmCalculator/>
|
||||||
|
|
||||||
```console
|
|
||||||
# Template for one camera without logs, replace <width> and <height>
|
|
||||||
$ python -c 'print("{:.2f}MB".format((<width> * <height> * 1.5 * 20 + 270480) / 1048576))'
|
|
||||||
|
|
||||||
# Example for 1280x720, including logs
|
|
||||||
$ python -c 'print("{:.2f}MB".format((1280 * 720 * 1.5 * 20 + 270480) / 1048576 + 40))'
|
|
||||||
66.63MB
|
|
||||||
|
|
||||||
# Example for eight cameras detecting at 1280x720, including logs
|
|
||||||
$ python -c 'print("{:.2f}MB".format(((1280 * 720 * 1.5 * 20 + 270480) / 1048576) * 8 + 40))'
|
|
||||||
253MB
|
|
||||||
```
|
|
||||||
|
|
||||||
The shm size cannot be set per container for Home Assistant add-ons. However, this is probably not required since by default Home Assistant Supervisor allocates `/dev/shm` with half the size of your total memory. If your machine has 8GB of memory, chances are that Frigate will have access to up to 4GB without any additional configuration.
|
The shm size cannot be set per container for Home Assistant add-ons. However, this is probably not required since by default Home Assistant Supervisor allocates `/dev/shm` with half the size of your total memory. If your machine has 8GB of memory, chances are that Frigate will have access to up to 4GB without any additional configuration.
|
||||||
|
|
||||||
|
|||||||
191
docs/src/components/ShmCalculator/index.jsx
Normal file
191
docs/src/components/ShmCalculator/index.jsx
Normal file
@ -0,0 +1,191 @@
|
|||||||
|
import React, { useState, useEffect } from "react";
|
||||||
|
import styles from "./styles.module.css";
|
||||||
|
|
||||||
|
const ShmCalculator = () => {
|
||||||
|
const [width, setWidth] = useState(1280);
|
||||||
|
const [height, setHeight] = useState(720);
|
||||||
|
const [cameraCount, setCameraCount] = useState(1);
|
||||||
|
const [result, setResult] = useState("26.32MB");
|
||||||
|
const [singleCameraShm, setSingleCameraShm] = useState("26.32MB");
|
||||||
|
const [totalShm, setTotalShm] = useState("26.32MB");
|
||||||
|
|
||||||
|
const calculate = () => {
|
||||||
|
if (!width || !height || !cameraCount) {
|
||||||
|
setResult("Please enter valid values");
|
||||||
|
setSingleCameraShm("-");
|
||||||
|
setTotalShm("-");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Single camera base SHM calculation (excluding logs)
|
||||||
|
// Formula: (width * height * 1.5 * 20 + 270480) / 1048576
|
||||||
|
const singleCameraBase =
|
||||||
|
(width * height * 1.5 * 20 + 270480) / 1048576;
|
||||||
|
setSingleCameraShm(`${singleCameraBase.toFixed(2)}mb`);
|
||||||
|
|
||||||
|
// Total SHM calculation (multiple cameras, including logs)
|
||||||
|
const totalBase = singleCameraBase * cameraCount;
|
||||||
|
const finalResult = totalBase + 40; // Default includes logs +40mb
|
||||||
|
|
||||||
|
setTotalShm(`${(totalBase + 40).toFixed(2)}mb`);
|
||||||
|
|
||||||
|
// Format result
|
||||||
|
if (finalResult < 1) {
|
||||||
|
setResult(`${(finalResult * 1024).toFixed(2)}kb`);
|
||||||
|
} else if (finalResult >= 1024) {
|
||||||
|
setResult(`${(finalResult / 1024).toFixed(2)}gb`);
|
||||||
|
} else {
|
||||||
|
setResult(`${finalResult.toFixed(2)}mb`);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const formatWithUnit = (value) => {
|
||||||
|
const match = value.match(/^([\d.]+)(mb|kb|gb)$/i);
|
||||||
|
if (match) {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{match[1]}<span className={styles.unit}>{match[2]}</span>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
};
|
||||||
|
|
||||||
|
const applyPreset = (w, h, count) => {
|
||||||
|
setWidth(w);
|
||||||
|
setHeight(h);
|
||||||
|
setCameraCount(count);
|
||||||
|
calculate();
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
calculate();
|
||||||
|
}, [width, height, cameraCount]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={styles.shmCalculator}>
|
||||||
|
<div className={styles.card}>
|
||||||
|
<h3 className={styles.title}>SHM Calculator</h3>
|
||||||
|
<p className={styles.description}>
|
||||||
|
Calculate required shared memory (SHM) based on camera resolution and
|
||||||
|
count
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div className={styles.row}>
|
||||||
|
<div className={styles.formGroup}>
|
||||||
|
<label htmlFor="width" className={styles.label}>
|
||||||
|
Width:
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
id="width"
|
||||||
|
type="number"
|
||||||
|
min="1"
|
||||||
|
placeholder="e.g.: 1280"
|
||||||
|
className={styles.input}
|
||||||
|
value={width}
|
||||||
|
onChange={(e) => setWidth(Number(e.target.value))}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={styles.formGroup}>
|
||||||
|
<label htmlFor="height" className={styles.label}>
|
||||||
|
Height:
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
id="height"
|
||||||
|
type="number"
|
||||||
|
min="1"
|
||||||
|
placeholder="e.g.: 720"
|
||||||
|
className={styles.input}
|
||||||
|
value={height}
|
||||||
|
onChange={(e) => setHeight(Number(e.target.value))}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={styles.formGroup}>
|
||||||
|
<label htmlFor="cameraCount" className={styles.label}>
|
||||||
|
Camera Count:
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
id="cameraCount"
|
||||||
|
type="number"
|
||||||
|
min="1"
|
||||||
|
placeholder="e.g.: 8"
|
||||||
|
className={styles.input}
|
||||||
|
value={cameraCount}
|
||||||
|
onChange={(e) => setCameraCount(Number(e.target.value))}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={styles.resultSection}>
|
||||||
|
<h4>Calculation Result</h4>
|
||||||
|
<div className={styles.resultValue}>
|
||||||
|
<span className={styles.resultNumber}>{formatWithUnit(result)}</span>
|
||||||
|
</div>
|
||||||
|
<div className={styles.formulaDisplay}>
|
||||||
|
<p>
|
||||||
|
<strong>Single Camera:</strong> {formatWithUnit(singleCameraShm)}
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<strong>Formula:</strong> (width × height × 1.5 × 20 + 270480) ÷
|
||||||
|
1048576
|
||||||
|
</p>
|
||||||
|
{cameraCount > 1 && (
|
||||||
|
<p>
|
||||||
|
<strong>Total ({cameraCount} cameras):</strong> {formatWithUnit(totalShm)}
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
<p>
|
||||||
|
<strong>With Logs:</strong> + 40<span className={styles.unit}>mb</span>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={styles.presets}>
|
||||||
|
<h4>Common Presets</h4>
|
||||||
|
<div className={styles.presetButtons}>
|
||||||
|
<button
|
||||||
|
className={styles.presetButton}
|
||||||
|
onClick={() => applyPreset(1280, 720, 1)}
|
||||||
|
>
|
||||||
|
1280x720 × 1
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
className={styles.presetButton}
|
||||||
|
onClick={() => applyPreset(1280, 720, 4)}
|
||||||
|
>
|
||||||
|
1280x720 × 4
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
className={styles.presetButton}
|
||||||
|
onClick={() => applyPreset(1280, 720, 8)}
|
||||||
|
>
|
||||||
|
1280x720 × 8
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
className={styles.presetButton}
|
||||||
|
onClick={() => applyPreset(1920, 1080, 1)}
|
||||||
|
>
|
||||||
|
1920x1080 × 1
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
className={styles.presetButton}
|
||||||
|
onClick={() => applyPreset(1920, 1080, 4)}
|
||||||
|
>
|
||||||
|
1920x1080 × 4
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
className={styles.presetButton}
|
||||||
|
onClick={() => applyPreset(3840, 2160, 1)}
|
||||||
|
>
|
||||||
|
4K × 1
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ShmCalculator;
|
||||||
173
docs/src/components/ShmCalculator/styles.module.css
Normal file
173
docs/src/components/ShmCalculator/styles.module.css
Normal file
@ -0,0 +1,173 @@
|
|||||||
|
.shmCalculator {
|
||||||
|
margin: 2rem 0;
|
||||||
|
max-width: 600px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card {
|
||||||
|
background: var(--ifm-background-surface-color);
|
||||||
|
border: 1px solid var(--ifm-border-color);
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 2rem;
|
||||||
|
box-shadow: var(--ifm-global-shadow-lw);
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme='light'] .card {
|
||||||
|
background: var(--ifm-color-emphasis-100);
|
||||||
|
border: 1px solid var(--ifm-color-emphasis-300);
|
||||||
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
margin: 0 0 0.5rem 0;
|
||||||
|
font-size: 1.5rem;
|
||||||
|
color: var(--ifm-font-color-base);
|
||||||
|
font-weight: var(--ifm-font-weight-semibold);
|
||||||
|
}
|
||||||
|
|
||||||
|
.description {
|
||||||
|
margin: 0 0 1.5rem 0;
|
||||||
|
color: var(--ifm-font-color-secondary);
|
||||||
|
font-size: 0.9rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.formGroup {
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.row {
|
||||||
|
display: flex;
|
||||||
|
gap: 1rem;
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.row .formGroup {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.label {
|
||||||
|
display: block;
|
||||||
|
margin-bottom: 0.25rem;
|
||||||
|
color: var(--ifm-font-color-base);
|
||||||
|
font-weight: var(--ifm-font-weight-semibold);
|
||||||
|
font-size: 0.9rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input {
|
||||||
|
width: 100%;
|
||||||
|
padding: 0.5rem 0.75rem;
|
||||||
|
border: 1px solid var(--ifm-border-color);
|
||||||
|
border-radius: 6px;
|
||||||
|
background: var(--ifm-background-color);
|
||||||
|
color: var(--ifm-font-color-base);
|
||||||
|
font-size: 0.95rem;
|
||||||
|
transition: border-color 0.2s, box-shadow 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme='light'] .input {
|
||||||
|
background: #fff;
|
||||||
|
border: 1px solid #d0d7de;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input:focus {
|
||||||
|
outline: none;
|
||||||
|
border-color: var(--ifm-color-primary);
|
||||||
|
box-shadow: 0 0 0 3px var(--ifm-color-primary-lightest);
|
||||||
|
}
|
||||||
|
|
||||||
|
.resultSection {
|
||||||
|
margin-top: 1rem;
|
||||||
|
padding: 1.5rem;
|
||||||
|
background: var(--ifm-background-color);
|
||||||
|
border-radius: 8px;
|
||||||
|
border: 1px solid var(--ifm-border-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme='light'] .resultSection {
|
||||||
|
background: #f6f8fa;
|
||||||
|
border: 1px solid #d0d7de;
|
||||||
|
}
|
||||||
|
|
||||||
|
.resultSection h4 {
|
||||||
|
margin: 0 0 1rem 0;
|
||||||
|
color: var(--ifm-font-color-base);
|
||||||
|
font-weight: var(--ifm-font-weight-semibold);
|
||||||
|
}
|
||||||
|
|
||||||
|
.resultValue {
|
||||||
|
text-align: center;
|
||||||
|
padding: 1rem;
|
||||||
|
background: var(--ifm-color-primary);
|
||||||
|
border-radius: 6px;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.resultNumber {
|
||||||
|
font-size: 2rem;
|
||||||
|
font-weight: var(--ifm-font-weight-bold);
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.formulaDisplay {
|
||||||
|
font-size: 0.85rem;
|
||||||
|
color: var(--ifm-font-color-secondary);
|
||||||
|
line-height: 1.6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.formulaDisplay p {
|
||||||
|
margin: 0.25rem 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.formulaDisplay strong {
|
||||||
|
color: var(--ifm-font-color-base);
|
||||||
|
}
|
||||||
|
|
||||||
|
.unit {
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
|
||||||
|
.presets {
|
||||||
|
margin-top: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.presets h4 {
|
||||||
|
margin: 0 0 0.75rem 0;
|
||||||
|
color: var(--ifm-font-color-base);
|
||||||
|
font-weight: var(--ifm-font-weight-semibold);
|
||||||
|
}
|
||||||
|
|
||||||
|
.presetButtons {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.presetButton {
|
||||||
|
padding: 0.5rem 1rem;
|
||||||
|
background: var(--ifm-background-surface-color);
|
||||||
|
border: 1px solid var(--ifm-border-color);
|
||||||
|
border-radius: 6px;
|
||||||
|
color: var(--ifm-font-color-base);
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 0.85rem;
|
||||||
|
font-weight: var(--ifm-font-weight-normal);
|
||||||
|
transition: all 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme='light'] .presetButton {
|
||||||
|
background: #fff;
|
||||||
|
border: 1px solid #d0d7de;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme='dark'] .presetButton {
|
||||||
|
background: #24292f;
|
||||||
|
border: 1px solid #3b434b;
|
||||||
|
}
|
||||||
|
|
||||||
|
.presetButton:hover {
|
||||||
|
background: var(--ifm-color-primary);
|
||||||
|
color: #fff;
|
||||||
|
border-color: var(--ifm-color-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.presetButton:active {
|
||||||
|
transform: translateY(1px);
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user