iOS - AVFoundation - 自定义相机界面

Snip20170312_4.png

使用系统提供的UIImagePickerController可以实现基本的拍照和录制视频的功能,但是很多时候从UI那边拿到的设计图都是和系统的不一样的,我们需要自定义相机的界面。

大概思路

1.根据UI的设计图,把基本的界面先搭建出来(感觉是废话⊙o⊙)。
2.使用AVFoundation必须的几个东西 -device,input,output,session,connection,previewLayer
3.按钮点击之后的逻辑处理 - 闪光灯,前后摄像头的切换等

主要的内容就是AVFoundation的使用

//1.获取device(audio,video)
//2.根据device创建input
//3.创建输出output(下面图片是输出的方式,共7种)
//4.创建全局的会话session,并且把输入和输出都添加到session中,统一管理
//5.如果需要实时的显示,就用AVCaptureVideoPreviewLayer预览图层来显示

图片还是视频区别在于输出output的不同

14881125871512.jpg

直接上代码

//

#import "CustomCameraVC.h"
#import "UIControl+BlocksKit.h"
#import "UIView+YGYAdd.h"
#import <AVFoundation/AVFoundation.h>

#define kScreenWidth [UIScreen mainScreen].bounds.size.width
#define kScreenHeight [UIScreen mainScreen].bounds.size.height
@interface CustomCameraVC () <AVCapturePhotoCaptureDelegate>

//UI界面搭建
@property (nonatomic, strong) UIView *topView;
@property (nonatomic, strong) UIButton *closeButton;
@property (nonatomic, strong) UIButton *flashModeButton;
@property (nonatomic, strong) UIButton *cameraButton;

@property (nonatomic, strong) UIView *middleView;

@property (nonatomic, strong) UIView *bottomView;
@property (nonatomic, strong) UIButton *albumButton;
@property (nonatomic, strong) UIButton *takePhotoButton;
@property (nonatomic, strong) UIButton *musicButton;

//自定义相机(AVFoundation)
@property (nonatomic, strong) AVCaptureSession *session;
@property (nonatomic, strong) AVCaptureDevice *device;
@property (nonatomic, strong) AVCaptureDeviceInput *input;
@property (nonatomic, strong) AVCaptureStillImageOutput *output;
@property (nonatomic, strong) AVCaptureConnection *connection;
@property (nonatomic, strong) AVCaptureVideoPreviewLayer *preViewLayer;

@property (nonatomic, strong) NSArray *flashModelArray;
@property (nonatomic, assign) NSInteger flashModel;
@end

@implementation CustomCameraVC

- (void)viewDidLoad {
    [super viewDidLoad];
    _flashModelArray = @[@"icon-pz-sgd-gb",@"icon-pz-sgd-zd",@"icon-pz-sgd"];
    _flashModel = 0;
    
    [self setupUI];
    [self customCamera];
}

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    [_session startRunning];
}

- (void)viewWillDisappear:(BOOL)animated {
    [super viewWillDisappear:animated];
    [_session stopRunning];
}


- (void)setupUI {
    //顶部UI
    [self makeTopUI];
    //中间预览图层
    [self makeMiddleUI];
    //底部UI
    [self makeBottomUI];
}

- (void)viewWillLayoutSubviews {
    [super viewWillLayoutSubviews];
    //---top
    
    _topView.frame = CGRectMake(0, 0, kScreenWidth, kScreenHeight*0.2);
    _closeButton.frame = CGRectMake(0, 0, 50, 50);
    _closeButton.centerY = _topView.centerY;
    
    _flashModeButton.frame = CGRectMake(0, 0, 50, 50);
    _flashModeButton.center = _topView.center;
    
    _cameraButton.frame = CGRectMake(0, 0, 50, 50);
    _cameraButton.centerY = _topView.centerY;
    _cameraButton.right = _topView.right;
    
    
    //---middle
    
    _middleView.frame = CGRectMake(0, CGRectGetMaxY(_topView.frame), kScreenWidth, kScreenHeight*0.6);
    _preViewLayer.frame = _middleView.bounds;
    
    //---bottom
    
    _bottomView.frame = CGRectMake(0, CGRectGetMaxY(_middleView.frame), kScreenWidth, kScreenHeight*0.2);
    _albumButton.frame = CGRectMake(0, 0, 50, 50);
//    _albumButton.centerY = _bottomView.centerY;//不能这么写,超出父控件
    _albumButton.centerY = _bottomView.height*0.5;
    
    _takePhotoButton.frame = CGRectMake(0, 0, 50, 50);
//    _takePhotoButton.center = _bottomView.center;
    _takePhotoButton.center = CGPointMake(_bottomView.width*0.5, _bottomView.height*0.5);
    
    _musicButton.frame = CGRectMake(0, 0, 50, 50);
//    _musicButton.centerY = _bottomView.centerY;
    _musicButton.centerY = _bottomView.height*0.5;
    _musicButton.right = _bottomView.right;
    
}

- (void)makeTopUI {
    _topView = [[UIView alloc] init];
    _topView.backgroundColor = [UIColor grayColor];
    
    
    _closeButton = [[UIButton alloc] init];
    [_closeButton setImage:[UIImage imageNamed:@"icon-pz-exit"] forState:UIControlStateNormal];
    [_closeButton bk_addEventHandler:^(id  _Nonnull sender) {
        //关闭控制器
        [self dismissViewControllerAnimated:YES completion:nil];
    } forControlEvents:UIControlEventTouchUpInside];
    
    
    _flashModeButton = [[UIButton alloc] init];
    [_flashModeButton setImage:[UIImage imageNamed:@"icon-pz-sgd"] forState:UIControlStateNormal];
    [_flashModeButton bk_addEventHandler:^(id  _Nonnull sender) {
        //切换闪光灯的模式
        //    icon-pz-sgd-zd
        [self changeFlashModel];
    } forControlEvents:UIControlEventTouchUpInside];
    
    _cameraButton = [[UIButton alloc] init];
    [_cameraButton setImage:[UIImage imageNamed:@"icon-pz-fz"] forState:UIControlStateNormal];
    [_cameraButton bk_addEventHandler:^(id  _Nonnull sender) {
        //切换前后摄像头
        [self changeCamera];
    } forControlEvents:UIControlEventTouchUpInside];
    
    
    [_topView addSubview:_closeButton];
    [_topView addSubview:_flashModeButton];
    [_topView addSubview:_cameraButton];
    
    [self.view addSubview:_topView];
    
}

- (void)makeMiddleUI {
    _middleView = [[UIView alloc] init];
    [self.view addSubview:_middleView];
}

- (void)makeBottomUI {
    _bottomView = [[UIView alloc] init];
    _bottomView.backgroundColor = [UIColor grayColor];
    [self.view addSubview:_bottomView];
    
    _albumButton = [[UIButton alloc] init];
    [_albumButton setImage:[UIImage imageNamed:@"icon-pz-TP"] forState:UIControlStateNormal];
    [_albumButton bk_addEventHandler:^(id  _Nonnull sender) {
        //从相册选取
    } forControlEvents:UIControlEventTouchUpInside];
    
    _takePhotoButton = [[UIButton alloc] init];
    [_takePhotoButton setImage:[UIImage imageNamed:@"icon-pz-pz"] forState:UIControlStateNormal];
    [_takePhotoButton bk_addEventHandler:^(id  _Nonnull sender) {
        [self takePhoto];
    } forControlEvents:UIControlEventTouchUpInside];
    
    _musicButton = [[UIButton alloc] init];
    [_musicButton setImage:[UIImage imageNamed:@"icon-pz-music"] forState:UIControlStateNormal];
    [_musicButton bk_addEventHandler:^(id  _Nonnull sender) {
        //音频选择
    } forControlEvents:UIControlEventTouchUpInside];
    
    [_bottomView addSubview:_albumButton];
    [_bottomView addSubview:_takePhotoButton];
    [_bottomView addSubview:_musicButton];
    
}

- (void)customCamera {
    _session = [[AVCaptureSession alloc] init];
    
    _device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];

    NSError *error = nil;
    _input = [[AVCaptureDeviceInput alloc] initWithDevice:_device error:&error];

    if (error) {
        NSLog(@"创建输入设备失败 -- %@",error);
        return;
    }
    
    AVCaptureStillImageOutput *output = [[AVCaptureStillImageOutput alloc] init];
    _output = output;
//    _connection = [output connectionWithMediaType:AVMediaTypeVideo];//千万不要在这里获取,输入和输出都没有加入session,所以获取的connection始终是nil

    if ([_session canSetSessionPreset:AVCaptureSessionPreset1280x720]) {
        [_session setSessionPreset:AVCaptureSessionPreset1280x720];
    }
    
    if ([_session canAddInput:_input]) {
        [_session addInput:_input];
    }else {
        NSLog(@"添加输入设备失败");
        return;
    }
    
    if ([_session canAddOutput:output]) {
        [_session addOutput:output];
    }else {
        NSLog(@"添加输出设备失败");
        return;
    }
    
    
    AVCaptureVideoPreviewLayer *layer = [AVCaptureVideoPreviewLayer layerWithSession:_session];
    layer.videoGravity = AVLayerVideoGravityResizeAspectFill ;
    _preViewLayer = layer;
    [_middleView.layer addSublayer:layer];
}

- (void)takePhoto {//拍照就是从输出(output)从connection中获取一张图片
    _connection = [_output connectionWithMediaType:AVMediaTypeVideo];
    [_output captureStillImageAsynchronouslyFromConnection:_connection completionHandler:^(CMSampleBufferRef imageDataSampleBuffer, NSError *error) {
        if (imageDataSampleBuffer) {
            NSData *data = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageDataSampleBuffer];
            UIImage *image = [UIImage imageWithData:data];
            //显示还是存储到相册的逻辑
            NSLog(@"%@",image);
        }
    }];
}

- (void)changeCamera {//切换摄像头 - input改变
    NSArray *devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo];
    for (int i = 0; i < devices.count; ++i) {
        AVCaptureDevice *device = devices[i];
        
        if (_device.position != device.position) {
            _device = device;
            break;//找到就不要再找,逻辑就不对了
        }
    }
    NSError *error = nil;
    AVCaptureDeviceInput *newInput = [AVCaptureDeviceInput deviceInputWithDevice:_device error:&error];

    if (error) {
        NSLog(@"创建输入设备失败 -- %@",error);
        return;
    }
    [_session beginConfiguration];
    [_session removeInput:_input];
    if ([_session canAddInput:newInput]) {
        [_session addInput:newInput];
        _input = newInput;
    }
    
    [_session commitConfiguration];
    
}

- (void)changeFlashModel {
    //FlashModel是输入设备的属性,不需要使用session
    
    if ([_device hasFlash]) {//必须判断,否则前置摄像头的时候就会奔溃
        [_device lockForConfiguration:nil];
        [_device setFlashMode:_flashModel++ % 3];//注意:闪关灯不是手电筒,只有拍的时候才会亮 
        [_device unlockForConfiguration];
        [_flashModeButton setImage:[UIImage imageNamed:_flashModelArray[_flashModel % 3]] forState:UIControlStateNormal];
    }
    
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,911评论 5 460
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,014评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 142,129评论 0 320
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,283评论 1 264
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,159评论 4 357
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,161评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,565评论 3 382
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,251评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,531评论 1 292
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,619评论 2 310
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,383评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,255评论 3 313
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,624评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,916评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,199评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,553评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,756评论 2 335

推荐阅读更多精彩内容