亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 系統 > iOS > 正文

iOS開發-自定義相機實例(仿微信)

2020-07-26 02:53:27
字體:
來源:轉載
供稿:網友

網上有很多自定義相機的例子,這里只是我臨時寫的一個小demo,僅供參考:

用到了下面幾個庫:

#import <AVFoundation/AVFoundation.h>#import <AssetsLibrary/AssetsLibrary.h>

在使用的時候需要在Info.plist中把相關權限寫進去:

Privacy - Microphone Usage DescriptionPrivacy - Photo Library Usage DescriptionPrivacy - Camera Usage Description

我在寫這個demo時,是按照微信的樣式寫的,同樣是點擊拍照、長按錄制視頻,視頻錄制完直接進行播放,這里封裝了一個簡易的播放器:

m文件

#import "HAVPlayer.h"#import <AVFoundation/AVFoundation.h>@interface HAVPlayer ()@property (nonatomic,strong) AVPlayer *player;//播放器對象@end@implementation HAVPlayer/*// Only override drawRect: if you perform custom drawing.// An empty implementation adversely affects performance during animation.- (void)drawRect:(CGRect)rect {  // Drawing code}*/- (instancetype)initWithFrame:(CGRect)frame withShowInView:(UIView *)bgView url:(NSURL *)url {  if (self = [self initWithFrame:frame]) {    //創建播放器層    AVPlayerLayer *playerLayer = [AVPlayerLayer playerLayerWithPlayer:self.player];    playerLayer.frame = self.bounds;    [self.layer addSublayer:playerLayer];    if (url) {      self.videoUrl = url;    }    [bgView addSubview:self];  }  return self;}- (void)dealloc {  [self removeAvPlayerNtf];  [self stopPlayer];  self.player = nil;}- (AVPlayer *)player {  if (!_player) {    _player = [AVPlayer playerWithPlayerItem:[self getAVPlayerItem]];    [self addAVPlayerNtf:_player.currentItem];  }  return _player;}- (AVPlayerItem *)getAVPlayerItem {  AVPlayerItem *playerItem=[AVPlayerItem playerItemWithURL:self.videoUrl];  return playerItem;}- (void)setVideoUrl:(NSURL *)videoUrl {  _videoUrl = videoUrl;  [self removeAvPlayerNtf];  [self nextPlayer];}- (void)nextPlayer {  [self.player seekToTime:CMTimeMakeWithSeconds(0, _player.currentItem.duration.timescale)];  [self.player replaceCurrentItemWithPlayerItem:[self getAVPlayerItem]];  [self addAVPlayerNtf:self.player.currentItem];  if (self.player.rate == 0) {    [self.player play];  }}- (void) addAVPlayerNtf:(AVPlayerItem *)playerItem {  //監控狀態屬性  [playerItem addObserver:self forKeyPath:@"status" options:NSKeyValueObservingOptionNew context:nil];  //監控網絡加載情況屬性  [playerItem addObserver:self forKeyPath:@"loadedTimeRanges" options:NSKeyValueObservingOptionNew context:nil];  [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(playbackFinished:) name:AVPlayerItemDidPlayToEndTimeNotification object:self.player.currentItem];}- (void)removeAvPlayerNtf {  AVPlayerItem *playerItem = self.player.currentItem;  [playerItem removeObserver:self forKeyPath:@"status"];  [playerItem removeObserver:self forKeyPath:@"loadedTimeRanges"];  [[NSNotificationCenter defaultCenter] removeObserver:self];}- (void)stopPlayer {  if (self.player.rate == 1) {    [self.player pause];//如果在播放狀態就停止  }}/** * 通過KVO監控播放器狀態 * * @param keyPath 監控屬性 * @param object 監視器 * @param change 狀態改變 * @param context 上下文 */-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context{  AVPlayerItem *playerItem = object;  if ([keyPath isEqualToString:@"status"]) {    AVPlayerStatus status= [[change objectForKey:@"new"] intValue];    if(status==AVPlayerStatusReadyToPlay){      NSLog(@"正在播放...,視頻總長度:%.2f",CMTimeGetSeconds(playerItem.duration));    }  }else if([keyPath isEqualToString:@"loadedTimeRanges"]){    NSArray *array=playerItem.loadedTimeRanges;    CMTimeRange timeRange = [array.firstObject CMTimeRangeValue];//本次緩沖時間范圍    float startSeconds = CMTimeGetSeconds(timeRange.start);    float durationSeconds = CMTimeGetSeconds(timeRange.duration);    NSTimeInterval totalBuffer = startSeconds + durationSeconds;//緩沖總長度    NSLog(@"共緩沖:%.2f",totalBuffer);  }}- (void)playbackFinished:(NSNotification *)ntf {  Plog(@"視頻播放完成");  [self.player seekToTime:CMTimeMake(0, 1)];  [self.player play];}@end

另外微信下面的按鈕長按會出現圓弧時間條:

m文件

#import "HProgressView.h"@interface HProgressView ()/** * 進度值0-1.0之間 */@property (nonatomic,assign)CGFloat progressValue;@property (nonatomic, assign) CGFloat currentTime;@end@implementation HProgressView// Only override drawRect: if you perform custom drawing.// An empty implementation adversely affects performance during animation.- (void)drawRect:(CGRect)rect {  // Drawing code  CGContextRef ctx = UIGraphicsGetCurrentContext();//獲取上下文  Plog(@"width = %f",self.frame.size.width);  CGPoint center = CGPointMake(self.frame.size.width/2.0, self.frame.size.width/2.0); //設置圓心位置  CGFloat radius = self.frame.size.width/2.0-5; //設置半徑  CGFloat startA = - M_PI_2; //圓起點位置  CGFloat endA = -M_PI_2 + M_PI * 2 * _progressValue; //圓終點位置  UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:center radius:radius startAngle:startA endAngle:endA clockwise:YES];  CGContextSetLineWidth(ctx, 10); //設置線條寬度  [[UIColor whiteColor] setStroke]; //設置描邊顏色  CGContextAddPath(ctx, path.CGPath); //把路徑添加到上下文  CGContextStrokePath(ctx); //渲染}- (void)setTimeMax:(NSInteger)timeMax {  _timeMax = timeMax;  self.currentTime = 0;  self.progressValue = 0;  [self setNeedsDisplay];  self.hidden = NO;  [self performSelector:@selector(startProgress) withObject:nil afterDelay:0.1];}- (void)clearProgress {  _currentTime = _timeMax;  self.hidden = YES;}- (void)startProgress {  _currentTime += 0.1;  if (_timeMax > _currentTime) {    _progressValue = _currentTime/_timeMax;    Plog(@"progress = %f",_progressValue);    [self setNeedsDisplay];    [self performSelector:@selector(startProgress) withObject:nil afterDelay:0.1];  }  if (_timeMax <= _currentTime) {    [self clearProgress];  }}@end

接下來就是相機的控制器了,由于是臨時寫的,所以用的xib,大家不要直接使用,直接上m文件代碼吧:

#import "HVideoViewController.h"#import <AVFoundation/AVFoundation.h>#import "HAVPlayer.h"#import "HProgressView.h"#import <Foundation/Foundation.h>#import <AssetsLibrary/AssetsLibrary.h>typedef void(^PropertyChangeBlock)(AVCaptureDevice *captureDevice);@interface HVideoViewController ()<AVCaptureFileOutputRecordingDelegate>//輕觸拍照,按住攝像@property (strong, nonatomic) IBOutlet UILabel *labelTipTitle;//視頻輸出流@property (strong,nonatomic) AVCaptureMovieFileOutput *captureMovieFileOutput;//圖片輸出流//@property (strong,nonatomic) AVCaptureStillImageOutput *captureStillImageOutput;//照片輸出流//負責從AVCaptureDevice獲得輸入數據@property (strong,nonatomic) AVCaptureDeviceInput *captureDeviceInput;//后臺任務標識@property (assign,nonatomic) UIBackgroundTaskIdentifier backgroundTaskIdentifier;@property (assign,nonatomic) UIBackgroundTaskIdentifier lastBackgroundTaskIdentifier;@property (weak, nonatomic) IBOutlet UIImageView *focusCursor; //聚焦光標//負責輸入和輸出設備之間的數據傳遞@property(nonatomic)AVCaptureSession *session;//圖像預覽層,實時顯示捕獲的圖像@property(nonatomic)AVCaptureVideoPreviewLayer *previewLayer;@property (strong, nonatomic) IBOutlet UIButton *btnBack;//重新錄制@property (strong, nonatomic) IBOutlet UIButton *btnAfresh;//確定@property (strong, nonatomic) IBOutlet UIButton *btnEnsure;//攝像頭切換@property (strong, nonatomic) IBOutlet UIButton *btnCamera;@property (strong, nonatomic) IBOutlet UIImageView *bgView;//記錄錄制的時間 默認最大60秒@property (assign, nonatomic) NSInteger seconds;//記錄需要保存視頻的路徑@property (strong, nonatomic) NSURL *saveVideoUrl;//是否在對焦@property (assign, nonatomic) BOOL isFocus;@property (strong, nonatomic) IBOutlet NSLayoutConstraint *afreshCenterX;@property (strong, nonatomic) IBOutlet NSLayoutConstraint *ensureCenterX;@property (strong, nonatomic) IBOutlet NSLayoutConstraint *backCenterX;//視頻播放@property (strong, nonatomic) HAVPlayer *player;@property (strong, nonatomic) IBOutlet HProgressView *progressView;//是否是攝像 YES 代表是錄制 NO 表示拍照@property (assign, nonatomic) BOOL isVideo;@property (strong, nonatomic) UIImage *takeImage;@property (strong, nonatomic) UIImageView *takeImageView;@property (strong, nonatomic) IBOutlet UIImageView *imgRecord;@end//時間大于這個就是視頻,否則為拍照#define TimeMax 1@implementation HVideoViewController-(void)dealloc{  [self removeNotification];}- (void)viewDidLoad {  [super viewDidLoad];  // Do any additional setup after loading the view.  UIImage *image = [UIImage imageNamed:@"sc_btn_take.png"];  self.backCenterX.constant = -(SCREEN_WIDTH/2/2)-image.size.width/2/2;  self.progressView.layer.cornerRadius = self.progressView.frame.size.width/2;  if (self.HSeconds == 0) {    self.HSeconds = 60;  }  [self performSelector:@selector(hiddenTipsLabel) withObject:nil afterDelay:4];}- (void)hiddenTipsLabel {  self.labelTipTitle.hidden = YES;}- (void)didReceiveMemoryWarning {  [super didReceiveMemoryWarning];  // Dispose of any resources that can be recreated.}- (void)viewWillAppear:(BOOL)animated {  [super viewWillAppear:animated];  [[UIApplication sharedApplication] setStatusBarHidden:YES];  [self customCamera];  [self.session startRunning];}-(void)viewDidAppear:(BOOL)animated{  [super viewDidAppear:animated];}-(void)viewDidDisappear:(BOOL)animated{  [super viewDidDisappear:animated];  [self.session stopRunning];}- (void)viewWillDisappear:(BOOL)animated {  [super viewWillDisappear:animated];  [[UIApplication sharedApplication] setStatusBarHidden:NO];}- (void)customCamera {  //初始化會話,用來結合輸入輸出  self.session = [[AVCaptureSession alloc] init];  //設置分辨率 (設備支持的最高分辨率)  if ([self.session canSetSessionPreset:AVCaptureSessionPresetHigh]) {    self.session.sessionPreset = AVCaptureSessionPresetHigh;  }  //取得后置攝像頭  AVCaptureDevice *captureDevice = [self getCameraDeviceWithPosition:AVCaptureDevicePositionBack];  //添加一個音頻輸入設備  AVCaptureDevice *audioCaptureDevice=[[AVCaptureDevice devicesWithMediaType:AVMediaTypeAudio] firstObject];  //初始化輸入設備  NSError *error = nil;  self.captureDeviceInput = [[AVCaptureDeviceInput alloc] initWithDevice:captureDevice error:&error];  if (error) {    Plog(@"取得設備輸入對象時出錯,錯誤原因:%@",error.localizedDescription);    return;  }  //添加音頻  error = nil;  AVCaptureDeviceInput *audioCaptureDeviceInput=[[AVCaptureDeviceInput alloc]initWithDevice:audioCaptureDevice error:&error];  if (error) {    NSLog(@"取得設備輸入對象時出錯,錯誤原因:%@",error.localizedDescription);    return;  }  //輸出對象  self.captureMovieFileOutput = [[AVCaptureMovieFileOutput alloc] init];//視頻輸出  //將輸入設備添加到會話  if ([self.session canAddInput:self.captureDeviceInput]) {    [self.session addInput:self.captureDeviceInput];    [self.session addInput:audioCaptureDeviceInput];    //設置視頻防抖    AVCaptureConnection *connection = [self.captureMovieFileOutput connectionWithMediaType:AVMediaTypeVideo];    if ([connection isVideoStabilizationSupported]) {      connection.preferredVideoStabilizationMode = AVCaptureVideoStabilizationModeCinematic;    }  }  //將輸出設備添加到會話 (剛開始 是照片為輸出對象)  if ([self.session canAddOutput:self.captureMovieFileOutput]) {    [self.session addOutput:self.captureMovieFileOutput];  }  //創建視頻預覽層,用于實時展示攝像頭狀態  self.previewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:self.session];  self.previewLayer.frame = self.view.bounds;//CGRectMake(0, 0, self.view.width, self.view.height);  self.previewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;//填充模式  [self.bgView.layer addSublayer:self.previewLayer];  [self addNotificationToCaptureDevice:captureDevice];  [self addGenstureRecognizer];}- (IBAction)onCancelAction:(UIButton *)sender {  [self dismissViewControllerAnimated:YES completion:^{    [Utility hideProgressDialog];  }];}- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {  if ([[touches anyObject] view] == self.imgRecord) {    Plog(@"開始錄制");    //根據設備輸出獲得連接    AVCaptureConnection *connection = [self.captureMovieFileOutput connectionWithMediaType:AVMediaTypeAudio];    //根據連接取得設備輸出的數據    if (![self.captureMovieFileOutput isRecording]) {      //如果支持多任務則開始多任務      if ([[UIDevice currentDevice] isMultitaskingSupported]) {        self.backgroundTaskIdentifier = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:nil];      }      if (self.saveVideoUrl) {        [[NSFileManager defaultManager] removeItemAtURL:self.saveVideoUrl error:nil];      }      //預覽圖層和視頻方向保持一致      connection.videoOrientation = [self.previewLayer connection].videoOrientation;      NSString *outputFielPath=[NSTemporaryDirectory() stringByAppendingString:@"myMovie.mov"];      NSLog(@"save path is :%@",outputFielPath);      NSURL *fileUrl=[NSURL fileURLWithPath:outputFielPath];      NSLog(@"fileUrl:%@",fileUrl);      [self.captureMovieFileOutput startRecordingToOutputFileURL:fileUrl recordingDelegate:self];    } else {      [self.captureMovieFileOutput stopRecording];    }  }}- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {  if ([[touches anyObject] view] == self.imgRecord) {    Plog(@"結束觸摸");    if (!self.isVideo) {      [self performSelector:@selector(endRecord) withObject:nil afterDelay:0.3];    } else {      [self endRecord];    }  }}- (void)endRecord {  [self.captureMovieFileOutput stopRecording];//停止錄制}- (IBAction)onAfreshAction:(UIButton *)sender {  Plog(@"重新錄制");  [self recoverLayout];}- (IBAction)onEnsureAction:(UIButton *)sender {  Plog(@"確定 這里進行保存或者發送出去");  if (self.saveVideoUrl) {    WS(weakSelf)    [Utility showProgressDialogText:@"視頻處理中..."];    ALAssetsLibrary *assetsLibrary=[[ALAssetsLibrary alloc]init];    [assetsLibrary writeVideoAtPathToSavedPhotosAlbum:self.saveVideoUrl completionBlock:^(NSURL *assetURL, NSError *error) {      Plog(@"outputUrl:%@",weakSelf.saveVideoUrl);      [[NSFileManager defaultManager] removeItemAtURL:weakSelf.saveVideoUrl error:nil];      if (weakSelf.lastBackgroundTaskIdentifier!= UIBackgroundTaskInvalid) {        [[UIApplication sharedApplication] endBackgroundTask:weakSelf.lastBackgroundTaskIdentifier];      }      if (error) {        Plog(@"保存視頻到相簿過程中發生錯誤,錯誤信息:%@",error.localizedDescription);        [Utility showAllTextDialog:KAppDelegate.window Text:@"保存視頻到相冊發生錯誤"];      } else {        if (weakSelf.takeBlock) {          weakSelf.takeBlock(assetURL);        }        Plog(@"成功保存視頻到相簿.");        [weakSelf onCancelAction:nil];      }    }];  } else {    //照片    UIImageWriteToSavedPhotosAlbum(self.takeImage, self, nil, nil);    if (self.takeBlock) {      self.takeBlock(self.takeImage);    }    [self onCancelAction:nil];  }}//前后攝像頭的切換- (IBAction)onCameraAction:(UIButton *)sender {  Plog(@"切換攝像頭");  AVCaptureDevice *currentDevice=[self.captureDeviceInput device];  AVCaptureDevicePosition currentPosition=[currentDevice position];  [self removeNotificationFromCaptureDevice:currentDevice];  AVCaptureDevice *toChangeDevice;  AVCaptureDevicePosition toChangePosition = AVCaptureDevicePositionFront;//前  if (currentPosition == AVCaptureDevicePositionUnspecified || currentPosition == AVCaptureDevicePositionFront) {    toChangePosition = AVCaptureDevicePositionBack;//后  }  toChangeDevice=[self getCameraDeviceWithPosition:toChangePosition];  [self addNotificationToCaptureDevice:toChangeDevice];  //獲得要調整的設備輸入對象  AVCaptureDeviceInput *toChangeDeviceInput=[[AVCaptureDeviceInput alloc]initWithDevice:toChangeDevice error:nil];  //改變會話的配置前一定要先開啟配置,配置完成后提交配置改變  [self.session beginConfiguration];  //移除原有輸入對象  [self.session removeInput:self.captureDeviceInput];  //添加新的輸入對象  if ([self.session canAddInput:toChangeDeviceInput]) {    [self.session addInput:toChangeDeviceInput];    self.captureDeviceInput = toChangeDeviceInput;  }  //提交會話配置  [self.session commitConfiguration];}- (void)onStartTranscribe:(NSURL *)fileURL {  if ([self.captureMovieFileOutput isRecording]) {    -- self.seconds;    if (self.seconds > 0) {      if (self.HSeconds - self.seconds >= TimeMax && !self.isVideo) {        self.isVideo = YES;//長按時間超過TimeMax 表示是視頻錄制        self.progressView.timeMax = self.seconds;      }      [self performSelector:@selector(onStartTranscribe:) withObject:fileURL afterDelay:1.0];    } else {      if ([self.captureMovieFileOutput isRecording]) {        [self.captureMovieFileOutput stopRecording];      }    }  }}#pragma mark - 視頻輸出代理-(void)captureOutput:(AVCaptureFileOutput *)captureOutput didStartRecordingToOutputFileAtURL:(NSURL *)fileURL fromConnections:(NSArray *)connections{  Plog(@"開始錄制...");  self.seconds = self.HSeconds;  [self performSelector:@selector(onStartTranscribe:) withObject:fileURL afterDelay:1.0];}-(void)captureOutput:(AVCaptureFileOutput *)captureOutput didFinishRecordingToOutputFileAtURL:(NSURL *)outputFileURL fromConnections:(NSArray *)connections error:(NSError *)error{  Plog(@"視頻錄制完成.");  [self changeLayout];  if (self.isVideo) {    self.saveVideoUrl = outputFileURL;    if (!self.player) {      self.player = [[HAVPlayer alloc] initWithFrame:self.bgView.bounds withShowInView:self.bgView url:outputFileURL];    } else {      if (outputFileURL) {        self.player.videoUrl = outputFileURL;        self.player.hidden = NO;      }    }  } else {    //照片    self.saveVideoUrl = nil;    [self videoHandlePhoto:outputFileURL];  }}- (void)videoHandlePhoto:(NSURL *)url {  AVURLAsset *urlSet = [AVURLAsset assetWithURL:url];  AVAssetImageGenerator *imageGenerator = [AVAssetImageGenerator assetImageGeneratorWithAsset:urlSet];  imageGenerator.appliesPreferredTrackTransform = YES;  // 截圖的時候調整到正確的方向  NSError *error = nil;  CMTime time = CMTimeMake(0,30);//縮略圖創建時間 CMTime是表示電影時間信息的結構體,第一個參數表示是視頻第幾秒,第二個參數表示每秒幀數.(如果要獲取某一秒的第幾幀可以使用CMTimeMake方法)  CMTime actucalTime; //縮略圖實際生成的時間  CGImageRef cgImage = [imageGenerator copyCGImageAtTime:time actualTime:&actucalTime error:&error];  if (error) {    Plog(@"截取視頻圖片失敗:%@",error.localizedDescription);  }  CMTimeShow(actucalTime);  UIImage *image = [UIImage imageWithCGImage:cgImage];  CGImageRelease(cgImage);  if (image) {    Plog(@"視頻截取成功");  } else {    Plog(@"視頻截取失敗");  }  self.takeImage = image;//[UIImage imageWithCGImage:cgImage];  [[NSFileManager defaultManager] removeItemAtURL:url error:nil];  if (!self.takeImageView) {    self.takeImageView = [[UIImageView alloc] initWithFrame:self.view.frame];    [self.bgView addSubview:self.takeImageView];  }  self.takeImageView.hidden = NO;  self.takeImageView.image = self.takeImage;}#pragma mark - 通知//注冊通知- (void)setupObservers{  NSNotificationCenter *notification = [NSNotificationCenter defaultCenter];  [notification addObserver:self selector:@selector(applicationDidEnterBackground:) name:UIApplicationWillResignActiveNotification object:[UIApplication sharedApplication]];}//進入后臺就退出視頻錄制- (void)applicationDidEnterBackground:(NSNotification *)notification {  [self onCancelAction:nil];}/** * 給輸入設備添加通知 */-(void)addNotificationToCaptureDevice:(AVCaptureDevice *)captureDevice{  //注意添加區域改變捕獲通知必須首先設置設備允許捕獲  [self changeDeviceProperty:^(AVCaptureDevice *captureDevice) {    captureDevice.subjectAreaChangeMonitoringEnabled=YES;  }];  NSNotificationCenter *notificationCenter= [NSNotificationCenter defaultCenter];  //捕獲區域發生改變  [notificationCenter addObserver:self selector:@selector(areaChange:) name:AVCaptureDeviceSubjectAreaDidChangeNotification object:captureDevice];}-(void)removeNotificationFromCaptureDevice:(AVCaptureDevice *)captureDevice{  NSNotificationCenter *notificationCenter= [NSNotificationCenter defaultCenter];  [notificationCenter removeObserver:self name:AVCaptureDeviceSubjectAreaDidChangeNotification object:captureDevice];}/** * 移除所有通知 */-(void)removeNotification{  NSNotificationCenter *notificationCenter= [NSNotificationCenter defaultCenter];  [notificationCenter removeObserver:self];}-(void)addNotificationToCaptureSession:(AVCaptureSession *)captureSession{  NSNotificationCenter *notificationCenter= [NSNotificationCenter defaultCenter];  //會話出錯  [notificationCenter addObserver:self selector:@selector(sessionRuntimeError:) name:AVCaptureSessionRuntimeErrorNotification object:captureSession];}/** * 設備連接成功 * * @param notification 通知對象 */-(void)deviceConnected:(NSNotification *)notification{  NSLog(@"設備已連接...");}/** * 設備連接斷開 * * @param notification 通知對象 */-(void)deviceDisconnected:(NSNotification *)notification{  NSLog(@"設備已斷開.");}/** * 捕獲區域改變 * * @param notification 通知對象 */-(void)areaChange:(NSNotification *)notification{  NSLog(@"捕獲區域改變...");}/** * 會話出錯 * * @param notification 通知對象 */-(void)sessionRuntimeError:(NSNotification *)notification{  NSLog(@"會話發生錯誤.");}/** * 取得指定位置的攝像頭 * * @param position 攝像頭位置 * * @return 攝像頭設備 */-(AVCaptureDevice *)getCameraDeviceWithPosition:(AVCaptureDevicePosition )position{  NSArray *cameras= [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo];  for (AVCaptureDevice *camera in cameras) {    if ([camera position] == position) {      return camera;    }  }  return nil;}/** * 改變設備屬性的統一操作方法 * * @param propertyChange 屬性改變操作 */-(void)changeDeviceProperty:(PropertyChangeBlock)propertyChange{  AVCaptureDevice *captureDevice= [self.captureDeviceInput device];  NSError *error;  //注意改變設備屬性前一定要首先調用lockForConfiguration:調用完之后使用unlockForConfiguration方法解鎖  if ([captureDevice lockForConfiguration:&error]) {    //自動白平衡    if ([captureDevice isWhiteBalanceModeSupported:AVCaptureWhiteBalanceModeContinuousAutoWhiteBalance]) {      [captureDevice setWhiteBalanceMode:AVCaptureWhiteBalanceModeContinuousAutoWhiteBalance];    }    //自動根據環境條件開啟閃光燈    if ([captureDevice isFlashModeSupported:AVCaptureFlashModeAuto]) {      [captureDevice setFlashMode:AVCaptureFlashModeAuto];    }    propertyChange(captureDevice);    [captureDevice unlockForConfiguration];  }else{    NSLog(@"設置設備屬性過程發生錯誤,錯誤信息:%@",error.localizedDescription);  }}/** * 設置閃光燈模式 * * @param flashMode 閃光燈模式 */-(void)setFlashMode:(AVCaptureFlashMode )flashMode{  [self changeDeviceProperty:^(AVCaptureDevice *captureDevice) {    if ([captureDevice isFlashModeSupported:flashMode]) {      [captureDevice setFlashMode:flashMode];    }  }];}/** * 設置聚焦模式 * * @param focusMode 聚焦模式 */-(void)setFocusMode:(AVCaptureFocusMode )focusMode{  [self changeDeviceProperty:^(AVCaptureDevice *captureDevice) {    if ([captureDevice isFocusModeSupported:focusMode]) {      [captureDevice setFocusMode:focusMode];    }  }];}/** * 設置曝光模式 * * @param exposureMode 曝光模式 */-(void)setExposureMode:(AVCaptureExposureMode)exposureMode{  [self changeDeviceProperty:^(AVCaptureDevice *captureDevice) {    if ([captureDevice isExposureModeSupported:exposureMode]) {      [captureDevice setExposureMode:exposureMode];    }  }];}/** * 設置聚焦點 * * @param point 聚焦點 */-(void)focusWithMode:(AVCaptureFocusMode)focusMode exposureMode:(AVCaptureExposureMode)exposureMode atPoint:(CGPoint)point{  [self changeDeviceProperty:^(AVCaptureDevice *captureDevice) {//    if ([captureDevice isFocusPointOfInterestSupported]) {//      [captureDevice setFocusPointOfInterest:point];//    }//    if ([captureDevice isExposurePointOfInterestSupported]) {//      [captureDevice setExposurePointOfInterest:point];//    }    if ([captureDevice isExposureModeSupported:exposureMode]) {      [captureDevice setExposureMode:exposureMode];    }    if ([captureDevice isFocusModeSupported:focusMode]) {      [captureDevice setFocusMode:focusMode];    }  }];}/** * 添加點按手勢,點按時聚焦 */-(void)addGenstureRecognizer{  UITapGestureRecognizer *tapGesture=[[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(tapScreen:)];  [self.bgView addGestureRecognizer:tapGesture];}-(void)tapScreen:(UITapGestureRecognizer *)tapGesture{  if ([self.session isRunning]) {    CGPoint point= [tapGesture locationInView:self.bgView];    //將UI坐標轉化為攝像頭坐標    CGPoint cameraPoint= [self.previewLayer captureDevicePointOfInterestForPoint:point];    [self setFocusCursorWithPoint:point];    [self focusWithMode:AVCaptureFocusModeContinuousAutoFocus exposureMode:AVCaptureExposureModeContinuousAutoExposure atPoint:cameraPoint];  }}/** * 設置聚焦光標位置 * * @param point 光標位置 */-(void)setFocusCursorWithPoint:(CGPoint)point{  if (!self.isFocus) {    self.isFocus = YES;    self.focusCursor.center=point;    self.focusCursor.transform = CGAffineTransformMakeScale(1.25, 1.25);    self.focusCursor.alpha = 1.0;    [UIView animateWithDuration:0.5 animations:^{      self.focusCursor.transform = CGAffineTransformIdentity;    } completion:^(BOOL finished) {      [self performSelector:@selector(onHiddenFocusCurSorAction) withObject:nil afterDelay:0.5];    }];  }}- (void)onHiddenFocusCurSorAction {  self.focusCursor.alpha=0;  self.isFocus = NO;}//拍攝完成時調用- (void)changeLayout {  self.imgRecord.hidden = YES;  self.btnCamera.hidden = YES;  self.btnAfresh.hidden = NO;  self.btnEnsure.hidden = NO;  self.btnBack.hidden = YES;  if (self.isVideo) {    [self.progressView clearProgress];  }  self.afreshCenterX.constant = -(SCREEN_WIDTH/2/2);  self.ensureCenterX.constant = SCREEN_WIDTH/2/2;  [UIView animateWithDuration:0.25 animations:^{    [self.view layoutIfNeeded];  }];  self.lastBackgroundTaskIdentifier = self.backgroundTaskIdentifier;  self.backgroundTaskIdentifier = UIBackgroundTaskInvalid;  [self.session stopRunning];}//重新拍攝時調用- (void)recoverLayout {  if (self.isVideo) {    self.isVideo = NO;    [self.player stopPlayer];    self.player.hidden = YES;  }  [self.session startRunning];  if (!self.takeImageView.hidden) {    self.takeImageView.hidden = YES;  }//  self.saveVideoUrl = nil;  self.afreshCenterX.constant = 0;  self.ensureCenterX.constant = 0;  self.imgRecord.hidden = NO;  self.btnCamera.hidden = NO;  self.btnAfresh.hidden = YES;  self.btnEnsure.hidden = YES;  self.btnBack.hidden = NO;  [UIView animateWithDuration:0.25 animations:^{    [self.view layoutIfNeeded];  }];}/*#pragma mark - Navigation// In a storyboard-based application, you will often want to do a little preparation before navigation- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {  // Get the new view controller using [segue destinationViewController].  // Pass the selected object to the new view controller.}*/@end

使用也挺簡單:

- (IBAction)onCameraAction:(UIButton *)sender {  //額 。。由于是demo,所以用的xib,大家根據需求自己更改,該demo只是提供一個思路,使用時不要直接拖入項目  HVideoViewController *ctrl = [[NSBundle mainBundle] loadNibNamed:@"HVideoViewController" owner:nil options:nil].lastObject;  ctrl.HSeconds = 30;//設置可錄制最長時間  ctrl.takeBlock = ^(id item) {    if ([item isKindOfClass:[NSURL class]]) {      NSURL *videoURL = item;      //視頻url    } else {      //圖片    }  };  [self presentViewController:ctrl animated:YES completion:nil];}

demo地址也給出來吧:iosCamera_jb51.rar

自此就結束啦,寫的比較簡單,希望能幫助到大家,謝謝!

x效果圖也帖出來吧:

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持武林網。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
51久久精品夜色国产麻豆| 91久久国产婷婷一区二区| 国产成人精品电影| 欧美性色xo影院| 性色av一区二区三区| 在线观看欧美www| 最近2019年手机中文字幕| 少妇高潮久久久久久潘金莲| 97久久超碰福利国产精品…| 亚洲视频在线免费观看| 日韩成人网免费视频| 黑人巨大精品欧美一区二区一视频| 欧美性猛交xxxx免费看久久久| 欧美日韩人人澡狠狠躁视频| 亚洲综合一区二区不卡| 成人a在线视频| 亚洲视频axxx| 成人午夜两性视频| 亚洲欧美一区二区激情| 国产午夜精品久久久| 国产精品午夜国产小视频| 97婷婷涩涩精品一区| 国产精品2018| 中文字幕v亚洲ⅴv天堂| 国产精品69久久| 亚洲国产精品一区二区久| 欧美日韩在线免费观看| 国产日韩欧美在线| 欧美国产日本高清在线| 国产精品夜色7777狼人| 成人国产精品一区二区| 91精品国产91| 久久理论片午夜琪琪电影网| 九九久久国产精品| 黄色精品在线看| 久久精品影视伊人网| 亚洲欧美日韩视频一区| 亚洲精品久久久久久久久| 国产精品网红福利| 国产亚洲精品一区二区| 狠狠色噜噜狠狠狠狠97| 上原亚衣av一区二区三区| 日韩成人久久久| 精品亚洲va在线va天堂资源站| 最近2019好看的中文字幕免费| 色七七影院综合| 日韩欧美在线视频| 日本一区二区在线播放| 国产精品爱啪在线线免费观看| 成人精品一区二区三区电影免费| 欧美重口另类videos人妖| 欧美肥老妇视频| 日韩成人高清在线| 国产精品视频最多的网站| 91高清视频在线免费观看| 亚洲欧美变态国产另类| 亚洲视频在线观看视频| 亚洲欧美日韩精品久久奇米色影视| 亚洲人成在线一二| 国产精品午夜视频| 亚洲情综合五月天| 国产精品一二三在线| 精品一区二区三区四区在线| 久久久久久18| 国产亚洲一区二区精品| 国产福利视频一区| 这里只有精品久久| 日韩欧美在线第一页| 性色av一区二区三区在线观看| 亚洲国产女人aaa毛片在线| 欧美一级在线亚洲天堂| 538国产精品一区二区免费视频| 亚洲国产一区二区三区在线观看| 亚洲色无码播放| 国产精品日韩久久久久| 97**国产露脸精品国产| 九九久久国产精品| 亚洲石原莉奈一区二区在线观看| 98精品国产高清在线xxxx天堂| 国产精品18久久久久久麻辣| 欧美放荡办公室videos4k| 欧美多人爱爱视频网站| 在线日韩中文字幕| 日韩成人中文字幕| 69久久夜色精品国产69乱青草| 欧美激情国产高清| 久久免费视频这里只有精品| 91久久久久久久久久久| 久久色精品视频| 欧美一区视频在线| 色偷偷91综合久久噜噜| 久久五月情影视| 成人在线免费观看视视频| 亚洲国产成人爱av在线播放| 欧美性生交大片免费| 91免费国产网站| 精品久久久久久久久久久久| 久久久精品亚洲| 欧美刺激性大交免费视频| 日本欧美在线视频| 成人黄色在线免费| 国产91在线播放九色快色| 日韩欧美成人区| 亚洲2020天天堂在线观看| 91美女福利视频高清| 中文字幕最新精品| 亚洲欧美日本伦理| 日韩av免费在线| 久久久久这里只有精品| 国色天香2019中文字幕在线观看| 国内精品小视频在线观看| 亚洲区在线播放| 成人黄色av播放免费| 欧美日韩国产在线| 亚洲日本成人网| 奇米四色中文综合久久| 精品视频在线播放色网色视频| 亚洲一级黄色片| 一本色道久久综合狠狠躁篇怎么玩| 日韩在线观看免费| 日韩高清电影免费观看完整版| 中文字幕日韩av综合精品| 国产亚洲福利一区| 亚洲自拍另类欧美丝袜| 日韩h在线观看| 亚洲欧美日韩第一区| 北条麻妃一区二区在线观看| 欧美激情精品久久久久久久变态| 国产成人精品免高潮在线观看| 欧美贵妇videos办公室| 精品久久久一区二区| 国产精品亚洲自拍| 国产亚洲精品久久久久久牛牛| 日韩经典一区二区三区| 91欧美精品成人综合在线观看| 欧美肥老太性生活视频| 日韩视频在线观看免费| 日韩精品视频在线免费观看| 欧美日本亚洲视频| 日韩精品极品在线观看播放免费视频| 欧美精品免费在线观看| 国产亚洲aⅴaaaaaa毛片| 伊是香蕉大人久久| 夜夜躁日日躁狠狠久久88av| 欧美亚洲国产视频小说| 国产在线精品播放| 久久久噜噜噜久噜久久| 欧美自拍视频在线观看| 揄拍成人国产精品视频| 国产丝袜视频一区| 久久久久九九九九| 久久久久99精品久久久久| 自拍偷拍免费精品| 国产精品国产三级国产专播精品人| 97超级碰在线看视频免费在线看| 亚洲曰本av电影| 国产视频精品va久久久久久| 91高清视频在线免费观看| 亚洲欧美日韩第一区| 国产精品视频内| 97久久久免费福利网址| 国内偷自视频区视频综合| 国语自产偷拍精品视频偷| 欧美激情在线视频二区|