2011-06-17 54 views
4

我有一个UIImagePickerController用于录制视频。现在我想要检测用户何时点击录制按钮。代表不提供任何此类回调。检测用户何时开始录像

有没有什么好的方法可以找出录像的时间?

回答

6

你是对的:代表没有收到关于何时发生视频捕获的任何信息。简单的解决方案是简单地滚动您自己的相机控件 - 将showsCameraControls属性设置为NO,并使用cameraOverlayView属性在自定义视图中提供您自己的控件 - 并让您的“捕捉”按钮调用图像选择器控制器的-startVideoCapture-stopVideoCapture方法提供您需要的任何通知给应用程序的其他部分。

+0

我喜欢这种方法.. – Obaid 2011-06-18 04:07:21

+0

那么你可以在哪里播放和重播视频呢?你如何创建这些屏幕? – PoolHallJunkie 2017-01-09 11:21:11

0

根据IOS API,方法 “startVideoCapture” 给出了布尔返回值

意味着它记录

没有指下列条件之一:

  1. 电影捕获已在进行中
  2. 该设备不支持电影
  3. 捕获该设备是磁盘空间

[参考:http://developer.apple.com/library/ios/#documentation/uikit/reference/UIImagePickerController_Class/UIImagePickerController/UIImagePickerController.html]

所以只要'startRecording'返回一个是,你几乎可以肯定地说它是录音。当然,要检查这一点,你可以随时用NSTimer手动定义你自己的回呼(虽然以前有一个热门辩论关于其准确性的高调)。

1

在一个完美的世界中,你希望苹果只提供一个几位代表会这样做。例如:

  • (无效)imagePickerControllerDidStartVideoCapturing:(的UIImagePickerController *)选择器
  • (无效)imagePickerControllerDidStopVideoCapturing:(的UIImagePickerController *)选择器

现实然而(按照苹果文档)是:

  • 针对UIImagePickerController的协议太基本了,无法做到这一点
  • 此类旨在原样使用,不支持子类
  • 此类的视图层次是私人的,不能修改

文档还指出:“你可以自定义视图分配给cameraOverlayView属性并使用该视图呈现附加信息或管理摄像头界面和您的代码之间的交互“。

在我的应用程序中,我需要提供“UIProgressView”以指示可以录制视频的时间。为了做到这一点,我需要能够检测视频捕捉开始的时刻。

我不想禁用本机相机控制,因为它们很酷,而且我很懒,所以我不想花太多时间重新发明轮子。我所需要的只是捕捉一个大红色按钮被启动或停止录制的事实。

我的解决办法是“覆盖”原来的启动/停止与自定义视图录制按钮,让用户交互的这一观点如下:

overlayView = [[UIView alloc] initWithFrame:self.view.frame]; 

// Start/ Stop fake button 
UIView *ssView = [[UIView alloc] initWithFrame:CGRectMake(self.view.frame.size.width/2 - 35, self.view.frame.size.height - 71, 70, 70)]; 
[ssView setUserInteractionEnabled:YES]; 

// Background color below is only there to make sure my pseudo-button overlaps native Start/Stop button. Comment out the line below to leave it transparent 
[ssView setBackgroundColor:[UIColor colorWithRed:0 green:1 blue:0 alpha:0.5f]]; 

UITapGestureRecognizer *t = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapped:)]; 
[ssView addGestureRecognizer:t]; 

[overlayView addSubview:ssView]; 

// My own progress bar 
UIProgressView *p = [[UIProgressView alloc] initWithProgressViewStyle:UIProgressViewStyleDefault]; 
[p setTintColor:[UIColor redColor]]; 
[p setCenter:CGPointMake(30, 130)]; 
[p setTransform:CGAffineTransformMakeRotation(M_PI/2)]; 
[p setProgress:0]; 

[overlayView addSubview:p]; 

pickerController.cameraOverlayView = overlayView; 

然后我定义的事件处理程序用于抽头如下:

-(void)tapped:(id)sender { 

    if (isRecording) { 
     [pickerController stopVideoCapture]; 
     NSLog(@"Video capturing stopped..."); 
     // add your business logic here ie stop updating progress bar etc... 
     [pickerController.cameraOverlayView setHidden:YES]; 
     isRecording = NO; 
     return; 
    } 

    if ([pickerController startVideoCapture]) { 
     NSLog(@"Video capturing started..."); 
     // add your business logic here ie start updating progress bar etc... 
     isRecording = YES; 
    } 

} 

接口文件的全码:

#import <UIKit/UIKit.h> 
#import <MobileCoreServices/MobileCoreServices.h> 

@interface ViewController : UIViewController <UIImagePickerControllerDelegate> 
- (IBAction)openCamera:(id)sender; 

@end 

Implementati on file:

#import "ViewController.h" 

@interface ViewController() { 
    UIImagePickerController *pickerController; 
    UIView* overlayView; 
    BOOL isRecording; 
} 

@end 

@implementation ViewController 

- (void)viewDidLoad 
{ 
    [super viewDidLoad]; 
    // Do any additional setup after loading the view, typically from a nib. 

    isRecording = NO; 

    pickerController = [[UIImagePickerController alloc] init]; 
    pickerController.delegate = self; 
    pickerController.allowsEditing = NO; 
    pickerController.videoMaximumDuration = 30.0f; 
    pickerController.sourceType = UIImagePickerControllerSourceTypeCamera; 
    pickerController.mediaTypes = [[NSArray alloc] initWithObjects: (NSString *) kUTTypeMovie, nil]; 

    // I want default controls be available here... 
    pickerController.showsCameraControls = YES; 

    overlayView = [[UIView alloc] initWithFrame:self.view.frame]; 

    // Start/ Stop fake button 
    UIView *ssView = [[UIView alloc] initWithFrame:CGRectMake(self.view.frame.size.width/2 - 35, self.view.frame.size.height - 71, 70, 70)]; 
    [ssView setUserInteractionEnabled:YES]; 
    // Background color below is only there to make sure myt pseudo-button overlaps native Start/Stop button 
    [ssView setBackgroundColor:[UIColor colorWithRed:0 green:1 blue:0 alpha:0.5f]]; 

    UITapGestureRecognizer *t = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapped:)]; 
    [ssView addGestureRecognizer:t]; 

    [overlayView addSubview:ssView]; 

    // My own progress bar 
    UIProgressView *p = [[UIProgressView alloc] initWithProgressViewStyle:UIProgressViewStyleDefault]; 
    [p setTintColor:[UIColor redColor]]; 
    [p setCenter:CGPointMake(30, 130)]; 
    [p setTransform:CGAffineTransformMakeRotation(M_PI/2)]; 
    [p setProgress:0]; 

    [overlayView addSubview:p]; 

    pickerController.cameraOverlayView = overlayView; 

} 

- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker { 
    // Cancel button tapped 
    [picker dismissViewControllerAnimated:YES completion:nil]; 
} 

- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info { 

    NSLog(@"Got image : %@", info); 
    [picker dismissViewControllerAnimated:YES completion:nil]; 

    // Do something with video captured 
} 

-(void)tapped:(id)sender { 

    if (isRecording) { 
     [pickerController stopVideoCapture]; 
     NSLog(@"Video capturing stopped..."); 
     // add your business logic here ie stop updating progress bar etc... 
     [pickerController.cameraOverlayView setHidden:YES]; 
     isRecording = NO; 
     return; 
    } 

    if ([pickerController startVideoCapture]) { 
     NSLog(@"Video capturing started..."); 
     // add your business logic here ie start updating progress bar etc... 
     isRecording = YES; 
    } 

} 

- (IBAction)openCamera:(id)sender { 
    [pickerController.cameraOverlayView setHidden:NO]; 
    [self presentViewController:pickerController animated:YES completion:nil];  
} 
@end 

您可能已经注意到,一旦视频捕捉停止后,我隐藏了cameraOverlayView。

[pickerController.cameraOverlayView setHidden:YES]; 

这是为了允许在录制视频后“重播/播放和使用”原生控件正常工作。

+0

真棒,你有一个按钮的图像? – Sasho 2014-05-01 09:20:12

0

这是一个swift 3 UIImagePickerController类,它只允许用户在相机处于横向时捕捉视频。

当您创建的UIImagePickerController:

var imagePicker = CameraVideo_ViewController() 

你需要有这将委托作为得好:

func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) { 
    self.imagePicker.isInFinalScreen = false 
} 

这是类。我真的没有时间整理它,它真的很混乱......我创建了这个类,通过尝试我所能做的一切,而无需删除默认控件。使用了一堆黑客,因此在删除变量时要非常小心,因为即使它们看起来没有用处,它们大多数都会计数。我会尝试重新发布一个更清晰的版本,我可以找到一些时间,但在那之前如果有人可以转贴一个更清洁,更新手我/我们将不胜感激。

import UIKit 
import AVFoundation; 

class CameraVideo_ViewController: UIImagePickerController { 

var viewMain:UIView! 
var lastOrientationWasLandscape:UIDeviceOrientation? 
var isForLibrary:Bool! = false 
var parentController:UIViewController! 

override func viewDidAppear(_ animated: Bool) { 
    if isForLibrary == true { 
     return 
    } 
    let orientation = UIDevice.current.orientation 
    if orientation == .landscapeLeft || orientation == .landscapeRight { 
     lastOrientationWasLandscape = orientation 
    } 
    if (self.isInFinalScreen == true){ 
     self.recordBut.frame = CGRect(x: self.view.frame.size.width - 70 - 16, y: self.view.frame.size.height/2 - 35, width: 70, height: 70) 
     self.isInFinalScreen = false 
    } 
    recordBut.alpha = 1 
    recordBut.isUserInteractionEnabled = true 
    retakeBut.alpha = 1 
    retakeBut.isUserInteractionEnabled = true 
    UIDevice.current.beginGeneratingDeviceOrientationNotifications() 
    NotificationCenter.default.addObserver(self, selector: #selector(orientationChanged(_:)), name: NSNotification.Name.UIDeviceOrientationDidChange, object: nil) 
    let notif = Notification.init(name: NSNotification.Name.UIDeviceOrientationDidChange) 
    orientationChanged(notif) 
} 
override func viewWillDisappear(_ animated: Bool) { 
    viewMain.alpha = 0 
    viewMain.isUserInteractionEnabled = false 
    lastOrientationWasLandscape = nil 
    recordBut.alpha = 0 
    recordBut.isUserInteractionEnabled = false 
    retakeBut.alpha = 0 
    retakeBut.isUserInteractionEnabled = false 
    self.viewMain.alpha = 0 
    self.viewMain.isUserInteractionEnabled = false 
    isInFinalScreenBool = false 
    recordedThisSession = false 
    if isForLibrary == true { 
     return 
    } 
    print("hidingCameraView") 
    NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIDeviceOrientationDidChange, object: nil) 
    UIDevice.current.endGeneratingDeviceOrientationNotifications() 

} 

override func viewDidLoad() { 
    super.viewDidLoad() 
    if isForLibrary == true { 
     return 
    } 

    viewMain = UIView() 
    viewMain.frame = CGRect(x: view.frame.minX, y: view.frame.minY, width: view.frame.width, height: view.frame.height) 
    viewMain.backgroundColor = UIColor.clear 

    let viewBg = UIView() 
    viewBg.frame = CGRect(x: view.frame.minX, y: view.frame.minY, width: view.frame.width, height: view.frame.height) 
    viewBg.backgroundColor = UIColor.black 
    viewBg.alpha = 0.5 

    let viewAlertBg = UIView() 
    viewAlertBg.frame = CGRect(x: view.frame.width/2 - 250/2, y: view.frame.height/2 - 100/2 - 25, width: 250, height: 100) 
    viewAlertBg.backgroundColor = UIColor.white 
    viewAlertBg.alpha = 1 
    viewAlertBg.clipsToBounds = true; 
    var path = UIBezierPath(roundedRect:viewAlertBg.bounds, 
          byRoundingCorners:[.topLeft, .topRight], 
          cornerRadii: CGSize(width: 25, height: 25)) 

    var maskLayer = CAShapeLayer() 

    maskLayer.path = path.cgPath 
    viewAlertBg.layer.mask = maskLayer 


    let viewAlertBgUnderline = UIView() 
    viewAlertBgUnderline.frame = CGRect(x: view.frame.width/2 - 250/2, y: viewAlertBg.frame.maxY, width: 250, height: 1) 
    viewAlertBgUnderline.backgroundColor = UIColor.lightGray 
    viewAlertBgUnderline.alpha = 1 
    viewAlertBgUnderline.clipsToBounds = true; 

    let viewAlertCancelBut = UIButton() 
    viewAlertCancelBut.frame = CGRect(x: view.frame.width/2 - 250/2, y: viewAlertBgUnderline.frame.maxY, width: 250, height: 50) 
    viewAlertCancelBut.backgroundColor = UIColor.white 
    viewAlertCancelBut.setTitle("Back", for: .normal) 
    viewAlertCancelBut.setTitleColor(UIColor.blue, for: .normal) 
    path = UIBezierPath(roundedRect:viewAlertCancelBut.bounds, 
          byRoundingCorners:[.bottomLeft, .bottomRight], 
          cornerRadii: CGSize(width: 25, height: 25)) 

    maskLayer = CAShapeLayer() 

    maskLayer.path = path.cgPath 
    viewAlertCancelBut.layer.mask = maskLayer 
    viewAlertCancelBut.addTarget(self, action: #selector(onBack(_:)), for: .touchUpInside) 

    let alertLabel = UILabel() 
    alertLabel.numberOfLines = 4 
    alertLabel.frame = CGRect(x: 16, y: 16, width: 250 - 32, height: 100 - 32) 
    alertLabel.textAlignment = NSTextAlignment.center 
    alertLabel.adjustsFontSizeToFitWidth = true 
    alertLabel.font = UIFont.systemFont(ofSize: 12) 
    alertLabel.backgroundColor = UIColor.clear 
    alertLabel.textColor = UIColor.black 
    let boldText = "The video must be recorded in landscape mode.\n" 
    let normalText = "Please hold your device in a horizontal position!" 
    let attrs = [NSFontAttributeName : UIFont.boldSystemFont(ofSize: 13)] 
    let boldString = NSMutableAttributedString(string:boldText, attributes:attrs) 
    let attributedString = NSMutableAttributedString(string:"") 
    attributedString.append(boldString) 
    attributedString.append(NSMutableAttributedString(string:normalText, attributes:nil)) 
    alertLabel.attributedText = attributedString 

    viewAlertBg.addSubview(alertLabel) 
    viewMain.addSubview(viewBg) 
    viewMain.addSubview(viewAlertCancelBut) 
    viewMain.addSubview(viewAlertBg) 
    viewMain.addSubview(viewAlertBgUnderline) 

    viewMain.alpha = 0 
    viewMain.isUserInteractionEnabled = false 

    // Start/ Stop fake button 
    recordBut = UIButton() 
    if (UIDevice.current.userInterfaceIdiom == .phone){ 
     recordBut.frame = CGRect(x: self.view.frame.size.width/2 - 35, y: self.view.frame.size.height - 70 - 2, width: 70, height: 70) 
    }else{ 
     recordBut.frame = CGRect(x: self.view.frame.size.height - 70 - 16, y: self.view.frame.size.width/2 - 35, width: 70, height: 70) 
    } 

    recordBut.setTitle("", for: .normal) 
    recordBut.setTitleColor(UIColor.blue, for: .normal) 
    recordBut.isUserInteractionEnabled = true 
    recordBut.backgroundColor = UIColor(red: 0, green: 1, blue: 0, alpha: 0.5) 
    recordBut.addTarget(self, action: #selector(tapped(_:)), for: .touchUpInside) 
    self.view.addSubview(recordBut) 

    retakeBut = UIButton() 
    if (UIDevice.current.userInterfaceIdiom == .phone){ 
     retakeBut.frame = CGRect(x: 0, y: self.view.frame.size.height - 70, width: 80, height: 70) 
    }else{ 
     retakeBut.frame = CGRect(x: 0, y: self.view.frame.size.width - 70, width: 80, height: 70) 
    } 
    retakeBut.setTitle("", for: .normal) 
    retakeBut.setTitleColor(UIColor.blue, for: .normal) 
    retakeBut.isUserInteractionEnabled = true 
    retakeBut.backgroundColor = UIColor(red: 0, green: 1, blue: 0, alpha: 0.5) 
    retakeBut.addTarget(self, action: #selector(retake(_:)), for: .touchUpInside) 
    self.view.addSubview(retakeBut) 
    self.view.addSubview(viewMain) 

} 
override func viewDidLayoutSubviews() { 
    if isForLibrary == true { 
     return 
    } 
    self.adjustViews(for: UIDevice.current.orientation) 
} 
var t:UITapGestureRecognizer! 
var recordBut:UIButton! 
var retakeBut:UIButton! 
var isInFinalScreen:Bool = false 
var isRecording:Bool = false 
var isInFinalScreenBool:Bool = false 
var recordedThisSession:Bool = false 
func tapped(_ sender:UIButton){ 
    if (isRecording == false && self.startVideoCapture()){ 
     recordedThisSession = true 
     isRecording = true 
     retakeBut.alpha = 0 
     retakeBut.isUserInteractionEnabled = false 
    }else{ 
     retakeBut.alpha = 1 
     retakeBut.isUserInteractionEnabled = true 
     recordBut.alpha = 0 
     recordBut.isUserInteractionEnabled = false 
     self.stopVideoCapture() 
     isRecording = false 
     if (UIDevice.current.orientation != .portrait){ 
      self.adjustViews(for: UIDevice.current.orientation) 
     } 
     isInFinalScreen = true 
     return 
    } 
} 
func retake(_ sender:UIButton){ 
    if (recordedThisSession == false){ 
     onBack(sender) 
    } 
    self.dismiss(animated: true, completion: { 
     self.parentController.present((self.parentController as! AddVideo_ViewController).imagePicker, animated: true, completion: { 

     }) 
    }) 
} 

func onBack(_ sender:UIButton){ 
    self.isInFinalScreen = false 
    self.dismiss(animated: true, completion: { 
    }) 
} 

override func didReceiveMemoryWarning() { 
    super.didReceiveMemoryWarning() 
    // Dispose of any resources that can be recreated. 
} 

func orientationChanged(_ notification: Notification) { 
    self.adjustViews(for: UIDevice.current.orientation) 
} 

func adjustViews(for orient: UIDeviceOrientation) { 
    var orientation = orient 
    if (orientation.isLandscape == true) || (orientation.isFlat && lastOrientationWasLandscape?.isPortrait == false) { 
     print(".....landscape.....") 
      if (UIDevice.current.userInterfaceIdiom == .pad){ 
       self.recordBut.frame = CGRect(x: self.view.frame.size.width - 70 - 16, y: self.view.frame.size.height/2 - 35, width: 70, height: 70) 
       self.retakeBut.frame = CGRect(x: 0, y: self.view.frame.size.height - 70, width: 80, height: 70) 
      }else{ 
       recordBut.frame = CGRect(x: self.view.frame.size.width/2 - 35, y: self.view.frame.size.height - 70 - 2, width: 70, height: 70) 
       retakeBut.frame = CGRect(x: 0, y: self.view.frame.size.height - 70, width: 80, height: 70) 
      } 
      if (recordedThisSession == false){ 
       if (UIDevice.current.userInterfaceIdiom == .pad){ 
        self.retakeBut.frame = CGRect(x: self.view.frame.size.width - 100, y: self.view.frame.size.height - 70, width: 100, height: 70) 
       }else{ 
        retakeBut.frame = CGRect(x: 0, y: self.view.frame.size.height - 70, width: 80, height: 70) 
       } 
      } 

      if (self.isInFinalScreenBool == true){ 
       return 
      } 
      if (self.isInFinalScreen == true){ 
       self.isInFinalScreenBool = !isInFinalScreenBool 
       self.isInFinalScreen = false 
       return 
      } 
      if (self.isRecording){ 
       return 
      } 
      self.viewMain.alpha = 0 
      self.viewMain.isUserInteractionEnabled = false 
      self.lastOrientationWasLandscape = orientation 
    } 
    else { 
     print(".....portrait.....") 
     self.lastOrientationWasLandscape = UIDeviceOrientation(rawValue: UIDeviceOrientation.portrait.rawValue) 
      if (UIDevice.current.userInterfaceIdiom == .pad){ 
       self.recordBut.frame = CGRect(x: self.view.frame.size.width - 70 - 16, y: self.view.frame.size.height/2 - 35, width: 70, height: 70) 
       self.retakeBut.frame = CGRect(x: 0, y: self.view.frame.size.height - 70, width: 80, height: 70) 
      }else{ 
       recordBut.frame = CGRect(x: self.view.frame.size.width/2 - 35, y: self.view.frame.size.height - 70 - 2, width: 70, height: 70) 
       retakeBut.frame = CGRect(x: 0, y: self.view.frame.size.height - 70, width: 80, height: 70) 
      } 
      if (recordedThisSession == false){ 
       if (UIDevice.current.userInterfaceIdiom == .pad){ 
        self.retakeBut.frame = CGRect(x: self.view.frame.size.width - 100, y: self.view.frame.size.height - 70, width: 100, height: 70) 
       }else{ 
        retakeBut.frame = CGRect(x: 0, y: self.view.frame.size.height - 70, width: 80, height: 70) 
       } 
      } 

      if (self.isInFinalScreenBool == true){ 
       return 
      } 
      if (self.isInFinalScreen){ 
       return 
      } 
      if (self.isRecording){ 
       return 
      } 
      self.viewMain.alpha = 1 
      self.viewMain.isUserInteractionEnabled = true 
    } 

} 
/* 
// MARK: - Navigation 

// In a storyboard-based application, you will often want to do a little preparation before navigation 
override func prepare(for segue: UIStoryboardSegue, sender: Any?) { 
    // Get the new view controller using segue.destinationViewController. 
    // Pass the selected object to the new view controller. 
} 
*/ 

} 

祝你好运!

相关问题