A motion-jpeg stream with Ruby and Sinatra
I’ve been trying to set up a Motion-JPEG streaming with ruby, for a webcam which uploads a picture per second to a server. I want new images to be served via streaming instead of making the browser call them every second via a javascript call.
I found many different solutions, some of them including EventMachine, which now is not necessary thanks to the new Sinatra 1.3 streaming feature.
The tricky part was related to the headers, the boundary, and the need to send the content type before each image.
For the test I first created a directory and stored some pictures inside
# place some jpg pictures here
And the code. My little app looks like this:
require 'sinatra'
set :server, :thin
get '/' do |dir|
boundary = 'some_shit'
source_dir = '/tmp/images'
headers \
"Cache-Control" => "no-cache, private",
"Pragma" => "no-cache",
"Content-type" => "multipart/x-mixed-replace; boundary=#{boundary}"
stream(:keep_open) do |out|
while true
file = random_file(source_dir) # see also latest_file() below
content = File.open("#{source_dir}/#{file}", 'rb') { |f| f.read }
out << "Content-type: image/jpeg\n\n"
out << content
out << "\n\n--#{boundary}\n\n"
sleep 1
end
end
end
## get a random image from a directory
##
def random_file(dir)
files = Dir.entries(dir).collect { |file| file }
files -= ['.', '..']
files[rand(files.size)]
end
## ... or get the newest image
## In this case I'm not taking the latest file
## uploaded by the camera, but the previous one.
## This is to avoid grabbing a currently uploading
## file, which may be shown as corrupt or incomplete.
##
def latest_file(dir)
files = Dir.entries(dir).collect { |file| file }.sort { |file2,file1| File.mtime(dir+file1) <=> File.mtime(dir+file2) }
files -= ['.', '..']
files[1]
end
Then simply create a Gemfile including Sinatra and Thin, as WebRick is not evented and does not support this kind of stream.
source :rubygems
gem 'sinatra'
gem 'thin'
And that’s all. Run the app and you’re done.
Just visit http://localhost:4567/ with your browser :-)
Categoría: Programación, Ruby 2 comentarios »

enero 13th, 2012 at 19:54
Hello,
I am very interested in your script, but how integrate it into an rails application to streaming a remote ip cam with open-uri and read it in browser ?
thx
enero 14th, 2012 at 20:36
Hello,
You can integrate it in a website by simple using a normal tag. This way:
img src=’http://your.streaming.server/your/motion/stream’