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)
Github: https://github.com/KallDrexx/elixir-media-libs
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