zbar-windows/iphone/ZBarReaderViewImpl_Capture.m
Mauro Carvalho Chehab cd5b63e5b5 Update to the very latest version of zbar
zbar was using a 2010 snapshot of its hg tree.
Take a new snapshot to get zbar's improvements.

[Imported from Fedora 26 tree]
2017-03-25 23:04:38 -03:00

403 lines
11 KiB
Objective-C

//------------------------------------------------------------------------
// Copyright 2010 (c) Jeff Brown <spadix@users.sourceforge.net>
//
// This file is part of the ZBar Bar Code Reader.
//
// The ZBar Bar Code Reader is free software; you can redistribute it
// and/or modify it under the terms of the GNU Lesser Public License as
// published by the Free Software Foundation; either version 2.1 of
// the License, or (at your option) any later version.
//
// The ZBar Bar Code Reader is distributed in the hope that it will be
// useful, but WITHOUT ANY WARRANTY; without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser Public License for more details.
//
// You should have received a copy of the GNU Lesser Public License
// along with the ZBar Bar Code Reader; if not, write to the Free
// Software Foundation, Inc., 51 Franklin St, Fifth Floor,
// Boston, MA 02110-1301 USA
//
// http://sourceforge.net/projects/zbar
//------------------------------------------------------------------------
#import <AVFoundation/AVFoundation.h>
#import <CoreMedia/CoreMedia.h>
#import <CoreVideo/CoreVideo.h>
#import <ZBarSDK/ZBarReaderView.h>
#import <ZBarSDK/ZBarCaptureReader.h>
#define MODULE ZBarReaderView
#import "debug.h"
// protected APIs
@interface ZBarReaderView()
- (void) _initWithImageScanner: (ZBarImageScanner*) _scanner;
- (void) initSubviews;
- (void) updateCrop;
- (void) setImageSize: (CGSize) size;
- (void) didTrackSymbols: (ZBarSymbolSet*) syms;
@end
@interface ZBarReaderViewImpl
: ZBarReaderView
{
AVCaptureSession *session;
AVCaptureDevice *device;
AVCaptureInput *input;
}
@end
@implementation ZBarReaderViewImpl
@synthesize device, session;
- (void) _initWithImageScanner: (ZBarImageScanner*) scanner
{
[super _initWithImageScanner: scanner];
session = [AVCaptureSession new];
NSNotificationCenter *notify =
[NSNotificationCenter defaultCenter];
[notify addObserver: self
selector: @selector(onVideoError:)
name: AVCaptureSessionRuntimeErrorNotification
object: session];
[notify addObserver: self
selector: @selector(onVideoStart:)
name: AVCaptureSessionDidStartRunningNotification
object: session];
[notify addObserver: self
selector: @selector(onVideoStop:)
name: AVCaptureSessionDidStopRunningNotification
object: session];
[notify addObserver: self
selector: @selector(onVideoStop:)
name: AVCaptureSessionWasInterruptedNotification
object: session];
[notify addObserver: self
selector: @selector(onVideoStart:)
name: AVCaptureSessionInterruptionEndedNotification
object: session];
self.device = [AVCaptureDevice
defaultDeviceWithMediaType: AVMediaTypeVideo];
captureReader = [[ZBarCaptureReader alloc]
initWithImageScanner: scanner];
captureReader.captureDelegate = (id<ZBarCaptureDelegate>)self;
[session addOutput: captureReader.captureOutput];
if([session canSetSessionPreset: AVCaptureSessionPreset640x480])
session.sessionPreset = AVCaptureSessionPreset640x480;
[captureReader addObserver: self
forKeyPath: @"size"
options: 0
context: NULL];
[self initSubviews];
}
- (void) initSubviews
{
AVCaptureVideoPreviewLayer *videoPreview =
[[AVCaptureVideoPreviewLayer
layerWithSession: session]
retain];
preview = videoPreview;
CGRect bounds = self.bounds;
bounds.origin = CGPointZero;
preview.bounds = bounds;
preview.position = CGPointMake(bounds.size.width / 2,
bounds.size.height / 2);
videoPreview.videoGravity = AVLayerVideoGravityResizeAspectFill;
[self.layer addSublayer: preview];
[super initSubviews];
}
- (void) dealloc
{
[[NSNotificationCenter defaultCenter]
removeObserver: self];
if(showsFPS) {
@try {
[captureReader removeObserver: self
forKeyPath: @"framesPerSecond"];
}
@catch(...) { }
}
@try {
[captureReader removeObserver: self
forKeyPath: @"size"];
}
@catch(...) { }
captureReader.captureDelegate = nil;
[captureReader release];
captureReader = nil;
[device release];
device = nil;
[input release];
input = nil;
[session release];
session = nil;
[super dealloc];
}
- (void) updateCrop
{
[super updateCrop];
captureReader.scanCrop = effectiveCrop;
}
- (ZBarImageScanner*) scanner
{
return(captureReader.scanner);
}
- (void) setDevice: (AVCaptureDevice*) newdev
{
id olddev = device;
AVCaptureInput *oldinput = input;
assert(!olddev == !oldinput);
NSError *error = nil;
device = [newdev retain];
if(device) {
assert([device hasMediaType: AVMediaTypeVideo]);
input = [[AVCaptureDeviceInput alloc]
initWithDevice: newdev
error: &error];
assert(input);
}
else
input = nil;
[session beginConfiguration];
if(oldinput)
[session removeInput: oldinput];
if(input)
[session addInput: input];
[session commitConfiguration];
[olddev release];
[oldinput release];
}
- (BOOL) enableCache
{
return(captureReader.enableCache);
}
- (void) setEnableCache: (BOOL) enable
{
captureReader.enableCache = enable;
}
- (void) setTorchMode: (NSInteger) mode
{
[super setTorchMode: mode];
if(running && [device isTorchModeSupported: mode])
@try {
device.torchMode = mode;
}
@catch(...) { }
}
- (void) setShowsFPS: (BOOL) show
{
[super setShowsFPS: show];
@try {
if(show)
[captureReader addObserver: self
forKeyPath: @"framesPerSecond"
options: 0
context: NULL];
else
[captureReader removeObserver: self
forKeyPath: @"framesPerSecond"];
}
@catch(...) { }
}
- (void) start
{
if(started)
return;
[super start];
[session startRunning];
captureReader.enableReader = YES;
}
- (void) stop
{
if(!started)
return;
[super stop];
captureReader.enableReader = NO;
[session stopRunning];
}
- (void) flushCache
{
[captureReader flushCache];
}
- (void) configureDevice
{
if([device isFocusModeSupported: AVCaptureFocusModeContinuousAutoFocus])
device.focusMode = AVCaptureFocusModeContinuousAutoFocus;
if([device isTorchModeSupported: torchMode])
device.torchMode = torchMode;
}
- (void) lockDevice
{
if(!running || locked) {
assert(0);
return;
}
// lock device and set focus mode
NSError *error = nil;
if([device lockForConfiguration: &error]) {
locked = YES;
[self configureDevice];
}
else {
zlog(@"failed to lock device: %@", error);
// just keep trying
[self performSelector: @selector(lockDevice)
withObject: nil
afterDelay: .5];
}
}
// AVCaptureSession notifications
- (void) onVideoStart: (NSNotification*) note
{
zlog(@"onVideoStart: running=%d %@", running, note);
if(running)
return;
running = YES;
locked = NO;
[self lockDevice];
if([readerDelegate respondsToSelector: @selector(readerViewDidStart:)])
[readerDelegate readerViewDidStart: self];
}
- (void) onVideoStop: (NSNotification*) note
{
zlog(@"onVideoStop: %@", note);
if(!running)
return;
running = NO;
if(locked)
[device unlockForConfiguration];
else
[NSObject cancelPreviousPerformRequestsWithTarget: self
selector: @selector(lockDevice)
object: nil];
locked = NO;
if([readerDelegate respondsToSelector:
@selector(readerView:didStopWithError:)])
[readerDelegate readerView: self
didStopWithError: nil];
}
- (void) onVideoError: (NSNotification*) note
{
zlog(@"onVideoError: %@", note);
if(running) {
// FIXME does session always stop on error?
running = started = NO;
[device unlockForConfiguration];
}
NSError *err =
[note.userInfo objectForKey: AVCaptureSessionErrorKey];
if([readerDelegate respondsToSelector:
@selector(readerView:didStopWithError:)])
[readerDelegate readerView: self
didStopWithError: err];
else
NSLog(@"ZBarReaderView: ERROR during capture: %@: %@",
[err localizedDescription],
[err localizedFailureReason]);
}
// NSKeyValueObserving
- (void) observeValueForKeyPath: (NSString*) path
ofObject: (id) obj
change: (NSDictionary*) info
context: (void*) ctx
{
if(obj == captureReader &&
[path isEqualToString: @"size"])
// adjust preview to match image size
[self setImageSize: captureReader.size];
else if(obj == captureReader &&
[path isEqualToString: @"framesPerSecond"])
fpsLabel.text = [NSString stringWithFormat: @"%.2ffps ",
captureReader.framesPerSecond];
}
// ZBarCaptureDelegate
- (void) captureReader: (ZBarCaptureReader*) reader
didTrackSymbols: (ZBarSymbolSet*) syms
{
[self didTrackSymbols: syms];
}
- (void) captureReader: (ZBarCaptureReader*) reader
didReadNewSymbolsFromImage: (ZBarImage*) zimg
{
zlog(@"scanned %d symbols: %@", zimg.symbols.count, zimg);
if(!readerDelegate)
return;
UIImageOrientation orient = [UIDevice currentDevice].orientation;
if(!UIDeviceOrientationIsValidInterfaceOrientation(orient)) {
orient = interfaceOrientation;
if(orient == UIInterfaceOrientationLandscapeLeft)
orient = UIDeviceOrientationLandscapeLeft;
else if(orient == UIInterfaceOrientationLandscapeRight)
orient = UIDeviceOrientationLandscapeRight;
}
switch(orient)
{
case UIDeviceOrientationPortraitUpsideDown:
orient = UIImageOrientationLeft;
break;
case UIDeviceOrientationLandscapeLeft:
orient = UIImageOrientationUp;
break;
case UIDeviceOrientationLandscapeRight:
orient = UIImageOrientationDown;
break;
default:
orient = UIImageOrientationRight;
break;
}
UIImage *uiimg = [zimg UIImageWithOrientation: orient];
[readerDelegate
readerView: self
didReadSymbols: zimg.symbols
fromImage: uiimg];
}
@end