add model mamager
This commit is contained in:
Binary file not shown.
@@ -48,6 +48,10 @@ namespace Path {
|
||||
return "/tmp/comma_download_cache" + Path::openpilot_prefix() + "/";
|
||||
}
|
||||
|
||||
inline std::string model_root() {
|
||||
return Hardware::PC() ? Path::comma_home() + "/media/0/models" : "/data/media/0/models";
|
||||
}
|
||||
|
||||
inline std::string shm_path() {
|
||||
#ifdef __APPLE__
|
||||
return"/tmp";
|
||||
|
||||
@@ -63,3 +63,9 @@ class Paths:
|
||||
if PC and platform.system() == "Darwin":
|
||||
return "/tmp" # This is not really shared memory on macOS, but it's the closest we can get
|
||||
return "/dev/shm"
|
||||
|
||||
@staticmethod
|
||||
def model_root() -> str:
|
||||
if PC:
|
||||
return str(Path(Paths.comma_home()) / "media" / "0" / "models")
|
||||
return "/data/media/0/models"
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -143,6 +143,9 @@ procs = [
|
||||
PythonProcess("fleet_manager", "selfdrive.frogpilot.fleetmanager.fleet_manager", check_fleet),
|
||||
PythonProcess("carrot_man", "selfdrive.carrot.carrot_man", always_run),#, enabled=not PC),
|
||||
PythonProcess("carrot_server", "selfdrive.carrot.carrot_server", always_run),
|
||||
|
||||
# Model Manager (always run so process is visible; full download/list when offroad)
|
||||
PythonProcess("models_manager", "selfdrive.models_manager.manager", always_run),
|
||||
#Xiaoge data broadcaster (conditional on ShareData param)
|
||||
PythonProcess("xiaoge_data", "selfdrive.carrot.xiaoge_data", enable_xiaoge_data),
|
||||
# c3x lite
|
||||
|
||||
Binary file not shown.
@@ -1,6 +1,11 @@
|
||||
import asyncio
|
||||
|
||||
import av
|
||||
import subprocess
|
||||
from fractions import Fraction
|
||||
from typing import Optional
|
||||
|
||||
from aiortc.mediastreams import VideoStreamTrack
|
||||
from teleoprtc.tracks import TiciVideoStreamTrack
|
||||
|
||||
from cereal import messaging
|
||||
@@ -41,3 +46,147 @@ class LiveStreamVideoStreamTrack(TiciVideoStreamTrack):
|
||||
|
||||
def codec_preference(self) -> str | None:
|
||||
return "H264"
|
||||
|
||||
|
||||
def _read_fb_virtual_size(path: str = "/sys/class/graphics/fb0/virtual_size") -> Optional[tuple[int, int]]:
|
||||
try:
|
||||
with open(path, "r", encoding="utf-8") as f:
|
||||
s = f.read().strip()
|
||||
w_s, h_s = s.split(",", 1)
|
||||
w, h = int(w_s), int(h_s)
|
||||
if w > 0 and h > 0:
|
||||
return (w, h)
|
||||
except Exception:
|
||||
pass
|
||||
return None
|
||||
|
||||
|
||||
class ScreenCaptureVideoStreamTrack(VideoStreamTrack):
|
||||
"""
|
||||
Best-effort full device screen capture for WebRTC.
|
||||
|
||||
Implementation notes:
|
||||
- Grabs framebuffer via ffmpeg fbdev input (typically /dev/fb0 on openpilot devices).
|
||||
- Outputs raw BGR frames and lets aiortc encode (CPU heavy, keep fps/resolution low).
|
||||
"""
|
||||
|
||||
kind = "video"
|
||||
|
||||
def __init__(self, fb_path: str = "/dev/fb0", fps: int = 10, scale: float = 0.5):
|
||||
super().__init__()
|
||||
self._fb_path = fb_path
|
||||
self._fps = max(1, int(fps))
|
||||
self._scale = float(scale) if scale is not None else 1.0
|
||||
|
||||
src_size = _read_fb_virtual_size() or (1920, 1080)
|
||||
src_w, src_h = src_size
|
||||
out_w = max(16, int((src_w * self._scale) // 2 * 2))
|
||||
out_h = max(16, int((src_h * self._scale) // 2 * 2))
|
||||
self._w, self._h = out_w, out_h
|
||||
self._frame_bytes = self._w * self._h * 3 # bgr24
|
||||
|
||||
self._proc: subprocess.Popen[bytes] | None = None
|
||||
self._use_black_frames = False
|
||||
self._pts = 0
|
||||
self._time_base = Fraction(1, 90000)
|
||||
self._pts_step = int(90000 / self._fps)
|
||||
|
||||
def _ensure_proc(self) -> subprocess.Popen[bytes]:
|
||||
if self._use_black_frames:
|
||||
raise RuntimeError("screen capture disabled; using black frames")
|
||||
|
||||
if self._proc is not None and self._proc.poll() is None:
|
||||
return self._proc
|
||||
|
||||
# Restart process
|
||||
if self._proc is not None:
|
||||
try:
|
||||
self._proc.kill()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
src_size = _read_fb_virtual_size() or (1920, 1080)
|
||||
src_w, src_h = src_size
|
||||
vf = f"scale={self._w}:{self._h},format=bgr24"
|
||||
|
||||
cmd = [
|
||||
"ffmpeg",
|
||||
"-hide_banner",
|
||||
"-loglevel", "error",
|
||||
"-f", "fbdev",
|
||||
"-framerate", str(self._fps),
|
||||
"-video_size", f"{src_w}x{src_h}",
|
||||
"-i", self._fb_path,
|
||||
"-vf", vf,
|
||||
"-f", "rawvideo",
|
||||
"-pix_fmt", "bgr24",
|
||||
"pipe:1",
|
||||
]
|
||||
|
||||
# stdout is raw frames; stderr suppressed by -loglevel error
|
||||
try:
|
||||
self._proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.DEVNULL)
|
||||
except FileNotFoundError:
|
||||
# ffmpeg missing
|
||||
self._use_black_frames = True
|
||||
raise
|
||||
assert self._proc.stdout is not None
|
||||
return self._proc
|
||||
|
||||
async def recv(self) -> av.VideoFrame:
|
||||
# If ffmpeg/fbdev isn't available, still produce frames so the browser gets a track.
|
||||
if self._use_black_frames:
|
||||
await asyncio.sleep(1.0 / self._fps)
|
||||
frame = av.VideoFrame(self._w, self._h, "bgr24")
|
||||
for p in frame.planes:
|
||||
p.update(bytes(p.buffer_size))
|
||||
frame.pts = self._pts
|
||||
frame.time_base = self._time_base
|
||||
self._pts += self._pts_step
|
||||
return frame
|
||||
|
||||
try:
|
||||
proc = self._ensure_proc()
|
||||
assert proc.stdout is not None
|
||||
|
||||
# Read one full frame worth of bytes
|
||||
buf = bytearray()
|
||||
while len(buf) < self._frame_bytes:
|
||||
chunk = await asyncio.to_thread(proc.stdout.read, self._frame_bytes - len(buf))
|
||||
if not chunk:
|
||||
# ffmpeg ended or stalled; restart and retry
|
||||
try:
|
||||
proc.kill()
|
||||
except Exception:
|
||||
pass
|
||||
self._proc = None
|
||||
await asyncio.sleep(0.05)
|
||||
proc = self._ensure_proc()
|
||||
assert proc.stdout is not None
|
||||
buf.clear()
|
||||
continue
|
||||
buf.extend(chunk)
|
||||
|
||||
frame = av.VideoFrame(self._w, self._h, "bgr24")
|
||||
frame.planes[0].update(bytes(buf))
|
||||
except Exception:
|
||||
# Any failure (fb0 missing, bad fbdev support, etc.) falls back to black frames
|
||||
self._use_black_frames = True
|
||||
await asyncio.sleep(1.0 / self._fps)
|
||||
frame = av.VideoFrame(self._w, self._h, "bgr24")
|
||||
for p in frame.planes:
|
||||
p.update(bytes(p.buffer_size))
|
||||
|
||||
frame.pts = self._pts
|
||||
frame.time_base = self._time_base
|
||||
self._pts += self._pts_step
|
||||
return frame
|
||||
|
||||
async def stop(self) -> None:
|
||||
try:
|
||||
if self._proc is not None and self._proc.poll() is None:
|
||||
self._proc.kill()
|
||||
except Exception:
|
||||
pass
|
||||
self._proc = None
|
||||
await super().stop()
|
||||
|
||||
Reference in New Issue
Block a user