forked from Github/frigate
Ability to set different codec for restream and use go2rtc hardware (#4876)
* Add video codec to restream config * Add handling of encode engine and video codec * Add test for video encoding * Set in main configuration docs as well * Add example to restream docs * Put back patch
This commit is contained in:
@@ -514,8 +514,17 @@ class JsmpegStreamConfig(FrigateBaseModel):
|
||||
quality: int = Field(default=8, ge=1, le=31, title="Live camera view quality.")
|
||||
|
||||
|
||||
class RestreamCodecEnum(str, Enum):
|
||||
copy = "copy"
|
||||
h264 = "h264"
|
||||
h265 = "h265"
|
||||
|
||||
|
||||
class RestreamConfig(FrigateBaseModel):
|
||||
enabled: bool = Field(default=True, title="Restreaming enabled.")
|
||||
video_encoding: RestreamCodecEnum = Field(
|
||||
default=RestreamCodecEnum.copy, title="Method for encoding the restream."
|
||||
)
|
||||
force_audio: bool = Field(
|
||||
default=True, title="Force audio compatibility with the browser."
|
||||
)
|
||||
|
||||
@@ -230,6 +230,15 @@ PRESETS_HW_ACCEL_ENCODE = {
|
||||
],
|
||||
}
|
||||
|
||||
PRESETS_HW_ACCEL_GO2RTC_ENGINE = {
|
||||
"preset-intel-vaapi": "vaapi",
|
||||
"preset-intel-qsv-h264": "vaapi", # go2rtc doesn't support qsv
|
||||
"preset-intel-qsv-h265": "vaapi",
|
||||
"preset-amd-vaapi": "vaapi",
|
||||
"preset-nvidia-h264": "cuda",
|
||||
"preset-nvidia-h265": "cuda",
|
||||
}
|
||||
|
||||
|
||||
def parse_preset_hardware_acceleration_decode(arg: Any) -> list[str]:
|
||||
"""Return the correct preset if in preset format otherwise return None."""
|
||||
@@ -267,6 +276,14 @@ def parse_preset_hardware_acceleration_encode(arg: Any) -> list[str]:
|
||||
return PRESETS_HW_ACCEL_ENCODE.get(arg, PRESETS_HW_ACCEL_ENCODE["default"])
|
||||
|
||||
|
||||
def parse_preset_hardware_acceleration_go2rtc_engine(arg: Any) -> list[str]:
|
||||
"""Return the correct engine for the preset otherwise returns None."""
|
||||
if not isinstance(arg, str):
|
||||
return None
|
||||
|
||||
return PRESETS_HW_ACCEL_GO2RTC_ENGINE.get(arg)
|
||||
|
||||
|
||||
PRESETS_INPUT = {
|
||||
"preset-http-jpeg-generic": _user_agent_args
|
||||
+ [
|
||||
|
||||
@@ -3,18 +3,33 @@
|
||||
|
||||
import logging
|
||||
import requests
|
||||
from frigate.util import escape_special_characters
|
||||
|
||||
from frigate.config import FrigateConfig
|
||||
from typing import Optional
|
||||
|
||||
from frigate.config import FrigateConfig, RestreamCodecEnum
|
||||
from frigate.const import BIRDSEYE_PIPE
|
||||
from frigate.ffmpeg_presets import parse_preset_hardware_acceleration_encode
|
||||
from frigate.ffmpeg_presets import (
|
||||
parse_preset_hardware_acceleration_encode,
|
||||
parse_preset_hardware_acceleration_go2rtc_engine,
|
||||
)
|
||||
from frigate.util import escape_special_characters
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def get_manual_go2rtc_stream(camera_url: str) -> str:
|
||||
def get_manual_go2rtc_stream(
|
||||
camera_url: str, codec: RestreamCodecEnum, engine: Optional[str]
|
||||
) -> str:
|
||||
"""Get a manual stream for go2rtc."""
|
||||
return f"ffmpeg:{camera_url}#video=copy#audio=aac#audio=opus"
|
||||
if codec == RestreamCodecEnum.copy:
|
||||
return f"ffmpeg:{camera_url}#video=copy#audio=aac#audio=opus"
|
||||
|
||||
if engine:
|
||||
return (
|
||||
f"ffmpeg:{camera_url}#video={codec}#hardware={engine}#audio=aac#audio=opus"
|
||||
)
|
||||
|
||||
return f"ffmpeg:{camera_url}#video={codec}#audio=aac#audio=opus"
|
||||
|
||||
|
||||
class RestreamApi:
|
||||
@@ -41,7 +56,11 @@ class RestreamApi:
|
||||
else:
|
||||
# go2rtc only supports rtsp for direct relay, otherwise ffmpeg is used
|
||||
self.relays[cam_name] = get_manual_go2rtc_stream(
|
||||
escape_special_characters(input.path)
|
||||
escape_special_characters(input.path),
|
||||
camera.restream.video_encoding,
|
||||
parse_preset_hardware_acceleration_go2rtc_engine(
|
||||
self.config.ffmpeg.hwaccel_args
|
||||
),
|
||||
)
|
||||
|
||||
if self.config.restream.birdseye:
|
||||
|
||||
@@ -45,7 +45,9 @@ class TestRestream(TestCase):
|
||||
}
|
||||
|
||||
@patch("frigate.restream.requests")
|
||||
def test_rtsp_stream(self, mock_requests) -> None:
|
||||
def test_rtsp_stream(
|
||||
self, mock_request
|
||||
) -> None: # need to ensure restream doesn't try to call API
|
||||
"""Test that the normal rtsp stream is sent plainly."""
|
||||
frigate_config = FrigateConfig(**self.config)
|
||||
restream = RestreamApi(frigate_config)
|
||||
@@ -53,13 +55,28 @@ class TestRestream(TestCase):
|
||||
assert restream.relays["back"].startswith("rtsp")
|
||||
|
||||
@patch("frigate.restream.requests")
|
||||
def test_http_stream(self, mock_requests) -> None:
|
||||
def test_http_stream(
|
||||
self, mock_request
|
||||
) -> None: # need to ensure restream doesn't try to call API
|
||||
"""Test that the http stream is sent via ffmpeg."""
|
||||
frigate_config = FrigateConfig(**self.config)
|
||||
restream = RestreamApi(frigate_config)
|
||||
restream.add_cameras()
|
||||
assert not restream.relays["front"].startswith("rtsp")
|
||||
|
||||
@patch("frigate.restream.requests")
|
||||
def test_restream_codec_change(
|
||||
self, mock_request
|
||||
) -> None: # need to ensure restream doesn't try to call API
|
||||
"""Test that the http stream is sent via ffmpeg."""
|
||||
self.config["cameras"]["front"]["restream"]["video_encoding"] = "h265"
|
||||
self.config["ffmpeg"] = {"hwaccel_args": "preset-nvidia-h264"}
|
||||
frigate_config = FrigateConfig(**self.config)
|
||||
restream = RestreamApi(frigate_config)
|
||||
restream.add_cameras()
|
||||
assert "#hardware=cuda" in restream.relays["front"]
|
||||
assert "#video=h265" in restream.relays["front"]
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main(verbosity=2)
|
||||
|
||||
Reference in New Issue
Block a user