mirror of
https://github.com/blakeblackshear/frigate.git
synced 2024-11-21 19:07:46 +01:00
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:
parent
760d65b214
commit
ea7d1aabba
@ -356,6 +356,10 @@ restream:
|
||||
enabled: True
|
||||
# Optional: Force audio compatibility with browsers (default: shown below)
|
||||
force_audio: True
|
||||
# Optional: Video encoding to be used. By default the codec will be copied but
|
||||
# it can be switched to another or an MJPEG stream can be encoded and restreamed
|
||||
# as h264 (default: shown below)
|
||||
video_encoding: "copy"
|
||||
# Optional: Restream birdseye via RTSP (default: shown below)
|
||||
# NOTE: Enabling this will set birdseye to run 24/7 which may increase CPU usage somewhat.
|
||||
birdseye: False
|
||||
|
@ -15,6 +15,22 @@ Different live view technologies (ex: MSE, WebRTC) support different audio codec
|
||||
|
||||
Birdseye RTSP restream can be enabled at `restream -> birdseye` and accessed at `rtsp://<frigate_host>:8554/birdseye`. Enabling the restream will cause birdseye to run 24/7 which may increase CPU usage somewhat.
|
||||
|
||||
#### Changing Restream Codec
|
||||
|
||||
Generally it is recommended to let the codec from the camera be copied. But there may be some cases where h265 needs to be transcoded as h264 or an MJPEG stream can be encoded and restreamed as h264. In this case the encoding will need to be set, if any hardware acceleration presets are set then that will be used to encode the stream.
|
||||
|
||||
```yaml
|
||||
ffmpeg:
|
||||
hwaccel_args: your-hwaccel-preset # <- highly recommended so the GPU is used
|
||||
|
||||
cameras:
|
||||
mjpeg_cam:
|
||||
ffmpeg:
|
||||
...
|
||||
restream:
|
||||
video_encoding: h264
|
||||
```
|
||||
|
||||
### RTMP (Deprecated)
|
||||
|
||||
In previous Frigate versions RTMP was used for re-streaming. RTMP has disadvantages however including being incompatible with H.265, high bitrates, and certain audio codecs. RTMP is deprecated and it is recommended to move to the new restream role.
|
||||
|
@ -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,19 +3,34 @@
|
||||
|
||||
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."""
|
||||
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:
|
||||
"""Control go2rtc relay API."""
|
||||
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user