rudebono

rudebono

How can I loop a video/audio file?

Hi everyone,

I’m pretty new to Membrane and don’t have much experience with media programming in general. I’m working on a personal project and have run into a problem I can’t seem to solve.

Here’s my question:

My goal is to take a short video or audio file and have it play on a continuous, infinite loop.

I’ve searched through the official docs, the website, and GitHub examples. I found plenty of information on how to play a file once, but I’m completely stuck on how to make it loop.

I’ve even asked an AI for suggestions, but it gave me a bunch of different ideas (like using a custom Source, a dynamic Pad, or handling Events) that were confusing and didn’t work when I tried them.

So, I was hoping someone here could help.

What is the standard or recommended way to loop a file in Membrane?

I’m looking for a stable and reliable approach.

Any help would be greatly appreciated.

Thanks in advance

Most Liked

mat-hek

mat-hek

Membrane Core Team

Hi there, unfortunately, due to how the framework is designed, it’s not straightforward. The best way IMO is to use the handle_element_end_of_stream callback to know when the stream finishes and restart the pipeline or a part of it. If you want to restart only a part of the pipeline, you need a tee between the part you want to restart and the rest. The stream needs to be at least demuxed (extracted from a container) at that point.

Another approach is to use a looping filter that will buffer the entire stream, as described here. The problem with this approach is that it, well, buffers the entire stream :wink:

rudebono

rudebono

Hello.

I got the idea from the handle_element_end_of_stream callback method you suggested and the link you shared.

Instead of removing the pipeline to stop the media streaming with RTMP later,

I chose to use a custom Membrane.Filter to loop the file again.

Here is a simple example I made:

defmodule MyApp.Application do
  use Application

  @impl true
  def start(_type, _args) do
    children = [
      MyApp.Pipeline
    ]

    opts = [strategy: :one_for_one, name: MyApp.Supervisor]
    Supervisor.start_link(children, opts)
  end
end
defmodule MyApp.Pipeline do
  use Membrane.Pipeline

  @location :code.priv_dir(:my_app) |> Path.join("bgm_24000hz_1ch_s16le.wav")
  @stream_format %Membrane.RawAudio{sample_rate: 24_000, channels: 1, sample_format: :s16le}

  def start_link(_opts) do
    Membrane.Pipeline.start_link(__MODULE__, [], name: __MODULE__)
  end

  @impl true
  def handle_init(_ctx, _opts) do
    spec = [
      child(:source, %Membrane.File.Source{location: @location, seekable?: true})
      |> child(:loop_filter, MyApp.LoopFilter)
      |> child(:raw_parser, %Membrane.RawAudioParser{
        stream_format: @stream_format,
        overwrite_pts?: true
      })
      |> child(:sink, Membrane.PortAudio.Sink)
    ]

    {[spec: spec], %{}}
  end
end
defmodule MyApp.LoopFilter do
  use Membrane.Filter

  def_input_pad(:input, accepted_format: _any)
  def_output_pad(:output, accepted_format: _any)

  @impl true
  def handle_init(_ctx, _opts) do
    {[], %{}}
  end

  @impl true
  def handle_playing(_ctx, state) do
    {[event: {:input, %Membrane.File.SeekSourceEvent{start: :bof, size_to_read: :infinity}}],
     state}
  end

  @impl true
  def handle_event(:input, %Membrane.File.EndOfSeekEvent{}, _ctx, state) do
    {[event: {:input, %Membrane.File.SeekSourceEvent{start: :bof, size_to_read: :infinity}}],
     state}
  end

  @impl true
  def handle_event(pad, event, ctx, state) do
    super(pad, event, ctx, state)
  end

  @impl true
  def handle_buffer(:input, buffer, _ctx, state) do
    {[buffer: {:output, buffer}], state}
  end
end

There’s no problem with Membrane.PortAudio.Sink, but later, when I add an audio mixer and send it via RTMP, additional pipelines may be created.

I’ll ask if I have more questions later.

It was very helpful, Thank you!

Where Next?

Popular in Discussions Top

ricklove
I was just introduced to Elixir and Phoenix. I was told about the 2 million websocket test that was done 2 years ago. From my research, t...
New
JakeBecker
TL;DR: I’ve just released an implementation of Microsoft’s IDE-independent Language Server Protocol for Elixir. It adds language support ...
1144 54120 245
New
rower687
Hi all, I’ve been reading a lot about the “let it crash” term and how supervising processes and the whole messaging passing make an elixi...
New
rms.mrcs
A couple of days ago I was discussing with a friend about different approaches to write microservices. He said that if he was going to w...
New
wmnnd
The Go vs Elixir thread got me thinking: Would it be too hard to implement a simple mechanism for creating Go-style static app binaries f...
New
Jayshua
I recently came across the javascript library htmx. It reminded me a lot of liveview so I thought the community here might be interested....
New
Rustixir
Hi everyone, im working on find best language/framework/system for high concurrency, high performance and stable performance after wor...
New
cblavier
Hey there, It’s been more than a year since we started using LiveView as our main UI library and building a whole library of UI componen...
New
100phlecs
Are there any downsides, like perf issues, to putting all functional components in CoreComponents as long as you prefix it with the conte...
New
matthias_toepp
I’d love to hear what people think about Wisp, the new Gleam web framework started by Gleam’s primary creator Louis Pilfold. Gleam, alon...
New

Other popular topics Top

Qqwy
Original source of discussion: This topic on the Pragmatic Programmers’ Functional Web Development with Elixir, OTP, and Phoenix forum. ...
New
mcarvalho
What is the difference between System.get_env and Application.get_env? For example, what are best practices to use one versus another.
New
boundedvariable
I am going through the kafka architecture. All the features what the kafka is providing are already in Erlang. I would like hear your opi...
New
Darmani72
If I have a post route which an argument: post /my_post_route/:my_param1, MyController.my_post_handler How would get the post params ...
New
greenz1
I have a phoenix application from which a user can download multiple(5-6) files of size 1MB. I couldn’t find anything related to sending ...
New
bsollish-terakeet
Credo is smart enough to check for (something like) this: assert length(the_list) == 0 with this response: Checking if an enum is empt...
New
pmjoe
I have a relationship of love and hate with Elixir. Lots of things are just absolutely right, but there are some things that are kind of ...
New
sergio
Kind of like when jquery came out, it was super necessary. Existing drag and drop libraries have a bunch of baggage to support old browse...
New
jason.o
In the code below, if the create action is not set to accept “extra_key” as an input, it errors out with a message shown above. Is there ...
New
AstonJ
Posting this to see if we can make things easier for people to get into Neovim. If you use Neovim and have a favourite distro please let ...
New

Latest on Elixir Forum

Elixir Forum

We're in Beta

About us Mission Statement