Skip to content

Conversation

@varsill
Copy link
Contributor

@varsill varsill commented Jul 28, 2025

This PR:

  • Updates ex_hls to a version which accepts how_much_to_skip_ms as a parameter
  • Adds how_much_to_skip option to the source element
  • Sends Discontinuity event on each output pad of the Source with duration field set to the duration of skipped part of the stream (it might differ from the requested how_much_to_skip due to the fact that it needs to be aligned with segments)

Related PR: membraneframework/ex_hls#5

closes membraneframework/membrane_core#992

@varsill varsill requested a review from FelonEkonom July 28, 2025 13:45
@FelonEkonom FelonEkonom requested a review from Copilot July 28, 2025 14:29
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR adds the ability to start HLS stream playback from a specific time offset by introducing a start_at option to the Source element. The implementation involves updating the ex_hls dependency to support start time parameters and propagating the start time through the source element and client components.

Key changes:

  • Updates ex_hls dependency to a version that supports start_at_ms parameter
  • Adds start_at option to the Source element with proper documentation and default value
  • Extends the client GenServer to pass start time to the underlying HLS client

Reviewed Changes

Copilot reviewed 4 out of 7 changed files in this pull request and generated 1 comment.

File Description
mix.exs Updates ex_hls dependency to newer commit and temporarily switches to GitHub ref for membrane_mp4_plugin
lib/membrane_http_adaptive_stream/source.ex Adds start_at option definition and passes it to ClientGenServer
lib/membrane_http_adaptive_stream/source/client_genserver.ex Extends GenServer to accept and use start_at parameter when creating HLS client
test/membrane_http_adaptive_stream/integration_test/source_test.exs Adds integration test for start_at functionality with reference files
Comments suppressed due to low confidence (1)

test/membrane_http_adaptive_stream/integration_test/source_test.exs:97

  • Using a fixed sleep duration in tests can lead to flaky tests. Consider using a more deterministic approach like waiting for specific pipeline events or using Testing.Pipeline.assert_end_of_stream/2 to ensure the test completes reliably.
      Process.sleep(10_000)

Comment on lines 83 to 94
hls_to_file_pipeline_spec(
@mpegts_url,
%Membrane.Transcoder{
assumed_input_stream_format: %Membrane.AAC{
encapsulation: :ADTS
},
output_stream_format: Membrane.AAC
},
audio_result_file,
video_result_file,
start_at
)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I forgot to fix it, but in the audio spec branch we should have AAC parser with :out_encapsulation set to :ADTS instead of transcoder with :assumed_input_stream_format in this test and in the test above

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The transcoder there remains unchanged 😢

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've removed it right now ;)

@varsill varsill requested a review from FelonEkonom August 8, 2025 08:38
end

@spec how_much_skipped(pid()) :: Membrane.Time.t()
def how_much_skipped(client_genserver) do
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please rename it to sth like how_much_already_skipped to distinguish it more from how_much_to_skip

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think "already" fits there, but I think how_much_truly_skipped sounds OK

state =
put_in(
state.how_much_skipped,
state.client.base_timestamp_ms |> round() |> Membrane.Time.milliseconds()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is base_timestamp_ms a part of public API? IMO it would be better to access it via a public function with docs and spec

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and I don't get why we set how_much_skipped to base_timestamp_ms - the name of the second variable doesn't sound like a value describing how much of a stream we have already skipped

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, it's a hacky solution (I didn't expect that I would need to send a Discontinuity event with information about how much of the stream was skipped).
how_much_skipped is set to base_timestamp_ms as the client sets base_timestamp_ms to the timestamp of the first non-discarded sample.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As discussed, I've added a helper function in ex_hls

Comment on lines 255 to 266
defp get_discontinuity_events(%{initial_discontinuity_event_sent?: false} = state) do
how_much_skipped = ClientGenServer.how_much_skipped(state.client_genserver)

get_pads(state)
|> Enum.flat_map(fn pad_ref ->
[event: {pad_ref, %Membrane.Event.Discontinuity{duration: how_much_skipped}}]
end)
end

defp get_discontinuity_events(_state) do
[]
end
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

discontinuity events are supposed to be sent up to once on every pad, am I right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that's right

Comment on lines 83 to 94
hls_to_file_pipeline_spec(
@mpegts_url,
%Membrane.Transcoder{
assumed_input_stream_format: %Membrane.AAC{
encapsulation: :ADTS
},
output_stream_format: Membrane.AAC
},
audio_result_file,
video_result_file,
start_at
)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The transcoder there remains unchanged 😢

@varsill varsill requested a review from FelonEkonom August 19, 2025 08:52
defp hls_to_file_pipeline_spec(
url,
audio_transcoder,
audio_processor,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
audio_processor,
audio_parser,

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in one case we pass Transcoder as this "audio_processor" so I would leave it this way

@varsill varsill changed the title Add start_at option to the Source element Add how_much_to_skip option to the Source element Aug 19, 2025
@varsill varsill merged commit 83cdd60 into master Aug 19, 2025
3 checks passed
@varsill varsill deleted the varsill/add_start_at_in_source branch August 19, 2025 09:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Seek in HLS

3 participants