温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

iOS如何实现自定义相机

发布时间:2021-07-08 18:22:34 来源:亿速云 阅读:746 作者:小新 栏目:移动开发

这篇文章主要为大家展示了“iOS如何实现自定义相机”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“iOS如何实现自定义相机”这篇文章吧。

用到了下面几个库:

#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地址也给出来吧:iosCamera_jb51.rar

自此就结束啦,写的比较简单,希望能帮助到大家,谢谢!

x效果图也帖出来吧:

iOS如何实现自定义相机

以上是“iOS如何实现自定义相机”这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注亿速云行业资讯频道!

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

ios
AI