Add h264_v4l2m2m codec and profiles to HomeKit cameras (#91246)
This commit is contained in:
parent
4f507e7f57
commit
7446ff478f
4 changed files with 90 additions and 4 deletions
|
@ -19,6 +19,8 @@ VIDEO_CODEC_COPY = "copy"
|
|||
VIDEO_CODEC_LIBX264 = "libx264"
|
||||
AUDIO_CODEC_OPUS = "libopus"
|
||||
VIDEO_CODEC_H264_OMX = "h264_omx"
|
||||
VIDEO_CODEC_H264_V4L2M2M = "h264_v4l2m2m"
|
||||
VIDEO_PROFILE_NAMES = ["baseline", "main", "high"]
|
||||
AUDIO_CODEC_COPY = "copy"
|
||||
|
||||
# #### Attributes ####
|
||||
|
@ -54,6 +56,7 @@ CONF_STREAM_ADDRESS = "stream_address"
|
|||
CONF_STREAM_SOURCE = "stream_source"
|
||||
CONF_SUPPORT_AUDIO = "support_audio"
|
||||
CONF_VIDEO_CODEC = "video_codec"
|
||||
CONF_VIDEO_PROFILE_NAMES = "video_profile_names"
|
||||
CONF_VIDEO_MAP = "video_map"
|
||||
CONF_VIDEO_PACKET_SIZE = "video_packet_size"
|
||||
CONF_STREAM_COUNT = "stream_count"
|
||||
|
@ -71,6 +74,7 @@ DEFAULT_MAX_WIDTH = 1920
|
|||
DEFAULT_PORT = 21063
|
||||
DEFAULT_CONFIG_FLOW_PORT = 21064
|
||||
DEFAULT_VIDEO_CODEC = VIDEO_CODEC_LIBX264
|
||||
DEFAULT_VIDEO_PROFILE_NAMES = VIDEO_PROFILE_NAMES
|
||||
DEFAULT_VIDEO_MAP = "0:v:0"
|
||||
DEFAULT_VIDEO_PACKET_SIZE = 1316
|
||||
DEFAULT_STREAM_COUNT = 3
|
||||
|
|
|
@ -40,6 +40,7 @@ from .const import (
|
|||
CONF_VIDEO_CODEC,
|
||||
CONF_VIDEO_MAP,
|
||||
CONF_VIDEO_PACKET_SIZE,
|
||||
CONF_VIDEO_PROFILE_NAMES,
|
||||
DEFAULT_AUDIO_CODEC,
|
||||
DEFAULT_AUDIO_MAP,
|
||||
DEFAULT_AUDIO_PACKET_SIZE,
|
||||
|
@ -51,6 +52,7 @@ from .const import (
|
|||
DEFAULT_VIDEO_CODEC,
|
||||
DEFAULT_VIDEO_MAP,
|
||||
DEFAULT_VIDEO_PACKET_SIZE,
|
||||
DEFAULT_VIDEO_PROFILE_NAMES,
|
||||
SERV_DOORBELL,
|
||||
SERV_MOTION_SENSOR,
|
||||
SERV_SPEAKER,
|
||||
|
@ -111,8 +113,6 @@ RESOLUTIONS = [
|
|||
(1600, 1200),
|
||||
]
|
||||
|
||||
VIDEO_PROFILE_NAMES = ["baseline", "main", "high"]
|
||||
|
||||
FFMPEG_WATCH_INTERVAL = timedelta(seconds=5)
|
||||
FFMPEG_LOGGER = "ffmpeg_logger"
|
||||
FFMPEG_WATCHER = "ffmpeg_watcher"
|
||||
|
@ -128,6 +128,7 @@ CONFIG_DEFAULTS = {
|
|||
CONF_AUDIO_MAP: DEFAULT_AUDIO_MAP,
|
||||
CONF_VIDEO_MAP: DEFAULT_VIDEO_MAP,
|
||||
CONF_VIDEO_CODEC: DEFAULT_VIDEO_CODEC,
|
||||
CONF_VIDEO_PROFILE_NAMES: DEFAULT_VIDEO_PROFILE_NAMES,
|
||||
CONF_AUDIO_PACKET_SIZE: DEFAULT_AUDIO_PACKET_SIZE,
|
||||
CONF_VIDEO_PACKET_SIZE: DEFAULT_VIDEO_PACKET_SIZE,
|
||||
CONF_STREAM_COUNT: DEFAULT_STREAM_COUNT,
|
||||
|
@ -346,7 +347,7 @@ class Camera(HomeAccessory, PyhapCamera):
|
|||
if self.config[CONF_VIDEO_CODEC] != "copy":
|
||||
video_profile = (
|
||||
"-profile:v "
|
||||
+ VIDEO_PROFILE_NAMES[
|
||||
+ self.config[CONF_VIDEO_PROFILE_NAMES][
|
||||
int.from_bytes(stream_config["v_profile_id"], byteorder="big")
|
||||
]
|
||||
+ " "
|
||||
|
|
|
@ -95,6 +95,7 @@ from .const import (
|
|||
TYPE_VALVE,
|
||||
VIDEO_CODEC_COPY,
|
||||
VIDEO_CODEC_H264_OMX,
|
||||
VIDEO_CODEC_H264_V4L2M2M,
|
||||
VIDEO_CODEC_LIBX264,
|
||||
)
|
||||
|
||||
|
@ -107,7 +108,12 @@ MAX_VERSION_PART = 2**32 - 1
|
|||
|
||||
|
||||
MAX_PORT = 65535
|
||||
VALID_VIDEO_CODECS = [VIDEO_CODEC_LIBX264, VIDEO_CODEC_H264_OMX, AUDIO_CODEC_COPY]
|
||||
VALID_VIDEO_CODECS = [
|
||||
VIDEO_CODEC_LIBX264,
|
||||
VIDEO_CODEC_H264_OMX,
|
||||
VIDEO_CODEC_H264_V4L2M2M,
|
||||
AUDIO_CODEC_COPY,
|
||||
]
|
||||
VALID_AUDIO_CODECS = [AUDIO_CODEC_OPUS, VIDEO_CODEC_COPY]
|
||||
|
||||
BASIC_INFO_SCHEMA = vol.Schema(
|
||||
|
|
|
@ -19,11 +19,13 @@ from homeassistant.components.homekit.const import (
|
|||
CONF_STREAM_SOURCE,
|
||||
CONF_SUPPORT_AUDIO,
|
||||
CONF_VIDEO_CODEC,
|
||||
CONF_VIDEO_PROFILE_NAMES,
|
||||
SERV_DOORBELL,
|
||||
SERV_MOTION_SENSOR,
|
||||
SERV_STATELESS_PROGRAMMABLE_SWITCH,
|
||||
VIDEO_CODEC_COPY,
|
||||
VIDEO_CODEC_H264_OMX,
|
||||
VIDEO_CODEC_H264_V4L2M2M,
|
||||
)
|
||||
from homeassistant.components.homekit.type_cameras import Camera
|
||||
from homeassistant.components.homekit.type_switches import Switch
|
||||
|
@ -516,6 +518,79 @@ async def test_camera_stream_source_configured_and_copy_codec(
|
|||
)
|
||||
|
||||
|
||||
async def test_camera_stream_source_configured_and_override_profile_names(
|
||||
hass: HomeAssistant, run_driver, events
|
||||
) -> None:
|
||||
"""Test a camera that can stream with a configured source over overridden profile names."""
|
||||
await async_setup_component(hass, ffmpeg.DOMAIN, {ffmpeg.DOMAIN: {}})
|
||||
await async_setup_component(
|
||||
hass, camera.DOMAIN, {camera.DOMAIN: {"platform": "demo"}}
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
entity_id = "camera.demo_camera"
|
||||
|
||||
hass.states.async_set(entity_id, None)
|
||||
await hass.async_block_till_done()
|
||||
acc = Camera(
|
||||
hass,
|
||||
run_driver,
|
||||
"Camera",
|
||||
entity_id,
|
||||
2,
|
||||
{
|
||||
CONF_STREAM_SOURCE: "/dev/null",
|
||||
CONF_SUPPORT_AUDIO: True,
|
||||
CONF_VIDEO_CODEC: VIDEO_CODEC_H264_V4L2M2M,
|
||||
CONF_VIDEO_PROFILE_NAMES: ["0", "2", "4"],
|
||||
CONF_AUDIO_CODEC: AUDIO_CODEC_COPY,
|
||||
},
|
||||
)
|
||||
bridge = HomeBridge("hass", run_driver, "Test Bridge")
|
||||
bridge.add_accessory(acc)
|
||||
|
||||
await acc.run()
|
||||
|
||||
assert acc.aid == 2
|
||||
assert acc.category == 17 # Camera
|
||||
|
||||
await _async_setup_endpoints(hass, acc)
|
||||
session_info = acc.sessions[MOCK_START_STREAM_SESSION_UUID]
|
||||
|
||||
working_ffmpeg = _get_working_mock_ffmpeg()
|
||||
|
||||
with patch(
|
||||
"homeassistant.components.demo.camera.DemoCamera.stream_source",
|
||||
return_value=None,
|
||||
), patch(
|
||||
"homeassistant.components.homekit.type_cameras.HAFFmpeg",
|
||||
return_value=working_ffmpeg,
|
||||
):
|
||||
await _async_start_streaming(hass, acc)
|
||||
await _async_reconfigure_stream(hass, acc, session_info, {})
|
||||
await _async_stop_all_streams(hass, acc)
|
||||
|
||||
expected_output = (
|
||||
"-map 0:v:0 -an -c:v h264_v4l2m2m -profile:v 4 -tune zerolatency -pix_fmt yuv420p -r 30 -b:v 299k "
|
||||
"-bufsize 1196k -maxrate 299k -payload_type 99 -ssrc {v_ssrc} -f rtp -srtp_out_suite "
|
||||
"AES_CM_128_HMAC_SHA1_80 -srtp_out_params zdPmNLWeI86DtLJHvVLI6YPvqhVeeiLsNtrAgbgL "
|
||||
"srtp://192.168.208.5:51246?rtcpport=51246&localrtcpport=51246&pkt_size=1316 -map 0:a:0 "
|
||||
"-vn -c:a copy -ac 1 -ar 24k -b:a 24k -bufsize 96k -payload_type 110 -ssrc {a_ssrc} "
|
||||
"-f rtp -srtp_out_suite AES_CM_128_HMAC_SHA1_80 -srtp_out_params "
|
||||
"shnETgfD+7xUQ8zRdsaytY11wu6CO73IJ+RZVJpU "
|
||||
"srtp://192.168.208.5:51108?rtcpport=51108&localrtcpport=51108&pkt_size=188"
|
||||
)
|
||||
|
||||
working_ffmpeg.open.assert_called_with(
|
||||
cmd=[],
|
||||
input_source="-i /dev/null",
|
||||
output=expected_output.format(**session_info),
|
||||
stdout_pipe=False,
|
||||
extra_cmd="-hide_banner -nostats",
|
||||
stderr_pipe=True,
|
||||
)
|
||||
|
||||
|
||||
async def test_camera_streaming_fails_after_starting_ffmpeg(
|
||||
hass: HomeAssistant, run_driver, events
|
||||
) -> None:
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue