class Motion::Capture
Constants
- CAMERA_POSITIONS
- FLASH_MODES
Attributes
device[R]
options[R]
preview_layer[R]
Public Class Methods
new(options = {})
click to toggle source
# File lib/project/motion-capture.rb, line 7 def initialize(options = {}) @options = options end
Public Instance Methods
attach(view, options = {})
click to toggle source
# File lib/project/motion-capture.rb, line 181 def attach(view, options = {}) @preview_layer = preview_layer_for_view(view, options) view.layer.addSublayer(preview_layer) end
can_set_preset?(preset)
click to toggle source
# File lib/project/motion-capture.rb, line 213 def can_set_preset?(preset) session.canSetSessionPreset(preset) end
capture(&block)
click to toggle source
# File lib/project/motion-capture.rb, line 76 def capture(&block) if defined?(AVCapturePhotoOutput) # iOS 10+ Dispatch::Queue.new('motion-capture').async do ensure_running_session do update_video_orientation! @capture_callback = block capture_settings = AVCapturePhotoSettings.photoSettingsWithFormat(AVVideoCodecKey => AVVideoCodecJPEG) photo_output.capturePhotoWithSettings(capture_settings, delegate: self) end end else # iOS 4-9 still_image_output.captureStillImageAsynchronouslyFromConnection(still_image_connection, completionHandler: -> (buffer, error) { if error error_callback.call(error) else image_data = AVCaptureStillImageOutput.jpegStillImageNSDataRepresentation(buffer) block.call(image_data) end }) end end
captureOutput(output, didFinishProcessingPhoto: photo, error: error)
click to toggle source
iOS 11+ AVCapturePhotoCaptureDelegate method
# File lib/project/motion-capture.rb, line 107 def captureOutput(output, didFinishProcessingPhoto: photo, error: error) if error error_callback.call(error) else @capture_callback.call(photo.fileDataRepresentation) end end
capture_and_save(&block)
click to toggle source
# File lib/project/motion-capture.rb, line 135 def capture_and_save(&block) capture do |jpeg_data| save_data(jpeg_data) do |asset_url| block.call(jpeg_data, asset_url) end end end
capture_image(&block)
click to toggle source
# File lib/project/motion-capture.rb, line 128 def capture_image(&block) capture do |jpeg_data| image = UIImage.imageWithData(jpeg_data) block.call(image) end end
capture_image_and_save(&block)
click to toggle source
# File lib/project/motion-capture.rb, line 143 def capture_image_and_save(&block) capture do |jpeg_data| save_data(jpeg_data) do |asset_url| image = UIImage.imageWithData(jpeg_data) block.call(image, asset_url) end end end
configure_session()
click to toggle source
# File lib/project/motion-capture.rb, line 42 def configure_session session.beginConfiguration set_preset(options.fetch(:preset, AVCaptureSessionPresetPhoto)) use_camera(options.fetch(:device, :default)) if defined?(AVCapturePhotoOutput) # iOS 10+ add_output(photo_output) else # iOS 4-9 add_output(still_image_output) end session.commitConfiguration end
ensure_running_session(&block)
click to toggle source
# File lib/project/motion-capture.rb, line 98 def ensure_running_session(&block) start! unless @starting || session.running? while @starting || !session.running? # wait for session to start... end block.call end
flash()
click to toggle source
# File lib/project/motion-capture.rb, line 225 def flash device.flashMode if @device end
flash_mode_available?(mode)
click to toggle source
# File lib/project/motion-capture.rb, line 234 def flash_mode_available?(mode) FLASH_MODES.keys.include?(mode) && device.isFlashModeSupported(FLASH_MODES[mode]) end
on_error(&block)
click to toggle source
# File lib/project/motion-capture.rb, line 11 def on_error(&block) @error_callback = block end
preset()
click to toggle source
# File lib/project/motion-capture.rb, line 221 def preset session.sessionPreset if @session end
running?()
click to toggle source
# File lib/project/motion-capture.rb, line 58 def running? @session && session.running? end
save_data(jpeg_data, &block)
click to toggle source
# File lib/project/motion-capture.rb, line 152 def save_data(jpeg_data, &block) if defined?(PHPhotoLibrary) # iOS 8+ save_to_photo_library(jpeg_data, &block) else # iOS 4-8 save_to_assets_library(jpeg_data, &block) end end
save_to_assets_library(jpeg_data, &block)
click to toggle source
iOS 4-8
# File lib/project/motion-capture.rb, line 161 def save_to_assets_library(jpeg_data, &block) assets_library.writeImageDataToSavedPhotosAlbum(jpeg_data, metadata: nil, completionBlock: -> (asset_url, error) { error ? error_callback.call(error) : block.call(asset_url) }) end
save_to_photo_library(jpeg_data, &block)
click to toggle source
iOS 8+
# File lib/project/motion-capture.rb, line 168 def save_to_photo_library(jpeg_data, &block) photo_library.performChanges(-> { image = UIImage.imageWithData(jpeg_data) PHAssetChangeRequest.creationRequestForAssetFromImage(image) }, completionHandler: -> (success, error) { if error error_callback.call(error) else block.call(nil) # asset url is not returned in completion block end }) end
set_flash(mode = :auto)
click to toggle source
iOS 4-9
# File lib/project/motion-capture.rb, line 230 def set_flash(mode = :auto) configure_with_lock { device.flashMode = FLASH_MODES[mode] } if flash_mode_available?(mode) end
set_preset(preset)
click to toggle source
# File lib/project/motion-capture.rb, line 217 def set_preset(preset) session.sessionPreset = preset if can_set_preset? preset end
start!()
click to toggle source
# File lib/project/motion-capture.rb, line 15 def start! return if session.running? if defined?(AVCapturePhotoOutput) # iOS 10+ @starting = true authorize_camera do |success| if success Dispatch::Queue.new('motion-capture').async do configure_session session.startRunning @starting = false end else @starting = false end end else # iOS 4-9 configure_session session.startRunning end end
stop!()
click to toggle source
# File lib/project/motion-capture.rb, line 62 def stop! session.stopRunning remove_outputs remove_inputs preview_layer.removeFromSuperlayer if preview_layer && preview_layer.superlayer @still_image_output = nil @photo_output = nil @session = nil @preview_layer = nil end
toggle_camera()
click to toggle source
# File lib/project/motion-capture.rb, line 199 def toggle_camera target_camera = using_rear_camera? ? :front : :rear use_camera(target_camera) end
toggle_flash()
click to toggle source
# File lib/project/motion-capture.rb, line 205 def toggle_flash if device && device.hasFlash target_mode = flash_on? ? :off : :on set_flash(target_mode) end end
use_camera(target_camera = :default)
click to toggle source
# File lib/project/motion-capture.rb, line 187 def use_camera(target_camera = :default) @device = camera_devices[target_camera] error_pointer = Pointer.new(:object) if input = AVCaptureDeviceInput.deviceInputWithDevice(device, error: error_pointer) set_input(input) else error_callback.call(error_pointer[0]) end end
Private Instance Methods
add_input(input)
click to toggle source
# File lib/project/motion-capture.rb, line 325 def add_input(input) session.addInput(input) if session.canAddInput(input) end
add_output(output)
click to toggle source
# File lib/project/motion-capture.rb, line 329 def add_output(output) session.addOutput(output) if session.canAddOutput(output) end
assets_library()
click to toggle source
iOS 4-8
# File lib/project/motion-capture.rb, line 272 def assets_library @assets_library ||= ALAssetsLibrary.alloc.init end
camera_devices()
click to toggle source
# File lib/project/motion-capture.rb, line 349 def camera_devices { default: default_camera, rear: rear_camera, front: front_camera } end
capture_devices()
click to toggle source
# File lib/project/motion-capture.rb, line 353 def capture_devices @capture_devices ||= AVCaptureDevice.devicesWithMediaType(AVMediaTypeVideo) end
configure_with_lock(&block)
click to toggle source
# File lib/project/motion-capture.rb, line 281 def configure_with_lock(&block) error_pointer = Pointer.new(:object) if device.lockForConfiguration(error_pointer) block.call device.unlockForConfiguration else error_callback.call(error_pointer[0]) end end
default_camera()
click to toggle source
# File lib/project/motion-capture.rb, line 333 def default_camera AVCaptureDevice.defaultDeviceWithMediaType(AVMediaTypeVideo) end
error_callback()
click to toggle source
# File lib/project/motion-capture.rb, line 240 def error_callback @error_callback ||= -> (error) { p "An error occurred: #{error.localizedDescription}." } end
flash_on?()
click to toggle source
# File lib/project/motion-capture.rb, line 368 def flash_on? device ? [FLASH_MODES[:on], FLASH_MODES[:auto]].include?(device.flashMode) : false end
front_camera()
click to toggle source
# File lib/project/motion-capture.rb, line 341 def front_camera capture_devices.select { |device| device.position == CAMERA_POSITIONS[:front] }.first end
orientation_mapping()
click to toggle source
# File lib/project/motion-capture.rb, line 264 def orientation_mapping { UIDeviceOrientationPortrait => AVCaptureVideoOrientationPortrait, UIDeviceOrientationPortraitUpsideDown => AVCaptureVideoOrientationPortraitUpsideDown, UIDeviceOrientationLandscapeRight => AVCaptureVideoOrientationLandscapeLeft, UIDeviceOrientationLandscapeLeft => AVCaptureVideoOrientationLandscapeRight } end
photo_library()
click to toggle source
iOS 8+
# File lib/project/motion-capture.rb, line 277 def photo_library @photo_library ||= PHPhotoLibrary.sharedPhotoLibrary end
photo_output()
click to toggle source
iOS 10+
# File lib/project/motion-capture.rb, line 385 def photo_output @photo_output ||= AVCapturePhotoOutput.alloc.init end
preview_layer_for_view(view, options = {})
click to toggle source
# File lib/project/motion-capture.rb, line 357 def preview_layer_for_view(view, options = {}) AVCaptureVideoPreviewLayer.layerWithSession(session).tap do |layer| layer_bounds = view.layer.bounds layer.bounds = layer_bounds layer.position = CGPointMake(CGRectGetMidX(layer_bounds), CGRectGetMidY(layer_bounds)) layer.zPosition = options.fetch(:z_position, -100) layer.videoGravity = options.fetch(:video_gravity, AVLayerVideoGravityResizeAspectFill) end end
rear_camera()
click to toggle source
# File lib/project/motion-capture.rb, line 337 def rear_camera capture_devices.select { |device| device.position == CAMERA_POSITIONS[:rear] }.first end
remove_input(input)
click to toggle source
# File lib/project/motion-capture.rb, line 317 def remove_input(input) session.removeInput(input) end
remove_inputs()
click to toggle source
# File lib/project/motion-capture.rb, line 305 def remove_inputs session.inputs.each do |input| remove_input(input) end end
remove_output(output)
click to toggle source
# File lib/project/motion-capture.rb, line 321 def remove_output(output) session.removeOutput(output) end
remove_outputs()
click to toggle source
# File lib/project/motion-capture.rb, line 311 def remove_outputs session.outputs.each do |output| remove_output(output) end end
session()
click to toggle source
# File lib/project/motion-capture.rb, line 372 def session @session ||= AVCaptureSession.alloc.init end
set_input(input)
click to toggle source
# File lib/project/motion-capture.rb, line 293 def set_input(input) remove_inputs add_input(input) end
set_output(output)
click to toggle source
# File lib/project/motion-capture.rb, line 299 def set_output(output) remove_outputs add_output(output) end
still_image_connection()
click to toggle source
iOS 4-9
# File lib/project/motion-capture.rb, line 245 def still_image_connection still_image_output.connectionWithMediaType(AVMediaTypeVideo).tap do |connection| device_orientation = UIDevice.currentDevice.orientation video_orientation = orientation_mapping.fetch(device_orientation, AVCaptureVideoOrientationPortrait) connection.setVideoOrientation(video_orientation) if connection.videoOrientationSupported? end end
still_image_output()
click to toggle source
iOS 4-9
# File lib/project/motion-capture.rb, line 377 def still_image_output @still_image_output ||= AVCaptureStillImageOutput.alloc.init.tap do |output| settings = { 'AVVideoCodecKey' => AVVideoCodecJPEG } output.setOutputSettings(settings) end end
update_video_orientation!()
click to toggle source
iOS 10+
# File lib/project/motion-capture.rb, line 255 def update_video_orientation! photo_output.connectionWithMediaType(AVMediaTypeVideo).tap do |connection| device_orientation = UIDevice.currentDevice.orientation video_orientation = orientation_mapping.fetch(device_orientation, AVCaptureVideoOrientationPortrait) connection.setVideoOrientation(video_orientation) if connection.videoOrientationSupported? end end
using_rear_camera?()
click to toggle source
# File lib/project/motion-capture.rb, line 345 def using_rear_camera? device ? device.position == CAMERA_POSITIONS[:rear] : false end