From f5960b633382142332045c601c7d9edb14df7cf8 Mon Sep 17 00:00:00 2001 From: Mebareksaf Date: Wed, 20 Dec 2023 16:19:52 +0100 Subject: [PATCH] create a separate playbackSpeeder element --- .../ex_nvr/elements/recording/timestamper.ex | 15 +----- .../lib/ex_nvr/elements/recording_bin.ex | 13 +---- .../ex_nvr/lib/ex_nvr/hls/playback_speeder.ex | 47 +++++++++++++++++++ .../lib/ex_nvr/pipelines/hls_playback.ex | 8 ++-- apps/ex_nvr_web/assets/js/app.js | 2 - .../lib/ex_nvr_web/live/dashboard_live.ex | 2 +- 6 files changed, 54 insertions(+), 33 deletions(-) create mode 100644 apps/ex_nvr/lib/ex_nvr/hls/playback_speeder.ex diff --git a/apps/ex_nvr/lib/ex_nvr/elements/recording/timestamper.ex b/apps/ex_nvr/lib/ex_nvr/elements/recording/timestamper.ex index 1dbb62fe..2ca7ab1b 100644 --- a/apps/ex_nvr/lib/ex_nvr/elements/recording/timestamper.ex +++ b/apps/ex_nvr/lib/ex_nvr/elements/recording/timestamper.ex @@ -12,16 +12,6 @@ defmodule ExNVR.Elements.Recording.Timestamper do start_date: [ spec: Membrane.Time.t(), description: "The start date of the first buffer" - ], - playback_speed: [ - spec: float(), - default: 1, - description: """ - The playback speed rate to either speed up or slow down the stream. - * A value lower than 1: speeds up the stream. - * A value greater than 1: slows down the stream. - * 1 is the default value which is the normal stream speed. - """ ] def_input_pad :input, @@ -36,12 +26,10 @@ defmodule ExNVR.Elements.Recording.Timestamper do @impl true def handle_init(_ctx, options) do - IO.inspect("Playback from TimeStamper: #{options.playback_speed}") {[], %{ offset: options.offset, start_date: options.start_date, - playback_speed: options.playback_speed, last_buffer_dts_or_pts: nil }} end @@ -59,10 +47,9 @@ defmodule ExNVR.Elements.Recording.Timestamper do buffer_duration = Membrane.Buffer.get_dts_or_pts(buffer) - state.last_buffer_dts_or_pts metadata = Map.put(buffer.metadata, :timestamp, state.start_date + buffer_duration) - IO.inspect("Old #{(buffer.pts + state.offset)} Multiply by #{state.playback_speed} gives: #{(buffer.pts + state.offset) * state.playback_speed}") buffer = %{ buffer - | pts: (buffer.pts + state.offset) * state.playback_speed, + | pts: buffer.pts + state.offset, dts: buffer.dts + state.offset, metadata: metadata } diff --git a/apps/ex_nvr/lib/ex_nvr/elements/recording_bin.ex b/apps/ex_nvr/lib/ex_nvr/elements/recording_bin.ex index 0a6864b0..f3c7c95d 100644 --- a/apps/ex_nvr/lib/ex_nvr/elements/recording_bin.ex +++ b/apps/ex_nvr/lib/ex_nvr/elements/recording_bin.ex @@ -57,16 +57,6 @@ defmodule ExNVR.Elements.RecordingBin do Note that if both `duration` and `end_date` are provided, an `end_of_stream` will be sent on the first satisfied condition. """ - ], - playback_speed: [ - spec: float(), - default: 1, - description: """ - The playback speed rate to either speed up or slow down the stream. - * A value lower than 1: speeds up the stream. - * A value greater than 1: slows down the stream. - * 1 is the default value which is the normal stream speed. - """ ] def_output_pad :video, @@ -123,8 +113,7 @@ defmodule ExNVR.Elements.RecordingBin do |> add_depayloader(track, id) |> child({:timestamper, id}, %Timestamper{ offset: state.recording_duration, - start_date: Membrane.Time.from_datetime(state.current_recording.start_date), - playback_speed: state.playback_speed + start_date: Membrane.Time.from_datetime(state.current_recording.start_date) }) |> get_child(:funnel) ] diff --git a/apps/ex_nvr/lib/ex_nvr/hls/playback_speeder.ex b/apps/ex_nvr/lib/ex_nvr/hls/playback_speeder.ex new file mode 100644 index 00000000..4a0a9ed6 --- /dev/null +++ b/apps/ex_nvr/lib/ex_nvr/hls/playback_speeder.ex @@ -0,0 +1,47 @@ +defmodule ExNVR.HLS.PlaybackSpeeder do + @moduledoc """ + Rewrites buffers pts according to the prodivded playback rate. + """ + + use Membrane.Filter + + def_input_pad :input, + demand_mode: :auto, + demand_unit: :buffers, + accepted_format: _any, + availability: :always + + def_output_pad :output, + demand_mode: :auto, + accepted_format: _any + + def_options rate: [ + spec: float(), + default: 1, + description: """ + The playback speed rate to either speed up or slow down the stream. + * A value lower than 1: speeds up the stream. + * A value greater than 1: slows down the stream. + * 1 is the default value which is the normal stream speed. + """ + ] + + @impl true + def handle_init(_ctx, options) do + state = + options + |> Map.from_struct() + + {[], state} + end + + @impl true + def handle_process(:input, buffer, _ctx, state) do + buffer = %{ + buffer + | pts: trunc(buffer.pts * state.rate) + } + + {[buffer: {:output, buffer}], state} + end +end diff --git a/apps/ex_nvr/lib/ex_nvr/pipelines/hls_playback.ex b/apps/ex_nvr/lib/ex_nvr/pipelines/hls_playback.ex index f8538344..05e56c8c 100644 --- a/apps/ex_nvr/lib/ex_nvr/pipelines/hls_playback.ex +++ b/apps/ex_nvr/lib/ex_nvr/pipelines/hls_playback.ex @@ -7,7 +7,7 @@ defmodule ExNVR.Pipelines.HlsPlayback do require Membrane.Logger - alias ExNVR.Elements + alias ExNVR.{Elements, HLS} alias ExNVR.Pipeline.Output @call_timeout :timer.seconds(10) @@ -43,11 +43,11 @@ defmodule ExNVR.Pipelines.HlsPlayback do spec = [ child(:source, %Elements.RecordingBin{ device: options[:device], - start_date: options[:start_date], - playback_speed: playback_speed + start_date: options[:start_date] }) |> via_out(:video) - |> child(:realtimer, ExNVR.Elements.Realtimer) + |> child(:realtimer, Elements.Realtimer) + |> child(:playback_speeder, %HLS.PlaybackSpeeder{rate: playback_speed}) |> via_in(Pad.ref(:video, :playback), options: [resolution: options[:resolution]]) |> child(:sink, %Output.HLS{ location: options[:directory], diff --git a/apps/ex_nvr_web/assets/js/app.js b/apps/ex_nvr_web/assets/js/app.js index f0838e7c..e2f0b1ac 100644 --- a/apps/ex_nvr_web/assets/js/app.js +++ b/apps/ex_nvr_web/assets/js/app.js @@ -85,7 +85,6 @@ let Hooks = { this.el.addEventListener("ratechange", this.changePlaybackspeed); }, changePlaybackspeed(event) { - console.log(event) let video = document.getElementById("live-video"); var rate = video.playbackRate; if (rate != 1) { @@ -110,7 +109,6 @@ let Hooks = { rate = 0.25; break; } - alert(rate) window.TimelineHook.pushEvent("playback_speed", { speedRate: rate, }) diff --git a/apps/ex_nvr_web/lib/ex_nvr_web/live/dashboard_live.ex b/apps/ex_nvr_web/lib/ex_nvr_web/live/dashboard_live.ex index d693e53e..4002a883 100644 --- a/apps/ex_nvr_web/lib/ex_nvr_web/live/dashboard_live.ex +++ b/apps/ex_nvr_web/lib/ex_nvr_web/live/dashboard_live.ex @@ -246,7 +246,7 @@ defmodule ExNVRWeb.DashboardLive do def handle_event("playback_speed", %{"speedRate" => speed_rate}, socket) do socket = socket - |> assign_start_date(socket.assigns.current_datetime) + |> assign(start_date: socket.assigns.current_datetime) |> live_view_enabled?() |> maybe_push_stream_event(socket.assigns.current_datetime, speed_rate)