module IPCam
Constants
- BASIS_SIZE
- Restart
- Stop
- VERSION
Public Class Methods
abort?()
click to toggle source
# File lib/ipcam/main.rb, line 401 def abort? @state == :ABORT end
add_client(que)
click to toggle source
# File lib/ipcam/main.rb, line 377 def add_client(que) @clients << {:que => que} end
alive?()
click to toggle source
# File lib/ipcam/main.rb, line 397 def alive? @state == :ALIVE end
get_camera_info()
click to toggle source
# File lib/ipcam/main.rb, line 306 def get_camera_info @mutex.synchronize { ret = { :device => $target, :state => @state } ret.merge!(:bus => @camera.bus, :name => @camera.name) if @camera return ret } end
get_config()
click to toggle source
# File lib/ipcam/main.rb, line 324 def get_config raise("state violation") if @state != :ALIVE return @config end
get_ident_string()
click to toggle source
# File lib/ipcam/main.rb, line 319 def get_ident_string raise("state violation") if @state != :ALIVE return "#{@camera.name}@#{@camera.bus}" end
remove_client(que)
click to toggle source
# File lib/ipcam/main.rb, line 381 def remove_client(que) @clients.reject! {|c| c[:que] == que} end
save_config()
click to toggle source
# File lib/ipcam/main.rb, line 368 def save_config $logger.info('main') {"save config to #{$db_file.to_s}"} @mutex.synchronize { $db_file.binwrite(@db.to_msgpack) } broadcast(:save_complete) end
set_control(id, val)
click to toggle source
# File lib/ipcam/main.rb, line 352 def set_control(id, val) raise("state violation") if @state != :ALIVE entry = nil @mutex.synchronize { entry = @config[:controls].find {|obj| obj[:id] == id} entry[:value] = val if entry } if entry restart_camera() broadcast(:update_control, id, val) end end
set_framerate(num, deno)
click to toggle source
# File lib/ipcam/main.rb, line 341 def set_framerate(num, deno) raise("state violation") if @state != :ALIVE @mutex.synchronize { @config[:framerate] = [num, deno] } restart_camera() broadcast(:update_framerate, num, deno) end
set_image_size(width, height)
click to toggle source
# File lib/ipcam/main.rb, line 329 def set_image_size(width, height) raise("state violation") if @state != :ALIVE @mutex.synchronize { @config[:image_width] = width @config[:image_height] = height } restart_camera() broadcast(:update_image_size, width, height) end
start()
click to toggle source
# File lib/ipcam/main.rb, line 19 def start restore_db() @mutex = Mutex.new @camera = nil @state = :STOP @img_que = Thread::Queue.new @clients = [] start_thread() WebServer.start(self) WebSocket.start(self) EM.run end
start_camera()
click to toggle source
# File lib/ipcam/main.rb, line 385 def start_camera raise("state violation") if @state != :STOP and @state != :ABORT start_thread() end
stop()
click to toggle source
# File lib/ipcam/main.rb, line 36 def stop stop_thread() WebServer.stop EM.stop end
stop?()
click to toggle source
# File lib/ipcam/main.rb, line 405 def stop? @state == :STOP end
stop_camera()
click to toggle source
# File lib/ipcam/main.rb, line 391 def stop_camera raise("state violation") if @state != :ALIVE stop_thread() end
Private Class Methods
broadcast(name, *args)
click to toggle source
# File lib/ipcam/main.rb, line 222 def broadcast(name, *args) WebSocket.broadcast(name, *args) end
camera_thread()
click to toggle source
# File lib/ipcam/main.rb, line 239 def camera_thread $logger.info("main") {"camera thread start"} @camera = Video4Linux2::Camera.new($target) if not @camera.support_formats.any? {|x| x.fcc == "MJPG"} raise("#{$target} is not support Motion-JPEG") end snd_thr = Thread.new {sender_thread} begin @mutex.synchronize { @config = load_settings() @camera.start change_state(:ALIVE) } loop { @img_que << @camera.capture } rescue Stop $logger.info("main") {"accept stop request"} change_state(:STOP) rescue Restart $logger.info("main") {"restart camera"} @camera.stop retry ensure @camera.stop if (@camera.busy? rescue false) end rescue => e $logger.error("main") {"camera error occured (#{e.message})"} change_state(:ABORT, :force) ensure @camera&.close @camera = nil snd_thr&.raise(Stop) snd_thr&.join $logger.info("main") {"camera thread stop"} end
change_state(state, force = false)
click to toggle source
# File lib/ipcam/main.rb, line 227 def change_state(state, force = false) flag = @mutex.try_lock if @state != state or force @state = state broadcast(:change_state, state) end @mutex.unlock if flag end
create_capability_list(cam)
click to toggle source
# File lib/ipcam/main.rb, line 89 def create_capability_list(cam) ret = cam.frame_capabilities(:MJPEG).inject([]) { |m, n| m << pack_capability(n) } return ret end
create_control_list(cam)
click to toggle source
# File lib/ipcam/main.rb, line 138 def create_control_list(cam) ret = cam.controls.inject([]) { |m, n| case n when Video4Linux2::Camera::IntegerControl m << pack_integer_control(n) when Video4Linux2::Camera::BooleanControl m << pack_boolean_control(n) when Video4Linux2::Camera::MenuControl m << pack_menu_control(n) else raise("Unknwon control found #{n.class}") end } return ret end
create_setting_entry(cam)
click to toggle source
# File lib/ipcam/main.rb, line 159 def create_setting_entry(cam) cap = select_capabilities(cam) rate = cap.rate.sort.first ret = { :image_width => cap.width, :image_height => cap.height, :framerate => [rate.numerator, rate.denominator], :capabilities => create_capability_list(cam), :controls => create_control_list(cam) } return ret end
load_settings()
click to toggle source
# File lib/ipcam/main.rb, line 200 def load_settings ret = @db.dig(@camera.bus.to_sym, @camera.name.to_sym) if not ret ret = create_setting_entry(@camera) (@db[@camera.bus] ||= {})[@camera.name] = ret $db_file.binwrite(@db.to_msgpack) end @camera.image_height = ret[:image_height] @camera.image_width = ret[:image_width] @camera.framerate = Rational(*ret[:framerate]) ret[:controls].each { |ctr| @camera.set_control(ctr[:id], ctr[:value]) rescue :ignore } return ret end
pack_boolean_control(c)
click to toggle source
# File lib/ipcam/main.rb, line 113 def pack_boolean_control(c) ret = { :type => :boolean, :id => c.id, :name => c.name, :value => c.default } return ret end
pack_capability(cap)
click to toggle source
# File lib/ipcam/main.rb, line 76 def pack_capability(cap) ret = { :width => cap.width, :height => cap.height, :rate => cap.rate.inject([]) { |m, n| m << [n.numerator, n.denominator] } } return ret end
pack_integer_control(c)
click to toggle source
# File lib/ipcam/main.rb, line 98 def pack_integer_control(c) ret = { :type => :integer, :id => c.id, :name => c.name, :value => c.default, :min => c.min, :max => c.max, :step => c.step } return ret end
restart_camera()
click to toggle source
# File lib/ipcam/main.rb, line 55 def restart_camera @cam_thr.raise(Restart) end
restore_db()
click to toggle source
# File lib/ipcam/main.rb, line 175 def restore_db begin blob = $db_file.binread @db = MessagePack.unpack(blob, :symbolize_keys => true) @db.keys { |bus| @db[bus].keys { |name| @db[bus][name.to_s] = @db[bus].delete(name) } @db[bus.to_s] = @db.deleye(bus) } rescue begin $db_file.delete rescue Errno::ENOENT # ignore end @db = {} end end
select_capabilities(cam)
click to toggle source
# File lib/ipcam/main.rb, line 60 def select_capabilities(cam) ret = cam.frame_capabilities(:MJPEG).instance_eval { self.sort! { |a,b| da = (BASIS_SIZE - (a.width * a.height)).abs db = (BASIS_SIZE - (b.width * b.height)).abs da <=> db } self.first } return ret end
sender_thread()
click to toggle source
# File lib/ipcam/main.rb, line 289 def sender_thread $logger.info("main") {"sender thread start"} loop { data = @img_que.deq @clients.each {|c| c[:que] << data} broadcast(:update_image, {:type => "image/jpeg", :data => data}) } rescue Stop @clients.each {|c| c[:que] << nil} ensure $logger.info("main") {"sender thread stop"} end
start_thread()
click to toggle source
# File lib/ipcam/main.rb, line 43 def start_thread @cam_thr = Thread.new {camera_thread} end
stop_thread()
click to toggle source
# File lib/ipcam/main.rb, line 48 def stop_thread @cam_thr.raise(Stop) @cam_thr.join @cam_thr = nil end