diff --git a/CHANGELOG.md b/CHANGELOG.md index 60624c5..803b9a5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ * Add ci GitHub action * Bump ex_m3u8 dependency. * Improve fragments (moof/mdat) generation in low latency HLS. +* Set correctly independent flag in `EXT-X-PART`. ## v0.5.0 - 2025-12-24 diff --git a/lib/hlx/media_playlist.ex b/lib/hlx/media_playlist.ex index 87184aa..6ff64ad 100644 --- a/lib/hlx/media_playlist.ex +++ b/lib/hlx/media_playlist.ex @@ -64,17 +64,23 @@ defmodule HLX.MediaPlaylist do add_segment(%{state | pending_segment: nil}, pending_segment) end - @spec add_part(t(), String.t(), number()) :: {Part.t(), t()} - def add_part(%{pending_segment: nil} = playlist, part_uri, part_duration) do - add_part(%{playlist | pending_segment: %Segment{}, part_index: 0}, part_uri, part_duration) + @spec add_part(t(), String.t(), number(), boolean()) :: {Part.t(), t()} + def add_part(%{pending_segment: nil} = playlist, part_uri, part_duration, independent?) do + add_part( + %{playlist | pending_segment: %Segment{}, part_index: 0}, + part_uri, + part_duration, + independent? + ) end - def add_part(%{pending_segment: segment} = playlist, part_uri, part_duration) do + def add_part(%{pending_segment: segment} = playlist, part_uri, part_duration, independent?) do part = %Part{ uri: part_uri, duration: part_duration, index: playlist.part_index, - segment_index: segment_count(playlist) + segment_index: segment_count(playlist), + independent?: independent? } {part, @@ -158,19 +164,17 @@ defmodule HLX.MediaPlaylist do end defp delete_old_parts(state) do - if not is_nil(state.part_target_duration) and state.segment_count > 2 do + if not is_nil(state.part_target_duration) and state.segment_count > 1 do {seg_1, segments} = Qex.pop_back!(state.segments) {seg_2, segments} = Qex.pop_back!(segments) - {seg_3, segments} = Qex.pop_back!(segments) state = segments - |> Qex.push(%{seg_3 | parts: []}) - |> Qex.push(seg_2) + |> Qex.push(%{seg_2 | parts: []}) |> Qex.push(seg_1) |> then(&%{state | segments: &1}) - {state, seg_3.parts} + {state, seg_2.parts} else {state, []} end diff --git a/lib/hlx/part.ex b/lib/hlx/part.ex index 86c1168..a422e71 100644 --- a/lib/hlx/part.ex +++ b/lib/hlx/part.ex @@ -10,10 +10,11 @@ defmodule HLX.Part do size: non_neg_integer(), duration: number(), index: non_neg_integer(), - segment_index: non_neg_integer() + segment_index: non_neg_integer(), + independent?: boolean() } - defstruct [:uri, :size, :duration, :index, :segment_index] + defstruct [:uri, :size, :duration, :index, :segment_index, independent?: false] @spec new(Keyword.t()) :: t() def new(opts) do @@ -27,7 +28,7 @@ defmodule HLX.Part do Serializer.serialize(%Tags.Part{ uri: part.uri, duration: part.duration, - independent?: part.index == 0 + independent?: part.independent? }) end end diff --git a/lib/hlx/writer/tracks_muxer.ex b/lib/hlx/writer/tracks_muxer.ex index f15b68d..537f4e1 100644 --- a/lib/hlx/writer/tracks_muxer.ex +++ b/lib/hlx/writer/tracks_muxer.ex @@ -103,10 +103,15 @@ defmodule HLX.Writer.TracksMuxer do {data, part_duration, muxer_state} = tracks_muxer.muxer_mod.push_parts(parts, tracks_muxer.muxer_state) - tracks_duration = - Map.new(parts, fn {track_id, samples} -> - part_duration = Enum.reduce(samples, 0, &(&1.duration + &2)) - {track_id, tracks_muxer.track_durations[track_id] + part_duration} + {tracks_duration, independent_segment?} = + Enum.reduce(parts, {tracks_muxer.track_durations, true}, fn {track_id, samples}, + {durations, independent?} -> + durations = + Map.update!(durations, track_id, fn d -> + d + Enum.reduce(samples, 0, &(&1.duration + &2)) + end) + + {durations, independent? and hd(samples).sync?} end) tracks_muxer = %{ @@ -115,7 +120,7 @@ defmodule HLX.Writer.TracksMuxer do track_durations: tracks_duration } - {data, part_duration, tracks_muxer} + {{data, part_duration, independent_segment?}, tracks_muxer} end @spec flush(t()) :: {iodata(), non_neg_integer(), t()} diff --git a/lib/hlx/writer/variant.ex b/lib/hlx/writer/variant.ex index a82da38..4d09ac5 100644 --- a/lib/hlx/writer/variant.ex +++ b/lib/hlx/writer/variant.ex @@ -87,9 +87,11 @@ defmodule HLX.Writer.Variant do @spec push_parts(t(), TracksMuxer.parts()) :: t() def push_parts(variant, parts) do - {data, duration, tracks_muxer} = TracksMuxer.push_parts(variant.tracks_muxer, parts) + {{data, duration, independant?}, tracks_muxer} = + TracksMuxer.push_parts(variant.tracks_muxer, parts) + {uri, storage} = Storage.Segment.store_part(data, variant.storage) - {part, playlist} = MediaPlaylist.add_part(variant.playlist, uri, duration) + {part, playlist} = MediaPlaylist.add_part(variant.playlist, uri, duration, independant?) {part, %{