Skip to content

Commit f7103da

Browse files
authored
Refactor av.open calls to support type annotations (#129688)
1 parent bf4922a commit f7103da

File tree

2 files changed

+60
-60
lines changed

2 files changed

+60
-60
lines changed

homeassistant/components/stream/recorder.py

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -105,17 +105,16 @@ def write_segment(segment: Segment) -> None:
105105

106106
# Create output on first segment
107107
if not output:
108+
container_options: dict[str, str] = {
109+
"video_track_timescale": str(int(1 / source_v.time_base)),
110+
"movflags": "frag_keyframe+empty_moov",
111+
"min_frag_duration": str(self.stream_settings.min_segment_duration),
112+
}
108113
output = av.open(
109114
self.video_path + ".tmp",
110115
"w",
111116
format=RECORDER_CONTAINER_FORMAT,
112-
container_options={
113-
"video_track_timescale": str(int(1 / source_v.time_base)),
114-
"movflags": "frag_keyframe+empty_moov",
115-
"min_frag_duration": str(
116-
self.stream_settings.min_segment_duration
117-
),
118-
},
117+
container_options=container_options,
119118
)
120119

121120
# Add output streams if necessary

homeassistant/components/stream/worker.py

Lines changed: 54 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -164,63 +164,64 @@ def make_new_av(
164164
av.audio.stream.AudioStream | None,
165165
]:
166166
"""Make a new av OutputContainer and add output streams."""
167+
container_options: dict[str, str] = {
168+
# Removed skip_sidx - see:
169+
# https://github.com/home-assistant/core/pull/39970
170+
# "cmaf" flag replaces several of the movflags used,
171+
# but too recent to use for now
172+
"movflags": "frag_custom+empty_moov+default_base_moof+frag_discont+negative_cts_offsets+skip_trailer+delay_moov",
173+
# Sometimes the first segment begins with negative timestamps,
174+
# and this setting just
175+
# adjusts the timestamps in the output from that segment to start
176+
# from 0. Helps from having to make some adjustments
177+
# in test_durations
178+
"avoid_negative_ts": "make_non_negative",
179+
"fragment_index": str(sequence + 1),
180+
"video_track_timescale": str(int(1 / input_vstream.time_base)),
181+
# Only do extra fragmenting if we are using ll_hls
182+
# Let ffmpeg do the work using frag_duration
183+
# Fragment durations may exceed the 15% allowed variance but it seems ok
184+
**(
185+
{
186+
"movflags": "empty_moov+default_base_moof+frag_discont+negative_cts_offsets+skip_trailer+delay_moov",
187+
# Create a fragment every TARGET_PART_DURATION. The data from
188+
# each fragment is stored in a "Part" that can be combined with
189+
# the data from all the other "Part"s, plus an init section,
190+
# to reconstitute the data in a "Segment".
191+
#
192+
# The LL-HLS spec allows for a fragment's duration to be within
193+
# the range [0.85x,1.0x] of the part target duration. We use the
194+
# frag_duration option to tell ffmpeg to try to cut the
195+
# fragments when they reach frag_duration. However,
196+
# the resulting fragments can have variability in their
197+
# durations and can end up being too short or too long. With a
198+
# video track with no audio, the discrete nature of frames means
199+
# that the frame at the end of a fragment will sometimes extend
200+
# slightly beyond the desired frag_duration.
201+
#
202+
# If there are two tracks, as in the case of a video feed with
203+
# audio, there is an added wrinkle as the fragment cut seems to
204+
# be done on the first track that crosses the desired threshold,
205+
# and cutting on the audio track may also result in a shorter
206+
# video fragment than desired.
207+
#
208+
# Given this, our approach is to give ffmpeg a frag_duration
209+
# somewhere in the middle of the range, hoping that the parts
210+
# stay pretty well bounded, and we adjust the part durations
211+
# a bit in the hls metadata so that everything "looks" ok.
212+
"frag_duration": str(
213+
int(self._stream_settings.part_target_duration * 9e5)
214+
),
215+
}
216+
if self._stream_settings.ll_hls
217+
else {}
218+
),
219+
}
167220
container = av.open(
168221
memory_file,
169222
mode="w",
170223
format=SEGMENT_CONTAINER_FORMAT,
171-
container_options={
172-
# Removed skip_sidx - see:
173-
# https://github.com/home-assistant/core/pull/39970
174-
# "cmaf" flag replaces several of the movflags used,
175-
# but too recent to use for now
176-
"movflags": "frag_custom+empty_moov+default_base_moof+frag_discont+negative_cts_offsets+skip_trailer+delay_moov",
177-
# Sometimes the first segment begins with negative timestamps,
178-
# and this setting just
179-
# adjusts the timestamps in the output from that segment to start
180-
# from 0. Helps from having to make some adjustments
181-
# in test_durations
182-
"avoid_negative_ts": "make_non_negative",
183-
"fragment_index": str(sequence + 1),
184-
"video_track_timescale": str(int(1 / input_vstream.time_base)),
185-
# Only do extra fragmenting if we are using ll_hls
186-
# Let ffmpeg do the work using frag_duration
187-
# Fragment durations may exceed the 15% allowed variance but it seems ok
188-
**(
189-
{
190-
"movflags": "empty_moov+default_base_moof+frag_discont+negative_cts_offsets+skip_trailer+delay_moov",
191-
# Create a fragment every TARGET_PART_DURATION. The data from
192-
# each fragment is stored in a "Part" that can be combined with
193-
# the data from all the other "Part"s, plus an init section,
194-
# to reconstitute the data in a "Segment".
195-
#
196-
# The LL-HLS spec allows for a fragment's duration to be within
197-
# the range [0.85x,1.0x] of the part target duration. We use the
198-
# frag_duration option to tell ffmpeg to try to cut the
199-
# fragments when they reach frag_duration. However,
200-
# the resulting fragments can have variability in their
201-
# durations and can end up being too short or too long. With a
202-
# video track with no audio, the discrete nature of frames means
203-
# that the frame at the end of a fragment will sometimes extend
204-
# slightly beyond the desired frag_duration.
205-
#
206-
# If there are two tracks, as in the case of a video feed with
207-
# audio, there is an added wrinkle as the fragment cut seems to
208-
# be done on the first track that crosses the desired threshold,
209-
# and cutting on the audio track may also result in a shorter
210-
# video fragment than desired.
211-
#
212-
# Given this, our approach is to give ffmpeg a frag_duration
213-
# somewhere in the middle of the range, hoping that the parts
214-
# stay pretty well bounded, and we adjust the part durations
215-
# a bit in the hls metadata so that everything "looks" ok.
216-
"frag_duration": str(
217-
int(self._stream_settings.part_target_duration * 9e5)
218-
),
219-
}
220-
if self._stream_settings.ll_hls
221-
else {}
222-
),
223-
},
224+
container_options=container_options,
224225
)
225226
output_vstream = container.add_stream(template=input_vstream)
226227
# Check if audio is requested

0 commit comments

Comments
 (0)