Add support for stream orientation in go2rtc

This commit is contained in:
Robert Resch 2025-07-15 17:17:24 +02:00
parent 2c2ac4b669
commit a2e177b411
No known key found for this signature in database
GPG Key ID: 9D9D9DCB43120143
3 changed files with 46 additions and 9 deletions

View File

@ -79,7 +79,7 @@ from .const import (
CameraState, CameraState,
StreamType, StreamType,
) )
from .helper import get_camera_from_entity_id from .helper import get_camera_from_entity_id, get_dynamic_camera_stream_settings
from .img_util import scale_jpeg_camera_image from .img_util import scale_jpeg_camera_image
from .prefs import CameraPreferences, DynamicStreamSettings # noqa: F401 from .prefs import CameraPreferences, DynamicStreamSettings # noqa: F401
from .webrtc import ( from .webrtc import (
@ -550,9 +550,9 @@ class Camera(Entity, cached_properties=CACHED_PROPERTIES_WITH_ATTR_):
self.hass, self.hass,
source, source,
options=self.stream_options, options=self.stream_options,
dynamic_stream_settings=await self.hass.data[ dynamic_stream_settings=await get_dynamic_camera_stream_settings(
DATA_CAMERA_PREFS self.hass, self.entity_id
].get_dynamic_stream_settings(self.entity_id), ),
stream_label=self.entity_id, stream_label=self.entity_id,
) )
self.stream.set_update_callback(self.async_write_ha_state) self.stream.set_update_callback(self.async_write_ha_state)
@ -942,9 +942,7 @@ async def websocket_get_prefs(
hass: HomeAssistant, connection: ActiveConnection, msg: dict[str, Any] hass: HomeAssistant, connection: ActiveConnection, msg: dict[str, Any]
) -> None: ) -> None:
"""Handle request for account info.""" """Handle request for account info."""
stream_prefs = await hass.data[DATA_CAMERA_PREFS].get_dynamic_stream_settings( stream_prefs = await get_dynamic_camera_stream_settings(hass, msg["entity_id"])
msg["entity_id"]
)
connection.send_result(msg["id"], asdict(stream_prefs)) connection.send_result(msg["id"], asdict(stream_prefs))

View File

@ -7,10 +7,11 @@ from typing import TYPE_CHECKING
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.exceptions import HomeAssistantError from homeassistant.exceptions import HomeAssistantError
from .const import DATA_COMPONENT from .const import DATA_CAMERA_PREFS, DATA_COMPONENT
if TYPE_CHECKING: if TYPE_CHECKING:
from . import Camera from . import Camera
from .prefs import DynamicStreamSettings
def get_camera_from_entity_id(hass: HomeAssistant, entity_id: str) -> Camera: def get_camera_from_entity_id(hass: HomeAssistant, entity_id: str) -> Camera:
@ -26,3 +27,10 @@ def get_camera_from_entity_id(hass: HomeAssistant, entity_id: str) -> Camera:
raise HomeAssistantError("Camera is off") raise HomeAssistantError("Camera is off")
return camera return camera
async def get_dynamic_camera_stream_settings(
hass: HomeAssistant, entity_id: str
) -> DynamicStreamSettings:
"""Get dynamic stream settings for a camera entity."""
return await hass.data[DATA_CAMERA_PREFS].get_dynamic_stream_settings(entity_id)

View File

@ -31,7 +31,9 @@ from homeassistant.components.camera import (
WebRTCSendMessage, WebRTCSendMessage,
async_register_webrtc_provider, async_register_webrtc_provider,
) )
from homeassistant.components.camera.helper import get_dynamic_camera_stream_settings
from homeassistant.components.default_config import DOMAIN as DEFAULT_CONFIG_DOMAIN from homeassistant.components.default_config import DOMAIN as DEFAULT_CONFIG_DOMAIN
from homeassistant.components.stream import Orientation
from homeassistant.config_entries import SOURCE_SYSTEM, ConfigEntry from homeassistant.config_entries import SOURCE_SYSTEM, ConfigEntry
from homeassistant.const import CONF_URL, EVENT_HOMEASSISTANT_STOP from homeassistant.const import CONF_URL, EVENT_HOMEASSISTANT_STOP
from homeassistant.core import Event, HomeAssistant, callback from homeassistant.core import Event, HomeAssistant, callback
@ -57,12 +59,13 @@ from .server import Server
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
_FFMPEG = "ffmpeg"
_SUPPORTED_STREAMS = frozenset( _SUPPORTED_STREAMS = frozenset(
( (
"bubble", "bubble",
"dvrip", "dvrip",
"expr", "expr",
"ffmpeg", _FFMPEG,
"gopro", "gopro",
"homekit", "homekit",
"http", "http",
@ -310,6 +313,34 @@ class WebRTCProvider(CameraWebRTCProvider):
await self.teardown() await self.teardown()
raise HomeAssistantError("Stream source is not supported by go2rtc") raise HomeAssistantError("Stream source is not supported by go2rtc")
camera_prefs = await get_dynamic_camera_stream_settings(
self._hass, camera.entity_id
)
if camera_prefs.orientation is not Orientation.NO_TRANSFORM:
# Camera orientation manually set by user
if not stream_source.startswith(_FFMPEG):
stream_source = _FFMPEG + ":" + stream_source
stream_source += "#video=h264#audio=copy"
match camera_prefs.orientation:
case Orientation.MIRROR:
stream_source += "#raw=-vf hflip"
case Orientation.ROTATE_180:
stream_source += "#rotate=180"
case Orientation.FLIP:
stream_source += "#raw=-vf vflip"
case Orientation.ROTATE_LEFT_AND_FLIP:
# Cannot use any filter when using raw -vf
# https://github.com/AlexxIT/go2rtc/issues/487
stream_source += "#raw=-vf transpose=2,vflip"
case Orientation.ROTATE_LEFT:
stream_source += "#rotate=-90"
case Orientation.ROTATE_RIGHT_AND_FLIP:
# Cannot use any filter when using raw -vf
# https://github.com/AlexxIT/go2rtc/issues/487
stream_source += "#raw=-vf transpose=1,vflip"
case Orientation.ROTATE_RIGHT:
stream_source += "#rotate=90"
streams = await self._rest_client.streams.list() streams = await self._rest_client.streams.list()
if (stream := streams.get(camera.entity_id)) is None or not any( if (stream := streams.get(camera.entity_id)) is None or not any(