1 Replies - 5659 Views - Last Post: 31 October 2011 - 01:37 PM Rate Topic: -----

#1 NotarySojac  Icon User is offline

  • D.I.C Regular
  • member icon

Reputation: 53
  • View blog
  • Posts: 428
  • Joined: 30-September 10

Ruby and video streaming

Posted 27 October 2011 - 12:58 PM

Hey, I'm about to start work on an OpenCV project involving "blob tracking". I got a new cam in the mail, but I was thinking about starting out by doing some desktop/ predefined-image streaming to make testing a little easier.

The IP cam I put on order offers mjpeg streaming, which I haven't heard about before, but it looks like you can direct a webbrowser to an IP:port that's streaming and webbrowsers like firefox and chrome will "just wrok" and play the stream (unconfirmed =/ but that style of streaming would simplify things for other projects I have). Unfortunately, the only example I could find for that is a java example, which is a language I'm only so-so at (links working again).

Does anyone have any thoughts or ideas on streaming images in a simple yet versatile way using ruby?

This post has been edited by NotarySojac: 27 October 2011 - 01:24 PM


Is This A Good Question/Topic? 0
  • +

Replies To: Ruby and video streaming

#2 NotarySojac  Icon User is offline

  • D.I.C Regular
  • member icon

Reputation: 53
  • View blog
  • Posts: 428
  • Joined: 30-September 10

Re: Ruby and video streaming

Posted 31 October 2011 - 01:37 PM

If anyone's interested, I've made the progress I needed to get started.

After spending like a day setting up a java IDE and doing some hello java vlogs, I realized I should really be searching for "build your own webserver" google results. After that it came together really nicely.

Here's a simple ruby http server that, by default, will stream /web/test.jpg and /web/test2.jpg to anyone trying to connect (single thread so one customer at a time). I don't have any sort of code for setting a frame rate so the images come in pretty randomly. It's kinda cool.
# Here's a simple webserver.  It mostly just does files and lame stuff
# It Might not work right unless you explicitly change the global 
# variable IS_UNIX to true/false, depending on your situation.  

#  Expected files/folder!
#
#  Linux:
#  "/web/test.jpg"       # a jpeg file to test
#  "/web/test2.jpg"      # a different jpeg
#
#  Windows:
#  "c:\web\test.jpg" 
#  "c:\web\test2.jpg" 

#  Notes:
#
#  You can toggle IS_TESTING_MJPEG to off if you'd like to just get an http server
#  going, but I should enphasize that this is a proof of concept and is probably
#  Unsafe and certainly quite easy to DOS.  /web/index.html should exist.  
#
#  Once it's running, you can connect to it by dailing in 127.0.0.1:9090 on your
#  local web browser.  





#  Ignore this code, it has nothing to do with the server, it just checks if
#  You're testing it on windows
def Kernel.is_unix?
  processor, platform, *rest = RUBY_PLATFORM.split("-")
  return false if platform == 'mswin32' or platform == 'mingw32'
  return true  # There's a somewhat good chance this is a unix machine after all...
end

IS_UNIX = Kernel.is_unix?
IS_TESTING_MJPEG = true



#  Begin server specific code
#  ref:  an msdn blog whose author decided leaving a note "this won't work on linux" 
#   was better than coding for that likely possibility 
#


require 'socket'

class HttpServer
  def initialize(session, request, basePath)
    @session = session
    @request = request
    @basePath = basePath
  end

  def getFullPath()
    fileName = nil
    if @request =~ /GET .* HTTP.*/
      fileName = @request.gsub(/GET /, '').gsub(/ HTTP.*/, '')
    end
    fileName = fileName.strip
    unless fileName == nil
      fileName = @basePath + fileName
      fileName = File.expand_path(fileName, @defaultPath)
      fileName.gsub!('/', '\\')
    end
    fileName << "\\index.html" if  File.directory?(fileName)
    fileName.gsub!('\\', '/') if IS_UNIX
    return fileName
  end

  def serve()      # This function gets hit every time someone sends a request to the server
    puts "serv()"  # notice that I stubbed it with my own function
    if IS_TESTING_MJPEG
      serv_mjpeg
      return
    end
    @fullPath = getFullPath()
    src = nil
    begin
      if File.exist?(@fullPath) and File.file?(@fullPath)
        if @fullPath.index(@basePath) == 0 #path should start with base path
          contentType = getContentType(@fullPath)
          @session.print "HTTP/1.1 200/OK\r\nServer: Someones\r\nContent-type: #{contentType}\r\n\r\n"
          src = File.open(@fullPath, "rb")
          while (not src.eof?)
            buffer = src.read(256)
            @session.write(buffer)
          end
          src.close
          src = nil
        else
          # should have sent a 403 Forbidden access but then the attacker knows that such a file exists
          @session.print "HTTP/1.1 404/Object Not Found\r\nServer: Someones\r\n\r\n"
        end
      else
        @session.print "HTTP/1.1 404/Object Not Found\r\nServer: Someones\r\n\r\n"
      end
    ensure
      src.close unless src == nil
      @session.close
    end
  end
  
  def serv_mjpeg()
    puts "serving mjpeg only"
    
    # Print the header
    @session.print "HTTP/1.0 200 OK\r\n" +
      "Server: YourServerName\r\n" +
      "Connection: close\r\n" +
      "Max-Age: 0\r\n" +
      "Expires: 0\r\n" +
      "Cache-Control: no-cache, private\r\n" + 
      "Pragma: no-cache\r\n" + 
      "Content-Type: multipart/x-mixed-replace; " +
      "boundary=--BoundaryString\r\n\r\n"
    
    
    file_one = "c:\\test.jpg"
    file_two = "c:\\test2.jpg"
    
    if IS_UNIX
      file_one = "/web/test.jpg"
      file_two = "/web/test2.jpg"
    end
    
    flip_me = false
    
    while true do
      
      file = flip_me ? file_one : file_two
      flip_me = !flip_me
      
      # read jpeg
      data = nil
      data = File.open(file, "rb")
    
      # Print the image file's header
      @session.print "--BoundaryString\r\n" +
          "Content-type: image/jpg\r\n" +
          "Content-Length: " +
          data.size.to_s +
          "\r\n\r\n"
      
      # Print the actual image data
      #@session.print data
      while (not data.eof?)
        buffer = data.read(256)
        @session.write(buffer)
      end
      data.close
      data = nil

      @session.print "\r\n\r\n"
    end
    @session.close
    puts "Done serving"
  end

  def getContentType(path)
    ext = File.extname(path)
    return "text/html"  if ext == ".html" or ext == ".htm"
    return "text/plain" if ext == ".txt"
    return "text/css"   if ext == ".css"
    return "image/jpeg" if ext == ".jpeg" or ext == ".jpg"
    return "image/gif"  if ext == ".gif"
    return "image/bmp"  if ext == ".bmp"
    return "text/plain" if ext == ".rb"
    return "text/xml"   if ext == ".xml"
    return "text/xml"   if ext == ".xsl"
    return "text/html"
  end
end

def logger(message)
  logStr =  "\n\n======================================================\n#{message}"
  puts logStr
  $log.puts logStr unless $log == nil
end

# ~ENTRY POINT

basePath = "c:\\web"
basePath = "/web" if IS_UNIX  # base path for linux

server = TCPServer.new('0.0.0.0', 9090)             # put in 0.0.0.0 as the server name to allow the server to recieve requests marked to any Server host name (192.168.1.243, 88.123.213.21, YOUR_SERVER.com, etc.) )
                                                    # also specify the port to be 9090
logfile = basePath + "\\log.txt"
logfile = basePath + "/log.txt" if IS_UNIX  # logfile for linux

$log = File.open(logfile, "w+")

loop do
  session = server.accept         # the program is going to wait here forever, 
                                  # OR until someone actually connects to the 
                                  # server on the specified port. 
                                  
  request = session.gets          # The program will wait here until it recieves 
                                  # a 'get' request from the client.  Thanks to
                                  # how buggy this program was written, you can 
                                  # DOS the server by connecting to the server 
                                  # through telnet on port 9090.  
  
  
  logStr =  "#{session.peeraddr[2]} (#{session.peeraddr[3]})\n"
  logStr += Time.now.localtime.strftime("%Y/%m/%d %H:%M:%S")
  logStr += "\n#{request}"
  logger(logStr)
  
  Thread.start(session, request) do |session, request|
    HttpServer.new(session, request, basePath).serve()
  end
end
log.close


Was This Post Helpful? 1
  • +
  • -

Page 1 of 1