From 01b9d4d848db208e5bc3babe1be3055e2728a942 Mon Sep 17 00:00:00 2001 From: Nicolas Mowen Date: Sun, 15 Jan 2023 08:38:19 -0700 Subject: [PATCH] Rework audio encoding for restream (#5092) * Use memo for recordings timezone * Add audio encoding field and simplify stream creation * Update docs and tests * Fix bad logic --- docs/docs/configuration/index.md | 8 ++++++-- docs/docs/configuration/restream.md | 4 ++-- frigate/config.py | 16 ++++++++++++--- frigate/restream.py | 32 ++++++++++++++++++++--------- frigate/test/test_restream.py | 2 +- 5 files changed, 44 insertions(+), 18 deletions(-) diff --git a/docs/docs/configuration/index.md b/docs/docs/configuration/index.md index 34ee7c4a6..969f693e4 100644 --- a/docs/docs/configuration/index.md +++ b/docs/docs/configuration/index.md @@ -356,8 +356,12 @@ rtmp: restream: # Optional: Enable the restream (default: True) enabled: True - # Optional: Force audio compatibility with browsers (default: shown below) - force_audio: True + # Optional: Set the audio codecs to restream with + # possible values are aac, copy, opus. Set to copy + # only to avoid transcoding (default: shown below) + audio_encoding: + - aac + - opus # 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) diff --git a/docs/docs/configuration/restream.md b/docs/docs/configuration/restream.md index fda1c874a..8cea0e019 100644 --- a/docs/docs/configuration/restream.md +++ b/docs/docs/configuration/restream.md @@ -7,9 +7,9 @@ title: Restream Frigate can restream your video feed as an RTSP feed for other applications such as Home Assistant to utilize it at `rtsp://:8554/`. Port 8554 must be open. [This allows you to use a video feed for detection in Frigate and Home Assistant live view at the same time without having to make two separate connections to the camera](#reduce-connections-to-camera). The video feed is copied from the original video feed directly to avoid re-encoding. This feed does not include any annotation by Frigate. -#### Force Audio +#### Copy Audio -Different live view technologies (ex: MSE, WebRTC) support different audio codecs. The `restream -> force_audio` flag tells the restream to make multiple streams available so that all live view technologies are supported. Some camera streams don't work well with this, in which case `restream -> force_audio` should be disabled. +Different live view technologies (ex: MSE, WebRTC) support different audio codecs. The `restream -> audio_encoding` field tells the restream to make multiple streams available so that all live view technologies are supported. Some camera streams don't work well with this, in which case `restream -> audio_encoding` should be set to `copy` only. #### Birdseye Restream diff --git a/frigate/config.py b/frigate/config.py index 44c1472e1..bcf5e320c 100644 --- a/frigate/config.py +++ b/frigate/config.py @@ -524,16 +524,26 @@ class JsmpegStreamConfig(FrigateBaseModel): quality: int = Field(default=8, ge=1, le=31, title="Live camera view quality.") -class RestreamCodecEnum(str, Enum): +class RestreamVideoCodecEnum(str, Enum): copy = "copy" h264 = "h264" h265 = "h265" +class RestreamAudioCodecEnum(str, Enum): + aac = "aac" + copy = "copy" + opus = "opus" + + class RestreamConfig(FrigateBaseModel): enabled: bool = Field(default=True, title="Restreaming enabled.") - video_encoding: RestreamCodecEnum = Field( - default=RestreamCodecEnum.copy, title="Method for encoding the restream." + audio_encoding: list[RestreamAudioCodecEnum] = Field( + default=[RestreamAudioCodecEnum.aac, RestreamAudioCodecEnum.opus], + title="Codecs to supply for audio.", + ) + video_encoding: RestreamVideoCodecEnum = Field( + default=RestreamVideoCodecEnum.copy, title="Method for encoding the restream." ) force_audio: bool = Field( default=True, title="Force audio compatibility with the browser." diff --git a/frigate/restream.py b/frigate/restream.py index 0f99d4a8a..0fe43fc0e 100644 --- a/frigate/restream.py +++ b/frigate/restream.py @@ -6,7 +6,7 @@ import requests from typing import Optional -from frigate.config import FrigateConfig, RestreamCodecEnum +from frigate.config import FrigateConfig, RestreamAudioCodecEnum, RestreamVideoCodecEnum from frigate.const import BIRDSEYE_PIPE from frigate.ffmpeg_presets import ( parse_preset_hardware_acceleration_encode, @@ -18,18 +18,26 @@ logger = logging.getLogger(__name__) def get_manual_go2rtc_stream( - camera_url: str, codec: RestreamCodecEnum, engine: Optional[str] + camera_url: str, + aCodecs: list[RestreamAudioCodecEnum], + vCodec: RestreamVideoCodecEnum, + 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" + stream = f"ffmpeg:{camera_url}" - if engine: - return ( - f"ffmpeg:{camera_url}#video={codec}#hardware={engine}#audio=aac#audio=opus" - ) + for aCodec in aCodecs: + stream += f"#audio={aCodec}" - return f"ffmpeg:{camera_url}#video={codec}#audio=aac#audio=opus" + if vCodec == RestreamVideoCodecEnum.copy: + stream += "#video=copy" + else: + stream += f"#video={vCodec}" + + if engine: + stream += f"#hardware={engine}" + + return stream class RestreamApi: @@ -50,7 +58,10 @@ class RestreamApi: if "restream" in input.roles: if ( input.path.startswith("rtsp") - and not camera.restream.force_audio + and camera.restream.video_encoding + == RestreamVideoCodecEnum.copy + and camera.restream.audio_encoding + == [RestreamAudioCodecEnum.copy] ): self.relays[ cam_name @@ -59,6 +70,7 @@ class RestreamApi: # go2rtc only supports rtsp for direct relay, otherwise ffmpeg is used self.relays[cam_name] = get_manual_go2rtc_stream( escape_special_characters(input.path), + camera.restream.audio_encoding, camera.restream.video_encoding, parse_preset_hardware_acceleration_go2rtc_engine( self.config.ffmpeg.hwaccel_args diff --git a/frigate/test/test_restream.py b/frigate/test/test_restream.py index 5de8c5cf1..2be781306 100644 --- a/frigate/test/test_restream.py +++ b/frigate/test/test_restream.py @@ -25,7 +25,7 @@ class TestRestream(TestCase): }, "restream": { "enabled": True, - "force_audio": False, + "audio_encoding": ["copy"], }, }, "front": {