Boombox - a simple streaming library on top of Membrane

Hi everyone,

I’d like to share with you a new library from the Membrane team - Boombox. It’s a simple streaming tool built on top of Membrane. It’s not as flexible as Membrane, but simpler to learn :wink:
For example, receiving an RTMP stream and broadcasting it via HLS is as simple as

Mix.install([:boombox])

Boombox.run(input: "rtmp://localhost:5432", output: "index.m3u8")

Boombox also allows you to interact with media in the Elixir code using a Stream-based API. For example, here’s how to generate a video and send it to a browser over WebRTC using Boombox and Image:

Mix.install([:boombox, :image, :req])

image =
  Req.get!("https://avatars.githubusercontent.com/u/25247695?s=200&v=4").body
  |> Image.open!()

angle = Stream.iterate(0, fn a -> rem(a + 3, 360) end)

timestamps =
  Stream.iterate(0, fn pts -> pts + div(Membrane.Time.seconds(1), 60) end)

Stream.zip(angle, timestamps)
|> Stream.map(fn {angle, pts} ->
  image = Image.rotate!(image, angle) |> Image.thumbnail!(200)
  %Boombox.Packet{kind: :video, payload: image, pts: pts}
end)
|> Boombox.run(
  input: {:stream, video: :image, audio: false},
  output: {:webrtc, "ws://localhost:8830"}
)

And there’s much more - see examples.

More info in the blog post.

We hope that Boombox will make media streaming in Elixir easier for everyone and smooth out the learning curve for Membrane :wink:

Happy streaming!

29 Likes

Fantastic work! I can’t wait to play with this.

7 Likes

Thanks! Specially for you, thumbnails :tada:

Boombox.run(input: "file.mp4", output: {:stream, video: :image, audio: false})
|> Stream.chunk_by(fn packet -> div(packet.pts, Membrane.Time.seconds(2)) end)
|> Stream.map(fn chunk -> hd(chunk).payload |> Image.thumbnail!(200) end)
|> Stream.with_index()
|> Enum.each(fn {thumbnail, i} -> Image.write(thumbnail, "thumb_#{i}.jpg") end)
2 Likes

You can just do Image.open() on a binary too (at least for most common image formats).

Great project, can’t wait to give this a spin!

1 Like

Thanks, that’s much better! And thanks again for Image, it’s been a pleasure to use and docs are wonderful :wink:

This is very cool!

I have a locally-running project that’s using MediaMTX to convert some IP camera RTSP streams to WebRTC (WHEP), which I then display in-browser using LiveView JS hooks. It looks like Boombox doesn’t quite replace this yet, but I’m looking forward to the day when I can plug something like this into my application and Phoenix router and have everything done in Elixir-land. :smile:

1 Like

Receiving RTSP and forwarding via WebRTC is already supported:

Boombox.run(input: "rtsp://my.rtsp.stream/", output: {:webrtc, "ws://signaling_url"})

but it’s point-to-point and WHEP is not there yet. But it’s going to change soon :wink:

1 Like

Yep! I was looking through some issues yesterday and saw that work was being done in membrane_plugin_webrtc and elsewhere :slight_smile:

What I’d eventually love would be something like…

# my_app/application.ex
children = [
  {Boombox, inputs: [cam1: "rtsp://...", cam2: "rtsp://..."], name: MyApp.Boombox}
  # ...
]

# my_app_web/router.ex
boombox_routes "/cams", boombox: MyApp.Boombox

and be able to hit /cams/cam1/whep to get things going :eyes:. This is just be spitballing, though – everything y’all are doing is insanely cool regardless!

This is very helpful, please keep doing it :smiley: I’d love to hear about more potential use cases that people have

Fantastic! Does Boombox support transcoding RTMP input to include multiple resolutions in the HLS output? Perhaps offloading the transcoding job to a different server/service?

Not yet. Added to the wishlist though :smiley: You may also check out this Membrane plugin: GitHub - membraneframework/membrane_abr_transcoder_plugin: ABR (adaptive bitrate) transcoder, that accepts an h.264 video and outputs multiple variants of it with different qualities.

3 Likes