mirror of
https://github.com/blakeblackshear/frigate.git
synced 2025-12-12 16:16:42 +03:00
add go2rtc stream add and ffprobe snapshot endpoints
This commit is contained in:
parent
c96ee0c968
commit
617d2a239e
@ -43,6 +43,7 @@ from frigate.util.builtin import (
|
|||||||
update_yaml_file_bulk,
|
update_yaml_file_bulk,
|
||||||
)
|
)
|
||||||
from frigate.util.config import find_config_file
|
from frigate.util.config import find_config_file
|
||||||
|
from frigate.util.image import run_ffmpeg_snapshot
|
||||||
from frigate.util.services import (
|
from frigate.util.services import (
|
||||||
ffprobe_stream,
|
ffprobe_stream,
|
||||||
get_nvidia_driver_info,
|
get_nvidia_driver_info,
|
||||||
@ -107,6 +108,45 @@ def go2rtc_camera_stream(request: Request, camera_name: str):
|
|||||||
return JSONResponse(content=stream_data)
|
return JSONResponse(content=stream_data)
|
||||||
|
|
||||||
|
|
||||||
|
@router.put(
|
||||||
|
"/go2rtc/streams/{stream_name}", dependencies=[Depends(require_role(["admin"]))]
|
||||||
|
)
|
||||||
|
def go2rtc_add_stream(request: Request, stream_name: str, src: str = ""):
|
||||||
|
"""Add or update a go2rtc stream configuration."""
|
||||||
|
try:
|
||||||
|
params = {"name": stream_name}
|
||||||
|
if src:
|
||||||
|
params["src"] = src
|
||||||
|
|
||||||
|
r = requests.put(
|
||||||
|
"http://127.0.0.1:1984/api/streams",
|
||||||
|
params=params,
|
||||||
|
timeout=10,
|
||||||
|
)
|
||||||
|
if not r.ok:
|
||||||
|
logger.error(f"Failed to add go2rtc stream {stream_name}: {r.text}")
|
||||||
|
return JSONResponse(
|
||||||
|
content=(
|
||||||
|
{"success": False, "message": f"Failed to add stream: {r.text}"}
|
||||||
|
),
|
||||||
|
status_code=r.status_code,
|
||||||
|
)
|
||||||
|
return JSONResponse(
|
||||||
|
content={"success": True, "message": "Stream added successfully"}
|
||||||
|
)
|
||||||
|
except requests.RequestException as e:
|
||||||
|
logger.error(f"Error communicating with go2rtc: {e}")
|
||||||
|
return JSONResponse(
|
||||||
|
content=(
|
||||||
|
{
|
||||||
|
"success": False,
|
||||||
|
"message": f"Error communicating with go2rtc: {str(e)}",
|
||||||
|
}
|
||||||
|
),
|
||||||
|
status_code=500,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@router.get("/version", response_class=PlainTextResponse)
|
@router.get("/version", response_class=PlainTextResponse)
|
||||||
def version():
|
def version():
|
||||||
return VERSION
|
return VERSION
|
||||||
@ -533,7 +573,6 @@ def ffprobe(request: Request, paths: str = "", detailed: bool = False):
|
|||||||
"width": video_stream.get("width"),
|
"width": video_stream.get("width"),
|
||||||
"height": video_stream.get("height"),
|
"height": video_stream.get("height"),
|
||||||
"fps": _extract_fps(video_stream.get("r_frame_rate")),
|
"fps": _extract_fps(video_stream.get("r_frame_rate")),
|
||||||
"bitrate": _extract_bitrate(video_stream.get("bit_rate")),
|
|
||||||
"pixel_format": video_stream.get("pix_fmt"),
|
"pixel_format": video_stream.get("pix_fmt"),
|
||||||
"profile": video_stream.get("profile"),
|
"profile": video_stream.get("profile"),
|
||||||
"level": video_stream.get("level"),
|
"level": video_stream.get("level"),
|
||||||
@ -551,7 +590,6 @@ def ffprobe(request: Request, paths: str = "", detailed: bool = False):
|
|||||||
"codec": audio_stream.get("codec_name"),
|
"codec": audio_stream.get("codec_name"),
|
||||||
"channels": audio_stream.get("channels"),
|
"channels": audio_stream.get("channels"),
|
||||||
"sample_rate": audio_stream.get("sample_rate"),
|
"sample_rate": audio_stream.get("sample_rate"),
|
||||||
"bitrate": _extract_bitrate(audio_stream.get("bit_rate")),
|
|
||||||
"channel_layout": audio_stream.get("channel_layout"),
|
"channel_layout": audio_stream.get("channel_layout"),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -562,7 +600,6 @@ def ffprobe(request: Request, paths: str = "", detailed: bool = False):
|
|||||||
"format": format_info.get("format_name"),
|
"format": format_info.get("format_name"),
|
||||||
"duration": format_info.get("duration"),
|
"duration": format_info.get("duration"),
|
||||||
"size": format_info.get("size"),
|
"size": format_info.get("size"),
|
||||||
"bitrate": _extract_bitrate(format_info.get("bit_rate")),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
result["metadata"] = metadata
|
result["metadata"] = metadata
|
||||||
@ -576,6 +613,40 @@ def ffprobe(request: Request, paths: str = "", detailed: bool = False):
|
|||||||
return JSONResponse(content=output)
|
return JSONResponse(content=output)
|
||||||
|
|
||||||
|
|
||||||
|
@router.get("/ffprobe/snapshot", dependencies=[Depends(require_role(["admin"]))])
|
||||||
|
def ffprobe_snapshot(request: Request, url: str = "", timeout: int = 10):
|
||||||
|
"""Get a snapshot from a stream URL using ffmpeg."""
|
||||||
|
if not url:
|
||||||
|
return JSONResponse(
|
||||||
|
content={"success": False, "message": "URL parameter is required"},
|
||||||
|
status_code=400,
|
||||||
|
)
|
||||||
|
|
||||||
|
config: FrigateConfig = request.app.frigate_config
|
||||||
|
|
||||||
|
image_data, error = run_ffmpeg_snapshot(
|
||||||
|
config.ffmpeg, url, "mjpeg", timeout=timeout
|
||||||
|
)
|
||||||
|
|
||||||
|
if image_data:
|
||||||
|
return Response(
|
||||||
|
image_data,
|
||||||
|
media_type="image/jpeg",
|
||||||
|
headers={"Cache-Control": "no-store"},
|
||||||
|
)
|
||||||
|
elif error == "timeout":
|
||||||
|
return JSONResponse(
|
||||||
|
content={"success": False, "message": "Timeout capturing snapshot"},
|
||||||
|
status_code=408,
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
logger.error(f"ffmpeg failed: {error}")
|
||||||
|
return JSONResponse(
|
||||||
|
content={"success": False, "message": "Failed to capture snapshot"},
|
||||||
|
status_code=500,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def _extract_fps(r_frame_rate: str) -> float | None:
|
def _extract_fps(r_frame_rate: str) -> float | None:
|
||||||
"""Extract FPS from ffprobe r_frame_rate string (e.g., '30/1' -> 30.0)"""
|
"""Extract FPS from ffprobe r_frame_rate string (e.g., '30/1' -> 30.0)"""
|
||||||
if not r_frame_rate:
|
if not r_frame_rate:
|
||||||
@ -587,16 +658,6 @@ def _extract_fps(r_frame_rate: str) -> float | None:
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def _extract_bitrate(bit_rate: str) -> int | None:
|
|
||||||
"""Extract bitrate in kbps from ffprobe bit_rate string"""
|
|
||||||
if not bit_rate:
|
|
||||||
return None
|
|
||||||
try:
|
|
||||||
return round(int(bit_rate) / 1000) # Convert to kbps
|
|
||||||
except ValueError:
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
@router.get("/vainfo")
|
@router.get("/vainfo")
|
||||||
def vainfo():
|
def vainfo():
|
||||||
vainfo = vainfo_hwaccel()
|
vainfo = vainfo_hwaccel()
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user