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

首頁 > 系統 > iOS > 正文

iOS仿微信相機拍照、視頻錄制功能

2019-10-21 18:41:14
字體:
來源:轉載
供稿:網友

網上有很多自定義相機的例子,這里只是我臨時寫的一個iOS自定義相機(仿微信拍照、視頻錄制demo,僅供參考:

用到了下面幾個庫:

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

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

Privacy - Microphone Usage Description Privacy - Photo Library Usage Description Privacy - 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地址也給出來吧:不喜勿碰-_-/

KJCamera

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

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


注:相關教程知識閱讀請移步到IOS開發頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
欧美日韩另类字幕中文| 久久久久久久久久久亚洲| 日本午夜精品理论片a级appf发布| 91精品国产九九九久久久亚洲| 亚洲精品国产suv| 91久久精品美女高潮| 日韩精品极品视频免费观看| 国产亚洲欧美日韩一区二区| 亚洲第一福利网站| 亚洲电影免费观看高清完整版在线观看| 午夜精品福利视频| 中日韩美女免费视频网站在线观看| 亚洲电影免费观看高清完整版在线观看| 97涩涩爰在线观看亚洲| 成人免费网站在线观看| 日韩美女免费观看| 久久久久久久影视| 国产一区二区三区在线看| 亚洲国产成人精品女人久久久| 5278欧美一区二区三区| 丰满岳妇乱一区二区三区| 久久久久亚洲精品| 日韩美女写真福利在线观看| 中文字幕亚洲无线码在线一区| 亚洲欧美日韩另类| 欧美成人激情图片网| 国产精品高潮呻吟视频| 亚洲国产成人一区| 欧美亚洲激情视频| 国产精品国产三级国产aⅴ浪潮| 亚洲**2019国产| 日韩在线免费高清视频| 国产精品99久久久久久久久| 欧美性受xxxx黑人猛交| 亚洲天堂成人在线视频| 欧美成人黄色小视频| 欧美亚洲另类制服自拍| 亚洲综合色av| 欧美性videos高清精品| 国产一区二区三区视频免费| 欧美一区二区影院| 伊人亚洲福利一区二区三区| 久久国产精品99国产精| 国产成人中文字幕| 亚洲欧美国产一区二区三区| 亚洲字幕在线观看| 国产精品免费久久久| 亚洲第一免费网站| 亚洲a在线观看| 亚洲最大福利视频网| 国产欧美在线观看| 日韩高清电影好看的电视剧电影| 在线看片第一页欧美| 精品精品国产国产自在线| 高清视频欧美一级| 欧美极品少妇xxxxⅹ裸体艺术| 久久九九全国免费精品观看| 亚洲激情 国产| 福利精品视频在线| 精品magnet| 91精品视频网站| 久久久999成人| 26uuu另类亚洲欧美日本老年| 日韩免费黄色av| 日韩av片永久免费网站| 国产一区二区丝袜高跟鞋图片| 亚洲成年网站在线观看| 91九色单男在线观看| 九九精品在线观看| 97成人超碰免| 成人网中文字幕| 国产精品扒开腿爽爽爽视频| 久久久久久久999精品视频| 久久不射热爱视频精品| 97人洗澡人人免费公开视频碰碰碰| 亚洲久久久久久久久久久| 另类天堂视频在线观看| 亚洲人成亚洲人成在线观看| 超碰精品一区二区三区乱码| 一区二区三区黄色| 亚洲精品一区二区三区不| 久久久中精品2020中文| 亚洲欧美日韩中文在线制服| 久久综合五月天| 国产亚洲精品美女久久久| 粉嫩老牛aⅴ一区二区三区| 一本大道久久加勒比香蕉| 久久久精品中文字幕| 91精品国产综合久久久久久久久| 777精品视频| 亚洲一区二区三区视频播放| 国产精品久久激情| 亚洲第一偷拍网| 国产精品极品在线| 欧美午夜精品久久久久久久| 亚洲国产日韩精品在线| 亚洲女人天堂视频| 国产精品久久久久免费a∨大胸| 国产日韩换脸av一区在线观看| 国产女人18毛片水18精品| 日日狠狠久久偷偷四色综合免费| 欧美激情一级欧美精品| 国产极品精品在线观看| 亚洲人成电影网站色| 中文字幕一区二区精品| 狠狠爱在线视频一区| 精品久久久久久久大神国产| 亚洲精品久久久久久下一站| 97视频免费在线看| 日韩欧美在线观看视频| 亚洲欧美一区二区三区四区| 超碰91人人草人人干| 久久久久久久久久久亚洲| 国产精品免费视频xxxx| 国产91av在线| 国产精品免费久久久久影院| 日韩欧美大尺度| 亚洲在线www| 久久久久久香蕉网| 国产欧美韩国高清| 亚洲欧洲一区二区三区久久| 日本一欧美一欧美一亚洲视频| 国产精品日日做人人爱| 日韩av免费看网站| 亚洲第一区中文99精品| 成人久久18免费网站图片| 国产视频久久久久久久| 日韩禁在线播放| 欧美成人免费在线观看| 成人黄色av播放免费| 色综合男人天堂| 日韩成人在线免费观看| 亚洲天堂免费视频| 国产精品久久久久久久久久久久| 2021久久精品国产99国产精品| 国产91色在线|| 欧美亚洲日本网站| 欧美一区在线直播| 久久视频精品在线| 欧美多人乱p欧美4p久久| 久久精品成人一区二区三区| 久久亚洲精品成人| 国产成人在线一区| 精品毛片三在线观看| 欧美色另类天堂2015| 亚洲精品国产福利| 日韩欧美国产视频| 日韩精品亚洲视频| 色综合老司机第九色激情| 久久中文字幕视频| 亚洲日韩第一页| 国产精品日韩欧美综合| 色老头一区二区三区在线观看| 一道本无吗dⅴd在线播放一区| 欧美在线xxx| 亚洲国产精品va在线观看黑人| 91av在线精品| 中文字幕亚洲在线| 日韩av在线网址| 日韩中文在线视频| 久久久97精品| 日韩禁在线播放| 欧美性感美女h网站在线观看免费| 国产香蕉精品视频一区二区三区|