@@ -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