mirror of
https://github.com/home-assistant/core.git
synced 2025-07-21 12:17:07 +00:00
Minor cleanup on stream (#58486)
* Allow for rounding errors in playlist validation * Allow EXT-X-TARGETDURATION to change * Reuse original source in test_record_stream_audio
This commit is contained in:
parent
577d8b1469
commit
7024a5d7d9
@ -18,7 +18,14 @@ from .const import (
|
||||
MAX_SEGMENTS,
|
||||
NUM_PLAYLIST_SEGMENTS,
|
||||
)
|
||||
from .core import PROVIDERS, IdleTimer, StreamOutput, StreamSettings, StreamView
|
||||
from .core import (
|
||||
PROVIDERS,
|
||||
IdleTimer,
|
||||
Segment,
|
||||
StreamOutput,
|
||||
StreamSettings,
|
||||
StreamView,
|
||||
)
|
||||
from .fmp4utils import get_codec_string
|
||||
|
||||
if TYPE_CHECKING:
|
||||
@ -44,7 +51,7 @@ class HlsStreamOutput(StreamOutput):
|
||||
"""Initialize HLS output."""
|
||||
super().__init__(hass, idle_timer, deque_maxlen=MAX_SEGMENTS)
|
||||
self.stream_settings: StreamSettings = hass.data[DOMAIN][ATTR_SETTINGS]
|
||||
self._target_duration = 0.0
|
||||
self._target_duration = self.stream_settings.min_segment_duration
|
||||
|
||||
@property
|
||||
def name(self) -> str:
|
||||
@ -53,20 +60,23 @@ class HlsStreamOutput(StreamOutput):
|
||||
|
||||
@property
|
||||
def target_duration(self) -> float:
|
||||
"""
|
||||
Return the target duration.
|
||||
|
||||
The target duration is calculated as the max duration of any given segment,
|
||||
and it is calculated only one time to avoid changing during playback.
|
||||
"""
|
||||
if self._target_duration:
|
||||
return self._target_duration
|
||||
durations = [s.duration for s in self._segments if s.complete]
|
||||
if len(durations) < 2:
|
||||
return self.stream_settings.min_segment_duration
|
||||
self._target_duration = max(durations)
|
||||
"""Return the target duration."""
|
||||
return self._target_duration
|
||||
|
||||
@callback
|
||||
def _async_put(self, segment: Segment) -> None:
|
||||
"""Async put and also update the target duration.
|
||||
|
||||
The target duration is calculated as the max duration of any given segment.
|
||||
Technically it should not change per the hls spec, but some cameras adjust
|
||||
their GOPs periodically so we need to account for this change.
|
||||
"""
|
||||
super()._async_put(segment)
|
||||
self._target_duration = (
|
||||
max((s.duration for s in self._segments), default=segment.duration)
|
||||
or self.stream_settings.min_segment_duration
|
||||
)
|
||||
|
||||
|
||||
class HlsMasterPlaylistView(StreamView):
|
||||
"""Stream view used only for Chromecast compatibility."""
|
||||
|
@ -224,7 +224,9 @@ async def test_ll_hls_stream(hass, hls_stream, stream_worker_sync):
|
||||
datetimes[-1] - datetimes.popleft()
|
||||
).total_seconds()
|
||||
if segment_duration:
|
||||
assert datetime_duration == segment_duration
|
||||
assert math.isclose(
|
||||
datetime_duration, segment_duration, rel_tol=1e-3
|
||||
)
|
||||
tested[datetime_re] = True
|
||||
continue
|
||||
match = inf_re.match(line)
|
||||
@ -232,7 +234,7 @@ async def test_ll_hls_stream(hass, hls_stream, stream_worker_sync):
|
||||
segment_duration = float(match.group("segment_duration"))
|
||||
# Check that segment durations are consistent with part durations
|
||||
if len(part_durations) > 1:
|
||||
assert math.isclose(sum(part_durations), segment_duration)
|
||||
assert math.isclose(sum(part_durations), segment_duration, rel_tol=1e-3)
|
||||
tested[inf_re] = True
|
||||
part_durations.clear()
|
||||
# make sure all playlist tests were performed
|
||||
|
@ -194,7 +194,7 @@ async def test_record_stream_audio(
|
||||
await async_setup_component(hass, "stream", {"stream": {}})
|
||||
|
||||
# Generate source video with no audio
|
||||
source = generate_h264_video(container_format="mov")
|
||||
orig_source = generate_h264_video(container_format="mov")
|
||||
|
||||
for a_codec, expected_audio_streams in (
|
||||
("aac", 1), # aac is a valid mp4 codec
|
||||
@ -202,9 +202,8 @@ async def test_record_stream_audio(
|
||||
("empty", 0), # audio stream with no packets
|
||||
(None, 0), # no audio stream
|
||||
):
|
||||
|
||||
# Remux source video with new audio
|
||||
source = remux_with_audio(source, "mov", a_codec) # mov can store PCM
|
||||
source = remux_with_audio(orig_source, "mov", a_codec) # mov can store PCM
|
||||
|
||||
record_worker_sync.reset()
|
||||
stream_worker_sync.pause()
|
||||
|
Loading…
x
Reference in New Issue
Block a user