Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Revamped debug UI and add camera / process info, ffprobe copying #4349

Merged
merged 22 commits into from
Nov 13, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docker/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ RUN apt-get -qq update \
apt-transport-https \
gnupg \
wget \
procps \
unzip tzdata libxml2 xz-utils \
python3-pip \
# add raspberry pi repo
Expand Down
8 changes: 8 additions & 0 deletions docs/docs/integrations/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -264,3 +264,11 @@ Get recording segment details for the given timestamp range.
| -------- | ---- | ------------------------------------- |
| `after` | int | Unix timestamp for beginning of range |
| `before` | int | Unix timestamp for end of range |

### `GET /api/ffprobe`

Get ffprobe output for camera feed paths.

| param | Type | Description |
| ------- | ------ | ---------------------------------- |
| `paths` | string | `,` separated list of camera paths |
40 changes: 37 additions & 3 deletions frigate/http.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import base64
from collections import OrderedDict
from datetime import datetime, timedelta
import copy
import logging
import json
import os
import subprocess as sp
import time
Expand All @@ -28,9 +28,9 @@

from frigate.const import CLIPS_DIR
from frigate.models import Event, Recordings
from frigate.object_processing import TrackedObject, TrackedObjectProcessor
from frigate.object_processing import TrackedObject
from frigate.stats import stats_snapshot
from frigate.util import clean_camera_user_pass
from frigate.util import clean_camera_user_pass, ffprobe_stream
from frigate.version import VERSION

logger = logging.getLogger(__name__)
Expand Down Expand Up @@ -957,3 +957,37 @@ def imagestream(detected_frames_processor, camera_name, fps, height, draw_option
b"--frame\r\n"
b"Content-Type: image/jpeg\r\n\r\n" + jpg.tobytes() + b"\r\n\r\n"
)


@bp.route("/ffprobe", methods=["GET"])
def ffprobe():
path_param = request.args.get("paths", "")

if not path_param:
return jsonify(
{"success": False, "message": f"Path needs to be provided."}, "404"
)

if "," in clean_camera_user_pass(path_param):
paths = path_param.split(",")
else:
paths = [path_param]

# user has multiple streams
output = []

for path in paths:
ffprobe = ffprobe_stream(path)
output.append(
{
"return_code": ffprobe.returncode,
"stderr": json.loads(ffprobe.stderr.decode("unicode_escape").strip())
if ffprobe.stderr.decode()
else {},
"stdout": json.loads(ffprobe.stdout.decode("unicode_escape").strip())
if ffprobe.stdout.decode()
else {},
}
)

return jsonify(output)
7 changes: 7 additions & 0 deletions frigate/stats.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
from frigate.const import RECORD_DIR, CLIPS_DIR, CACHE_DIR
from frigate.types import StatsTrackingTypes, CameraMetricsTypes
from frigate.version import VERSION
from frigate.util import get_cpu_stats
from frigate.object_detection import ObjectDetectProcess

logger = logging.getLogger(__name__)
Expand Down Expand Up @@ -90,6 +91,9 @@ def stats_snapshot(stats_tracking: StatsTrackingTypes) -> dict[str, Any]:
for name, camera_stats in camera_metrics.items():
total_detection_fps += camera_stats["detection_fps"].value
pid = camera_stats["process"].pid if camera_stats["process"] else None
ffmpeg_pid = (
camera_stats["ffmpeg_pid"].value if camera_stats["ffmpeg_pid"] else None
)
cpid = (
camera_stats["capture_process"].pid
if camera_stats["capture_process"]
Expand All @@ -102,6 +106,7 @@ def stats_snapshot(stats_tracking: StatsTrackingTypes) -> dict[str, Any]:
"detection_fps": round(camera_stats["detection_fps"].value, 2),
"pid": pid,
"capture_pid": cpid,
"ffmpeg_pid": ffmpeg_pid,
}

stats["detectors"] = {}
Expand All @@ -114,6 +119,8 @@ def stats_snapshot(stats_tracking: StatsTrackingTypes) -> dict[str, Any]:
}
stats["detection_fps"] = round(total_detection_fps, 2)

stats["cpu_usages"] = get_cpu_stats()

stats["service"] = {
"uptime": (int(time.time()) - stats_tracking["started"]),
"version": VERSION,
Expand Down
48 changes: 48 additions & 0 deletions frigate/util.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import copy
import datetime
import logging
import subprocess as sp
import json
import re
import signal
import traceback
Expand Down Expand Up @@ -679,6 +681,52 @@ def escape_special_characters(path: str) -> str:
return path


def get_cpu_stats() -> dict[str, dict]:
"""Get cpu usages for each process id"""
usages = {}
# -n=2 runs to ensure extraneous values are not included
top_command = ["top", "-b", "-n", "2"]

p = sp.run(
top_command,
encoding="ascii",
capture_output=True,
)

if p.returncode != 0:
logger.error(p.stderr)
return usages
else:
lines = p.stdout.split("\n")

for line in lines:
stats = list(filter(lambda a: a != "", line.strip().split(" ")))
try:
usages[stats[0]] = {
"cpu": stats[8],
"mem": stats[9],
}
except:
continue

return usages


def ffprobe_stream(path: str) -> sp.CompletedProcess:
"""Run ffprobe on stream."""
ffprobe_cmd = [
"ffprobe",
"-print_format",
"json",
"-show_entries",
"stream=codec_long_name,width,height,bit_rate,duration,display_aspect_ratio,avg_frame_rate",
"-loglevel",
"quiet",
path,
]
return sp.run(ffprobe_cmd, capture_output=True)


class FrameManager(ABC):
@abstractmethod
def create(self, name, size) -> AnyStr:
Expand Down
4 changes: 3 additions & 1 deletion web/__test__/handlers.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,16 +39,18 @@ export const handlers = [
return res(
ctx.status(200),
ctx.json({
cpu_usages: { 74: {cpu: 6, mem: 6}, 64: { cpu: 5, mem: 5 }, 54: { cpu: 4, mem: 4 }, 71: { cpu: 3, mem: 3}, 60: {cpu: 2, mem: 2}, 72: {cpu: 1, mem: 1} },
detection_fps: 0.0,
detectors: { coral: { detection_start: 0.0, inference_speed: 8.94, pid: 52 } },
front: { camera_fps: 5.0, capture_pid: 64, detection_fps: 0.0, pid: 54, process_fps: 0.0, skipped_fps: 0.0 },
front: { camera_fps: 5.0, capture_pid: 64, detection_fps: 0.0, pid: 54, process_fps: 0.0, skipped_fps: 0.0, ffmpeg_pid: 72 },
side: {
camera_fps: 6.9,
capture_pid: 71,
detection_fps: 0.0,
pid: 60,
process_fps: 0.0,
skipped_fps: 0.0,
ffmpeg_pid: 74,
},
service: { uptime: 34812, version: '0.8.1-d376f6b' },
})
Expand Down
Loading