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:
Nicolas Mowen
2023-01-03 18:24:34 -07:00
committed by GitHub
parent 760d65b214
commit ea7d1aabba
6 changed files with 90 additions and 8 deletions

View File

@@ -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."
)

View File

@@ -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
+ [

View File

@@ -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:

View File

@@ -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)