2013-03-16 22 views
15

Kamera aracılığıyla video çekmek için doğrudan AVFoundation kullandığım bir iphone uygulaması geliştiriyorum.AVFoundation geribesleme dikdörtgeni odaklanmak için dokunun

Bir kullanıcı için tap to focus işlevini etkinleştirmek üzere bir özellik geliştirdim.

- (void) focus:(CGPoint) aPoint; 
{ 
#if HAS_AVFF 
    Class captureDeviceClass = NSClassFromString(@"AVCaptureDevice"); 
    if (captureDeviceClass != nil) {   
     AVCaptureDevice *device = [captureDeviceClass defaultDeviceWithMediaType:AVMediaTypeVideo]; 
     if([device isFocusPointOfInterestSupported] && 
      [device isFocusModeSupported:AVCaptureFocusModeAutoFocus]) { 
      CGRect screenRect = [[UIScreen mainScreen] bounds]; 
      double screenWidth = screenRect.size.width; 
      double screenHeight = screenRect.size.height; 
      double focus_x = aPoint.x/screenWidth; 
      double focus_y = aPoint.y/screenHeight; 
      if([device lockForConfiguration:nil]) { 
       [device setFocusPointOfInterest:CGPointMake(focus_x,focus_y)]; 
       [device setFocusMode:AVCaptureFocusModeAutoFocus]; 
       if ([device isExposureModeSupported:AVCaptureExposureModeAutoExpose]){ 
        [device setExposureMode:AVCaptureExposureModeAutoExpose]; 
       } 
       [device unlockForConfiguration]; 
      } 
     } 
    } 
#endif 
} 

Şimdiye kadar çok iyi, ancak fotoğraf uygulamasında olduğu gibi geri bildirim dikdörtgeni eksik. AVFoundation Framework'e bu geri bildirim dikdörtgeni gösterme ya da bu özelliği kendim uygulamak zorunda mıyım?

+1

İlgisiz sorununuza ancak, eğer 'kullanılarak yapılmalıdır (CaptureDeviceClass! = Nil) –

+0

İpucu için teşekkürler. Farkları çok önemsemedim ve şimdi fark ettim, o yüzden baktım. Bir sınıfa başvurduğumdan dolayı kesinlikle haklısın. – Alexander

+0

@Alexander, seninkiyle aynı problemle karşı karşıyayım. Bu sorunu çözdünüz mü? – ttotto

cevap

34

Yaptığım şey: Kullanıcı, kamera yerleşimi üzerine dokunduğunda gösterilen kareyi oluşturan sınıftır.

CameraFocusSquare.h 

#import <UIKit/UIKit.h> 
@interface CameraFocusSquare : UIView 
@end 


CameraFocusSquare.m 

#import "CameraFocusSquare.h" 
#import <QuartzCore/QuartzCore.h> 

const float squareLength = 80.0f; 
@implementation FBKCameraFocusSquare 

- (id)initWithFrame:(CGRect)frame 
{ 
    self = [super initWithFrame:frame]; 
    if (self) { 
     // Initialization code 

     [self setBackgroundColor:[UIColor clearColor]]; 
     [self.layer setBorderWidth:2.0]; 
     [self.layer setCornerRadius:4.0]; 
     [self.layer setBorderColor:[UIColor whiteColor].CGColor]; 

     CABasicAnimation* selectionAnimation = [CABasicAnimation 
               animationWithKeyPath:@"borderColor"]; 
     selectionAnimation.toValue = (id)[UIColor blueColor].CGColor; 
     selectionAnimation.repeatCount = 8; 
     [self.layer addAnimation:selectionAnimation 
          forKey:@"selectionAnimation"]; 

    } 
    return self; 
} 
@end 

Ve siz musluklar almak görünümünde

, aşağıdakileri yapın:

- (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event 
{ 
    UITouch *touch = [[event allTouches] anyObject]; 
    CGPoint touchPoint = [touch locationInView:touch.view]; 
    [self focus:touchPoint]; 

    if (camFocus) 
    { 
     [camFocus removeFromSuperview]; 
    } 
    if ([[touch view] isKindOfClass:[FBKVideoRecorderView class]]) 
    { 
     camFocus = [[CameraFocusSquare alloc]initWithFrame:CGRectMake(touchPoint.x-40, touchPoint.y-40, 80, 80)]; 
     [camFocus setBackgroundColor:[UIColor clearColor]]; 
     [self addSubview:camFocus]; 
     [camFocus setNeedsDisplay]; 

     [UIView beginAnimations:nil context:NULL]; 
     [UIView setAnimationDuration:1.5]; 
     [camFocus setAlpha:0.0]; 
     [UIView commitAnimations]; 
    } 
} 

- (void) focus:(CGPoint) aPoint; 
{ 
    Class captureDeviceClass = NSClassFromString(@"AVCaptureDevice"); 
    if (captureDeviceClass != nil) { 
     AVCaptureDevice *device = [captureDeviceClass defaultDeviceWithMediaType:AVMediaTypeVideo]; 
     if([device isFocusPointOfInterestSupported] && 
      [device isFocusModeSupported:AVCaptureFocusModeAutoFocus]) { 
      CGRect screenRect = [[UIScreen mainScreen] bounds]; 
      double screenWidth = screenRect.size.width; 
      double screenHeight = screenRect.size.height; 
      double focus_x = aPoint.x/screenWidth; 
      double focus_y = aPoint.y/screenHeight; 
      if([device lockForConfiguration:nil]) { 
       [device setFocusPointOfInterest:CGPointMake(focus_x,focus_y)]; 
       [device setFocusMode:AVCaptureFocusModeAutoFocus]; 
       if ([device isExposureModeSupported:AVCaptureExposureModeAutoExpose]){ 
        [device setExposureMode:AVCaptureExposureModeAutoExpose]; 
       } 
       [device unlockForConfiguration]; 
      } 
     } 
    } 
} 
+0

numaralı çözümde kodda "camFocus" ifadesinin bulunmadığını tespit ettim. – iqueqiorio

+0

@iqueqiorio camFocus, özel sınıf (kodun ilk kod parçası) olan CameraFocusSquare türünde bir değişkendir. – Anil

+0

Tamam, bunu nasıl açıklarım, 'KameraFocusSquare'i deniyorum * camFocus = [[CameraFocusSquare alloc] init]; 'ama bu bana bir hata veriyor? – iqueqiorio

11

Anil adlı parlak cevabı ekleme: Yerine hesaplamalar kendiniz yaparak, size bir göz sahip olmalıdır AVCaptureVideoPreviewLayercaptureDevicePointOfInterestForPoint:. Size çok daha tutarlı bir odak noktası (iOS 6'dan itibaren ve ileride) verilecektir. https://developer.apple.com/library/ios/documentation/AVFoundation/Reference/AVCaptureVideoPreviewLayer_Class/index.html#//apple_ref/occ/instm/AVCaptureVideoPreviewLayer/captureDevicePointOfInterestForPoint: Anil adlı cevabı @

6

harika bir başlangıç ​​olduğunu, ama benim için işe yaramadı

- (void) focus:(CGPoint) aPoint; 
{ 
    Class captureDeviceClass = NSClassFromString(@"AVCaptureDevice"); 
    if (captureDeviceClass != nil) { 
     AVCaptureDevice *device = [captureDeviceClass defaultDeviceWithMediaType:AVMediaTypeVideo]; 
     if([device isFocusPointOfInterestSupported] && 
      [device isFocusModeSupported:AVCaptureFocusModeAutoFocus]) { 

      CGPoint focusPoint = [self.captureVideoPreviewLayer captureDevicePointOfInterestForPoint:aPoint]; 
      if([device lockForConfiguration:nil]) { 
       [device setFocusPointOfInterest:CGPointMake(focusPoint.x,focusPoint.y)]; 
       [device setFocusMode:AVCaptureFocusModeAutoFocus]; 
       if ([device isExposureModeSupported:AVCaptureExposureModeAutoExpose]){ 
        [device setExposureMode:AVCaptureExposureModeAutoExpose]; 
       } 
       [device unlockForConfiguration]; 
      } 
     } 
    } 
} 

belgelerine buradan ulaşabilirsiniz. Kullanıcının sadece bir kez değil, bir odak noktası seçmeye devam edebilmesini sağlamak istedim (çözümünün yaptığı). Beni doğru yönde işaret ettiğin için @Anil'e teşekkürler.

Çözümümde bazı farklılıklar var.

  1. Odak karesini ve animasyonu yalnızca tek bir zaman yerine yeniden kullanabilmeyi istedim. o (Yapmak Anil adlı çözümü @ alamadım şey tamamlamasından sonra
  2. kaybolan ben animasyon istedi.
  3. yerine initWithFrame: kullanmak yerine, ben hayata benimkinin initWithTouchPoint:.
  4. Özellikle animasyon için bir yöntem var odak eylem.
  5. Ben de çerçevenin konumunu güncellemek için bir yöntem var.
  6. çerçevenin boyutu bulmak ve gerektiğinde büyüklüğünü değiştirmek için daha kolay, yani CameraFocusSquare içindedir.

CameraFocusSquare.h

@import UIKit; 

@interface CameraFocusSquare : UIView 

- (instancetype)initWithTouchPoint:(CGPoint)touchPoint; 
- (void)updatePoint:(CGPoint)touchPoint; 
- (void)animateFocusingAction; 

@end 

CameraFocusSquare.m

#import "CameraFocusSquare.h" 

@implementation CameraFocusSquare { 
    CABasicAnimation *_selectionBlink; 
} 

/** 
This is the init method for the square. It sets the frame for the view and sets border parameters. It also creates the blink animation. 
*/ 
- (instancetype)initWithTouchPoint:(CGPoint)touchPoint { 
    self = [self init]; 
    if (self) { 
     [self updatePoint:touchPoint]; 
     self.backgroundColor = [UIColor clearColor]; 
     self.layer.borderWidth = 2.0f; 
     self.layer.borderColor = [UIColor orangeColor].CGColor; 

     // create the blink animation 
     _selectionBlink = [CABasicAnimation 
       animationWithKeyPath:@"borderColor"]; 
     _selectionBlink.toValue = (id)[UIColor whiteColor].CGColor; 
     _selectionBlink.repeatCount = 3; // number of blinks 
     _selectionBlink.duration = 0.4; // this is duration per blink 
     _selectionBlink.delegate = self; 
    } 
    return self; 
} 

/** 
Updates the location of the view based on the incoming touchPoint. 
*/ 
- (void)updatePoint:(CGPoint)touchPoint { 
    CGFloat squareWidth = 50; 
    CGRect frame = CGRectMake(touchPoint.x - squareWidth/2, touchPoint.y - squareWidth/2, squareWidth, squareWidth); 
    self.frame = frame; 
} 

/** 
This unhides the view and initiates the animation by adding it to the layer. 
*/ 
- (void)animateFocusingAction { 
    // make the view visible 
    self.alpha = 1.0f; 
    self.hidden = NO; 
    // initiate the animation 
    [self.layer addAnimation:_selectionBlink forKey:@"selectionAnimation"]; 
} 

/** 
Hides the view after the animation stops. Since the animation is automatically removed, we don't need to do anything else here. 
*/ 
- (void)animationDidStop:(CAAnimation *)animation finished:(BOOL)flag { 
    // hide the view 
    self.alpha = 0.0f; 
    self.hidden = YES; 
} 

@end 

Ben bir görünüm üstünde Tüm bu başlatmak. Bu bana daha fazla esneklik sağlar ve UI kodumu denetleyici kodumdan ayırır (MVC'yi düşünün).

PreviewView.h

@import UIKit; 

@interface PreviewView : UIView 

- (IBAction)tapToFocus:(UITapGestureRecognizer *)gestureRecognizer; 

@end 

PreviewView.m

#import "PreviewView.h" 
#import "CameraFocusSquare.h" 

@implementation PreviewView { 
    CameraFocusSquare *_focusSquare; 
} 

- (IBAction)tapToFocus:(UITapGestureRecognizer *)gestureRecognizer { 
    CGPoint touchPoint = [gestureRecognizer locationOfTouch:0 inView:self]; 
    if (!_focusSquare) { 
     _focusSquare = [[CameraFocusSquare alloc] initWithTouchPoint:touchPoint]; 
     [self addSubview:_focusSquare]; 
     [_focusSquare setNeedsDisplay]; 
    } 
    else { 
     [_focusSquare updatePoint:touchPoint]; 
    } 
    [_focusSquare animateFocusingAction]; 
} 

@end 

Son olarak, benim UIViewController alt sınıfta, ben benim UITapGestureRecognizer oluşturulan ve görünümüne bağlı. Ayrıca, dokunarak odaklama kodumu da uygularım. onlar daha önemli kod üzerine hareket böylece

CameraViewController.m

- (void)viewDidLoad { 
    // do other initialization stuff here 

    // create the tap-to-focus gesture 
    UITapGestureRecognizer *tapToFocusRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapToFocus:)]; 
    tapToFocusRecognizer.numberOfTapsRequired = 1; 
    tapToFocusRecognizer.numberOfTouchesRequired = 1; 
    [self.previewView addGestureRecognizer:tapToFocusRecognizer]; 
} 

- (IBAction)tapToFocus:(UITapGestureRecognizer *)tapGestureRecognizer { 
    if (!_captureDevice) { 
     return; 
    } 
    if (![_captureDevice isFocusPointOfInterestSupported]) { 
     return; 
    } 
    if (![_captureDevice isFocusModeSupported:AVCaptureFocusModeAutoFocus]) { 
     return; 
    } 
    [self.previewView tapToFocus:tapGestureRecognizer]; 
    NSError *error; 
    [_captureDevice lockForConfiguration:&error]; 
    if (error) { 
     NSLog(@"Error trying to lock configuration of camera. %@", [error localizedDescription]); 
     return; 
    } 
    CGPoint touchPoint = [tapGestureRecognizer locationOfTouch:0 inView:self.cameraView]; 
    // range of touch point is from (0,0) to (1,1) 
    CGFloat touchX = touchPoint.x/self.previewView.frame.size.width; 
    CGFloat touchY = touchPoint.y/self.previewView.frame.size.height; 

    _captureDevice.focusMode = AVCaptureFocusModeAutoFocus; 
    if ([_captureDevice isExposureModeSupported:AVCaptureExposureModeAutoExpose]) { 
     _captureDevice.exposureMode = AVCaptureExposureModeAutoExpose; 
    } 
    _captureDevice.focusPointOfInterest = CGPointMake(touchX, touchY); 
    if ([_captureDevice isExposurePointOfInterestSupported]) { 
     _captureDevice.exposurePointOfInterest = CGPointMake(touchX, touchY); 
    } 
    [_captureDevice unlockForConfiguration]; 
} 

Umut bu insanlara yardım!

6

Swift uygulanması:

CameraFocusSquare görünümü:

class CameraFocusSquare: UIView,CAAnimationDelegate { 

internal let kSelectionAnimation:String = "selectionAnimation" 

fileprivate var _selectionBlink: CABasicAnimation? 

convenience init(touchPoint: CGPoint) { 
    self.init() 
    self.updatePoint(touchPoint) 
    self.backgroundColor = UIColor.clear 
    self.layer.borderWidth = 2.0 
    self.layer.borderColor = UIColor.orange.cgColor 
    initBlink() 
} 

override init(frame: CGRect) { 
    super.init(frame: frame) 
} 

fileprivate func initBlink() { 
    // create the blink animation 
    self._selectionBlink = CABasicAnimation(keyPath: "borderColor") 
    self._selectionBlink!.toValue = (UIColor.white.cgColor as AnyObject) 
    self._selectionBlink!.repeatCount = 3 
    // number of blinks 
    self._selectionBlink!.duration = 0.4 
    // this is duration per blink 
    self._selectionBlink!.delegate = self 
} 



required init?(coder aDecoder: NSCoder) { 
    fatalError("init(coder:) has not been implemented") 
} 

/** 
Updates the location of the view based on the incoming touchPoint. 
*/ 

func updatePoint(_ touchPoint: CGPoint) { 
    let squareWidth: CGFloat = 100 
    let frame: CGRect = CGRect(x: touchPoint.x - squareWidth/2, y: touchPoint.y - squareWidth/2, width: squareWidth, height: squareWidth) 
    self.frame = frame 
} 
/** 
This unhides the view and initiates the animation by adding it to the layer. 
*/ 

func animateFocusingAction() { 

    if let blink = _selectionBlink { 
     // make the view visible 
     self.alpha = 1.0 
     self.isHidden = false 
     // initiate the animation 
     self.layer.add(blink, forKey: kSelectionAnimation) 
    } 

} 
/** 
Hides the view after the animation stops. Since the animation is automatically removed, we don't need to do anything else here. 
*/ 

public func animationDidStop(_ anim: CAAnimation, finished flag: Bool){ 
    if flag{ 
     // hide the view 
     self.alpha = 0.0 
     self.isHidden = true 
    } 
} 

}

Gesture eylemi:

open func tapToFocus(_ gesture : UILongPressGestureRecognizer) { 

    if (gesture.state == UIGestureRecognizerState.began) { 

     let touchPoint:CGPoint = gesture.location(in: self.previewView) 

     if let fsquare = self.focusSquare { 
      fsquare.updatePoint(touchPoint) 
     }else{ 
      self.focusSquare = CameraFocusSquare(touchPoint: touchPoint) 
      self.previewView.addSubview(self.focusSquare!) 
      self.focusSquare?.setNeedsDisplay() 
     } 

     self.focusSquare?.animateFocusingAction() 

     let convertedPoint:CGPoint = self.previewLayer!.captureDevicePointOfInterest(for: touchPoint) 

     let currentDevice:AVCaptureDevice = self.videoDeviceInput!.device 

     if currentDevice.isFocusPointOfInterestSupported && currentDevice.isFocusModeSupported(AVCaptureFocusMode.autoFocus){ 

      do { 

       try currentDevice.lockForConfiguration() 
       currentDevice.focusPointOfInterest = convertedPoint 
       currentDevice.focusMode = AVCaptureFocusMode.autoFocus 

       if currentDevice.isExposureModeSupported(AVCaptureExposureMode.continuousAutoExposure){ 
        currentDevice.exposureMode = AVCaptureExposureMode.continuousAutoExposure 
       } 
       currentDevice.isSubjectAreaChangeMonitoringEnabled = true 
       currentDevice.unlockForConfiguration() 

      } catch { 

      } 
     } 
    } 
} 
İlgili konular