shavit
Video Streaming with Elixir (wiki)
To transcode the video there is FFMPEG.
On Demand
When a user uploads a video, the app renames and copy the file to a path, then call FFMPEG to transcode the video. Let’s say we are using HLS, we can use a script like this, to transcode the video to multiple resolutions, create a playlist file and sequences:
https://github.com/shavit/Diana/blob/master/bin/create_sequence
When a user requests a video, the server responds with m3u8 file, which contains a list of ts files. The creation of the sequence files was done by FFMPEG.
Example:
get "/video/:slug" do
ext = slug
|> String.split(".")
|> List.last
video_file = cond do
ext == "m3u8" -> "tmp/ts/320x180.m3u8"
ext == "ts" -> "tmp/ts/#{slug}"
# Default playlist file
true -> "tmp/ts/320x180.m3u8"
end
file_path = Path.join(System.cwd, video_file)
offset = get_offset(conn.req_headers)
size = get_file_size(file_path)
conn
|> put_resp_content_type("application/vnd.apple.mpegurl")
|> put_resp_header("Accept-Ranges", "bytes")
|> put_resp_header("Content-Length", "#{size}")
|> put_resp_header("Content-Range", "bytes #{offset}-#{size-1}/#{size}")
|> send_file(206, file_path, offset, size-offset)
end
The Content-Range gives the video player the option to seek in the video.
Live video
When a client broadcast the stream, the server should transcode the video on the fly to multiple resolutions and file types. This can be done with FFMPEG too.
To accept the live video, the app can listen to UDP connections in a separate process.
{:ok, _socket} = :gen_udp.open(3001, [:binary, {:active, true}])
When a client request a live stream, the respond should block and wait for data. I started to write named pipes but Elixir couldn’t read the fifos. It seems that it should be done using agents.
Elixir Media Libs
Open source elixir libraries for working with media (currently focused on RTMP). (Dedicated thread is here)
Hex Packages:
- amf0 - Library with functions for serializing and deserializing data in the AMF0 encoding format. It’s not 100% complete on the spec but it has the core types implemented.
- rtmp_handshake - Library that allows systems to perform an RTMP handshake, both as client and a server. It supports both simple and digest handshake formats.
- rtmp_session - An abstraction that represents a single peer in an RTMP connection. This is essentially the core brain of an RTMP peer where you give it TCP packets and it spits out events and tcp responses. Right now it is only programmed to work as a server, but the client portion is on my todo list.
- gen_rtmp_server - Behavior that makes easy to create your own RTMP server and provides callbacks for your own custom application logic to respond to RTMP events
Trending in Wikis
Other Trending Topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #phoenix_html
- #iex
- #blog-post
- #graphql
- #genstage
- #ai
- #elixirconf-us
- #websockets
- #supervisor
- #advent-of-code
- #distillery
- #processes
- #api
- #forms
- #metaprogramming
- #hex
- #performance










First 10 of 12 Posts
AstonJ
That’s really helpful, thanks!
Shall we split your post into a new thread and make it a wiki? (Can add some other info to it as well then - such as other options.) Pretty sure a lot of people will find it helpful in future
shavit
Yes, I wish to finish soon a simple working example and publish it.
AstonJ
…done - I’ll look forward to seeing your example
ijunaidfarooq
Could we shift the whole ffmpeg task to elixir through this? GitHub - talklittle/ffmpex: Elixir wrapper for FFmpeg command line interface · GitHub
KallDrexx
In a semi related note, I am 90% ready to release my rtmp abstraction libraries, a GenRtmpServer abstraction, and a (very) simple rtmp server implementation all in Elixir.
Unfortunately, playback video is artifacting which is the only hold up, and I’m trying to determine where the issue lies (I don’t believe it’s Elixir related but instead an issue with … well I’m still trying to figure it out). Once I can get playback working properly I plan to split the umbrella project out, put it on GitHub, and create hex packages for the different pieces.
OvermindDL1
Ooo, awesome! Looking forward.
shavit
I tried to use the Elixir FFMPEG library, but it seems that it doesn’t support pipes at the moment.
While it still in development, I came up with the following script to write incoming live HLS stream into disk.
Receiving video stream
In order to receive videos from a source, we can listen to UDP packets using a GenServer
The Bucket module is the same as the key value store module on Elixir website. The Encoder is a module that writes to the FFMPEG script above. It is the part where the data should be written into multiple process for multiple resolutions.
This incoming module will store any stream into the same file with the same configuration, so you will need to change that too.
Start the process when the app or the stream starts
Then write to it from Streaming.Incoming
Streaming the live data
You can write the response from the FFMPEG process, back to the key value storage and stream it to client. Keep in mind that unlike streaming files, it will take a lot of memory. It is also FILO, so you will need to reverse the list.
Another option which I use in the example, is to stream the files that FFMPEG created. When a client request the live stream, serve the playlist.m3u8 file and it will contain a list of all the *.ts video files.
Testing the stream
Run this command in order to stream to the server.
You should see the playlist under the ./tmp folder.
sudostack
Anybody have experience or know if Amazon’s Elastic Transcoder is an option that works and is cheaper than running one’s own instance on EC2 with FFmpeg?
idi527
It seems like it wouldn’t be cheaper. With nginx-rtmp (which executes ffmpeg) I can stream all day and pay just the ec2 price, with elastic transcoder I would have to pay $0.015 * 60 * 24 = $21.6 additionally.
aphillipo
Also worth looking at this New York Times project that abstracts the transcoding service allowing you to change in the future and not be locked in:
https://github.com/NYTimes/video-transcoding-api
It looks very very well written…