iOS分屏相機(jī)實(shí)現(xiàn)

話不多說首先上效果圖

WechatIMG7.png

原理:
屏幕的左半部分為AVCaptureVideoPreviewLayer
而右半部分則為UIImageView

代碼

遵循<AVCaptureVideoDataOutputSampleBufferDelegate>協(xié)議

//捕獲設(shè)備,通常是前置攝像頭,后置攝像頭,麥克風(fēng)(音頻輸入)
@property (nonatomic, strong) AVCaptureDevice *device;
//AVCaptureDeviceInput 代表輸入設(shè)備,他使用AVCaptureDevice 來初始化
@property (nonatomic, strong) AVCaptureDeviceInput *input;
//輸出圖片
@property (nonatomic ,strong) AVCaptureVideoDataOutput *imageOutput;
//session:由他把輸入輸出結(jié)合在一起,并開始啟動(dòng)捕獲設(shè)備(攝像頭)
@property (nonatomic, strong) AVCaptureSession *session;
//圖像預(yù)覽層,實(shí)時(shí)顯示捕獲的圖像
@property (nonatomic ,strong) AVCaptureVideoPreviewLayer *previewLayer;
@property (strong, nonatomic) UIImageView *outputImageView;
@property (strong, nonatomic) UIView *leftView;

- (void)cameraDistrict
{
    //    AVCaptureDevicePositionBack  后置攝像頭
    //    AVCaptureDevicePositionFront 前置攝像頭
    self.device = [self cameraWithPosition:AVCaptureDevicePositionBack];
    self.input = [[AVCaptureDeviceInput alloc] initWithDevice:self.device error:nil];

    self.imageOutput = [[AVCaptureVideoDataOutput alloc]init];
    self.imageOutput.alwaysDiscardsLateVideoFrames = YES;

    dispatch_queue_t queue;
    queue = dispatch_queue_create("cameraQueue", NULL);
    [self.imageOutput setSampleBufferDelegate:self queue:queue];

    NSString* key = (NSString*)kCVPixelBufferPixelFormatTypeKey;
    NSNumber* value = [NSNumber numberWithUnsignedInt:kCVPixelFormatType_32BGRA];
    NSDictionary* videoSettings = [NSDictionary dictionaryWithObject:value forKey:key];
    [self.imageOutput setVideoSettings:videoSettings];

    self.session = [[AVCaptureSession alloc] init];
    //     拿到的圖像的大小可以自行設(shè)定
    //    AVCaptureSessionPreset320x240
    //    AVCaptureSessionPreset352x288
    //    AVCaptureSessionPreset640x480
    //    AVCaptureSessionPreset960x540
    //    AVCaptureSessionPreset1280x720
    //    AVCaptureSessionPreset1920x1080
    //    AVCaptureSessionPreset3840x2160
    self.session.sessionPreset = AVCaptureSessionPreset640x480;
    //輸入輸出設(shè)備結(jié)合
    if ([self.session canAddInput:self.input]) {
        [self.session addInput:self.input];
    }
    if ([self.session canAddOutput:self.imageOutput]) {
        [self.session addOutput:self.imageOutput];
    }
    //預(yù)覽層的生成
    self.previewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:self.session];
    self.previewLayer.frame = self.leftView.bounds;

    self.previewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;
    [[self.previewLayer connection]setVideoOrientation:AVCaptureVideoOrientationLandscapeRight];
    [self.leftView.layer addSublayer:self.previewLayer];

    _outputImageView = [[UIImageView alloc]init];
    _outputImageView.contentMode = UIViewContentModeScaleAspectFill;
    _outputImageView.clipsToBounds = YES;
    [self.view addSubview:_outputImageView];

    _outputImageView.sd_layout
    .leftSpaceToView(self.leftView, 0)
    .rightSpaceToView(self.view, 0)
    .topSpaceToView(self.view, 0)
    .bottomSpaceToView(self.view, 0);

    //設(shè)備取景開始
    [self.session startRunning];
    if ([_device lockForConfiguration:nil]) {
        //自動(dòng)閃光燈,
        if ([_device isFlashModeSupported:AVCaptureFlashModeAuto]) {
            [_device setFlashMode:AVCaptureFlashModeAuto];
        }
        //自動(dòng)白平衡,但是好像一直都進(jìn)不去
        if ([_device isWhiteBalanceModeSupported:AVCaptureWhiteBalanceModeAutoWhiteBalance]) {
            [_device setWhiteBalanceMode:AVCaptureWhiteBalanceModeAutoWhiteBalance];
        }
        [_device unlockForConfiguration];
    }

}

- (AVCaptureDevice *)cameraWithPosition:(AVCaptureDevicePosition)position{
    NSArray *devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo];
    for ( AVCaptureDevice *device in devices )
        if ( device.position == position ){
            return device;
        }
    return nil;
}

- (AVCaptureVideoOrientation) videoOrientationFromCurrentDeviceOrientation {

    switch (self.interfaceOrientation) {
        case UIInterfaceOrientationPortrait: {
            return AVCaptureVideoOrientationPortrait;
        }
        case UIInterfaceOrientationLandscapeLeft: {
            return AVCaptureVideoOrientationLandscapeLeft;
        }
        case UIInterfaceOrientationLandscapeRight: {
            return AVCaptureVideoOrientationLandscapeRight;
        }
        case UIInterfaceOrientationPortraitUpsideDown: {
            return AVCaptureVideoOrientationPortraitUpsideDown;
        }
        case UIInterfaceOrientationUnknown: {
            break;
        }
    }

    return AVCaptureVideoOrientationLandscapeLeft;
}

#pragma mark AVCaptureSession delegate
/**
將sampleBuffer轉(zhuǎn)換成image并繪制在右側(cè)ImageView上
*/
- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection{
    CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);
    CVPixelBufferLockBaseAddress(imageBuffer,0);
    uint8_t *baseAddress = (uint8_t *)CVPixelBufferGetBaseAddress(imageBuffer);
    size_t bytesPerRow = CVPixelBufferGetBytesPerRow(imageBuffer);
    size_t width = CVPixelBufferGetWidth(imageBuffer);
    size_t height = CVPixelBufferGetHeight(imageBuffer);

    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    CGContextRef newContext = CGBitmapContextCreate(baseAddress,width, height, 8, bytesPerRow, colorSpace,kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst);
    CGImageRef newImage = CGBitmapContextCreateImage(newContext);
    CGContextRelease(newContext);
    CGColorSpaceRelease(colorSpace);

    UIImage *image= [UIImage imageWithCGImage:newImage scale:1.0 orientation:UIImageOrientationUp];
    CGImageRelease(newImage);
    [_outputImageView performSelectorOnMainThread:@selector(setImage:) withObject:image waitUntilDone:YES];
    CVPixelBufferUnlockBaseAddress(imageBuffer,0);
}

隱藏系統(tǒng)的音量調(diào)節(jié)窗口

    AVAudioSession *audio = [AVAudioSession sharedInstance];
    [audio setActive:YES error:nil];
    MPVolumeView *volumeView = [[MPVolumeView alloc]initWithFrame:CGRectMake(-2000, -2000, 10, 10)];
    volumeView.hidden = NO;
    [self.view addSubview:volumeView];

監(jiān)聽系統(tǒng)音量調(diào)節(jié)事件

    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(volumeClicked:) name:@"AVSystemController_SystemVolumeDidChangeNotification" object:nil];
//    但是僅僅監(jiān)聽是不起作用的,因?yàn)锧"AVSystemController_SystemVolumeDidChangeNotification"需要對(duì)它進(jìn)行響應(yīng),所以要在監(jiān)聽后加
    [[UIApplication sharedApplication] beginReceivingRemoteControlEvents];

根據(jù)音量加減來調(diào)節(jié)相機(jī)焦距

-(void)volumeClicked:(NSNotification *)noti{

    //1.0~67.5
    CGFloat zoom = self.device.videoZoomFactor;

    NSLog(@"%.f",zoom);

    NSDictionary *userInfo = [noti userInfo];
    CGFloat volume = [[userInfo valueForKey:@"AVSystemController_AudioVolumeNotificationParameter"]floatValue];

    if (volume == 1.0 && self.volume == 1.0) {//增加到最大了

        zoom += 0.25;

    }else if (volume == 0.0 && self.volume == 0.0)//減小到最小了
    {
        zoom -= 0.25;

    }else if(volume > self.volume)//++
    {
        zoom += 0.25;

        self.volume = volume;

    }else if (volume < self.volume)//--
    {

        self.volume = volume;
        zoom -= 0.25;

    }

    NSError *error = nil;
    if (zoom < 1 || zoom > 30) {
        return;
    }
    [self.device lockForConfiguration:&error];
    if (!error) {
        self.device.videoZoomFactor = zoom;
    }else
    {
        NSLog(@"error = %@", error);
    }
    [self.device unlockForConfiguration];
}

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫、插件、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 15,291評(píng)論 4 61
  • 冬天來了,對(duì)每一個(gè)父母來講,早上叫孩子起床都是一件困難的事情,有很多時(shí)候因?yàn)樵绯扛改附泻⒆悠鸫策@件事,使得孩子和父...
    重塑自我999閱讀 817評(píng)論 2 16
  • 重要的話不只要說三遍,最好天天說,人都很自戀,為了不辜負(fù)天天說的話,他會(huì)按照這個(gè)話去做,這便是“自證預(yù)言”,也可以...
    心靈的便簽閱讀 334評(píng)論 0 2
  • 我在失業(yè)一個(gè)月后。 亂找工作的一個(gè)月后。 天天心焦的一個(gè)月后。 收拾了行李箱,奔赴了另一個(gè)城市,僅僅是因?yàn)橛幸粋€(gè)符...
    貍光閱讀 531評(píng)論 0 0
  • 自家的偶像變成迷弟是一種怎樣的感受,詳情可以參考李易峰在優(yōu)酷熱播綜藝《這就是灌籃》里的表現(xiàn)。 第一次參加常駐綜藝的...
    萌叉叉大人閱讀 446評(píng)論 0 0

友情鏈接更多精彩內(nèi)容