Streaming made easy: convert videos to HLS and MPEG-DASH with Ruby
Delivering video content efficiently requires adaptive streaming formats like HLS (HTTP Live Streaming) and MPEG-DASH. In this guide, we'll explore how to convert videos to these formats using Ruby, FFmpeg, and the open-source Streamio FFMPEG gem. By automating video conversion tasks, you can enhance video delivery across various devices and network conditions.
Introduction to HLS and MPEG-DASH
Before diving into the code, let's understand what HLS and MPEG-DASH are and why they're essential for modern video streaming.
HLS is a streaming protocol developed by Apple that breaks down video content into small, HTTP-based file segments, allowing for adaptive bitrate streaming. MPEG-DASH (Dynamic Adaptive Streaming over HTTP) is a similar standard that enables high-quality streaming over the internet by dynamically adjusting the video quality in real-time based on the user's network conditions.
Implementing these formats improves the viewer's experience by reducing buffering and providing optimal video quality. Ensuring your videos can be streamed smoothly across different devices and network environments is crucial for modern applications.
Setting up your Ruby environment for video conversion
First, set up the Ruby environment needed for video conversion.
Ensure you have Ruby 3.0 or higher installed:
ruby -v
If you need to install or upgrade Ruby, use a version manager like RVM or rbenv.
Next, install FFmpeg 6.0 or higher. FFmpeg is required for processing video files.
For macOS users:
brew install ffmpeg
For Ubuntu/Debian users:
sudo apt-get update
sudo apt-get install ffmpeg
Create a new project directory and initialize it:
mkdir video_conversion
cd video_conversion
bundle init
Add the required gems to your Gemfile
:
source 'https://rubygems.org'
gem 'streamio-ffmpeg'
Install the dependencies:
bundle install
Introduction to FFmpeg and streamio FFmpeg gem
FFmpeg is a powerful open-source tool for handling multimedia data. It allows you to record, convert, and stream audio and video files. The Streamio FFMPEG gem provides a Ruby interface to FFmpeg, making it easier to integrate video processing into your Ruby applications.
Converting videos to HLS format in Ruby
Let's create a Ruby class to handle the conversion of videos to HLS format.
Create a new file called video_converter.rb
:
require 'streamio-ffmpeg'
require 'fileutils'
class VideoConverter
def initialize(input_file)
@movie = FFMPEG::Movie.new(input_file)
@input_file = input_file
end
def to_hls(output_dir)
FileUtils.mkdir_p(output_dir)
# Define quality variants
variants = [
{ resolution: '1280x720', bitrate: '2500k' },
{ resolution: '854x480', bitrate: '1500k' },
{ resolution: '640x360', bitrate: '800k' }
]
variant_commands = variants.map do |variant|
%W[
-vf scale=#{variant[:resolution]}
-b:v #{variant[:bitrate]}
-hls_time 10
-hls_playlist_type vod
-hls_segment_filename #{output_dir}/#{variant[:resolution]}_%03d.ts
#{output_dir}/#{variant[:resolution]}.m3u8
]
end
variant_commands.each do |command|
@movie.transcode(nil, {}, { custom: command.flatten })
end
generate_master_playlist(output_dir, variants)
end
private
def generate_master_playlist(output_dir, variants)
master_playlist = "#EXTM3U\n"
variants.each do |variant|
master_playlist += <<~PLAYLIST
#EXT-X-STREAM-INF:BANDWIDTH=#{variant[:bitrate].to_i * 1000},RESOLUTION=#{variant[:resolution]}
#{variant[:resolution]}.m3u8
PLAYLIST
end
File.write("#{output_dir}/master.m3u8", master_playlist)
end
end
This class initializes with an input video file and includes a method to_hls
that converts the
video to HLS format. It creates multiple quality variants and generates a master playlist for
adaptive streaming.
Converting videos to MPEG-DASH in Ruby
To convert videos to MPEG-DASH format, add a to_dash
method to the VideoConverter
class:
def to_dash(output_dir)
FileUtils.mkdir_p(output_dir)
options = %W[
-vf scale=1280:720
-b:v 2500k
-vf scale=854:480
-b:v 1500k
-vf scale=640:360
-b:v 800k
-use_template 1
-use_timeline 1
-adaptation_sets "id=0,streams=v id=1,streams=a"
-seg_duration 10
-f dash
#{output_dir}/manifest.mpd
]
@movie.transcode(nil, {}, { custom: options.flatten })
end
This method converts the input video into MPEG-DASH format, creating a manifest file and necessary segments for streaming.
Handling playlists and manifests in Ruby
Generating correct playlists and manifests is crucial for streaming. In the
generate_master_playlist
method, we build a master playlist that references the individual variant
playlists.
For MPEG-DASH, the manifest.mpd
file is automatically generated by FFmpeg when using the
appropriate flags.
Using the converter
Create a script to utilize the VideoConverter
class:
# Convert.rb
require_relative 'video_converter'
converter = VideoConverter.new('input.mp4')
# Convert to HLS
converter.to_hls('output/hls')
# Convert to MPEG-DASH
converter.to_dash('output/dash')
Run the script:
ruby convert.rb
Ensure that input.mp4
is replaced with the path to your actual video file.
Testing the streams
To test the generated streams, you can use a video player that supports HLS and MPEG-DASH. Here's an example using Video.js:
<!DOCTYPE html>
<html>
<head>
<title>Video Player</title>
<link href="https://vjs.zencdn.net/7.20.3/video-js.css" rel="stylesheet" />
<script src="https://vjs.zencdn.net/7.20.3/video.min.js"></script>
</head>
<body>
<video
id="player"
class="video-js vjs-default-skin"
controls
preload="auto"
width="640"
height="360"
>
<source src="output/hls/master.m3u8" type="application/x-mpegURL" />
<source src="output/dash/manifest.mpd" type="application/dash+xml" />
</video>
<script>
var player = videojs('player')
</script>
</body>
</html>
Open this HTML file in a browser to test the streaming video.
Challenges and solutions in video conversion
Handling large files
Processing large video files can be resource-intensive. Ensure your system has enough CPU and memory resources. For production environments, consider processing videos asynchronously or leveraging cloud services.
Format compatibility
Different browsers and devices have varying levels of support for HLS and MPEG-DASH. Always test your streams across multiple platforms.
Error handling
Add error handling to your VideoConverter
methods:
def to_hls(output_dir)
begin
# HLS conversion code
rescue StandardError => e
puts "Error converting to HLS: #{e.message}"
end
end
Conclusion
Automating video conversion tasks using Ruby, FFmpeg, and the Streamio FFMPEG gem enables you to deliver video content efficiently in adaptive streaming formats like HLS and MPEG-DASH. This enhances the viewer's experience by providing smooth playback across different devices and network conditions.
For a scalable and robust solution to handle video encoding and streaming, consider using Transloadit's video encoding service, which can automate these conversions and offer additional features to streamline your workflow.