前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >iOS:AVCaptureSession 通过摄像头获取某一帧的画面

iOS:AVCaptureSession 通过摄像头获取某一帧的画面

作者头像
菜菜不吃蔡
发布2018-09-19 11:01:31
2.8K0
发布2018-09-19 11:01:31
举报
文章被收录于专栏:编程语言编程语言

1.配置plist

2.上代码

代码语言:javascript
复制
//
//  ViewController.m
//  newface
//
//  Created by xc on 2018/8/27.
//  Copyright © 2018年 xc. All rights reserved.
//

#import "ViewController.h"
#import <AVFoundation/AVFoundation.h>
@interface ViewController ()<AVCaptureVideoDataOutputSampleBufferDelegate>
@property (nonatomic) AVCaptureDeviceDiscoverySession *videoDeviceDiscoverySession;
@property (nonatomic,strong) UIImageView *imgview;
@end

int g_width = 0;
int g_height = 0;
int g_pitch = 0;
@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    [self setupAVCapture];
}


- (void)captureOutput:(AVCaptureOutput *)captureOutput
didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer
       fromConnection:(AVCaptureConnection *)connection
{
    //通过抽样缓存数据创建一个UIImage对象
    unsigned char* pBGRA = NULL;
    UIImage* image = [self imageFromSampleBuffer:sampleBuffer:&pBGRA];//最开始一帧图像很暗,后面就正常了
    dispatch_async(dispatch_get_main_queue(), ^{
        // 回到主线程 image为捕捉到的画面,直接使用就OK了
        self.imgview.image = image;
        
    });
}

/**
 *  相机初始化方法
 */
- (void)setupAVCapture
{
    
    _imgview = [[UIImageView alloc]init];
    _imgview.frame =CGRectMake(0, 400, 100, 100);
    [self.view addSubview:_imgview];
    
    NSError *error = nil;
    
    // 1 创建session
    AVCaptureSession *session = [AVCaptureSession new];
    // 2 设置session显示分辨率
    if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone)
        [session setSessionPreset:AVCaptureSessionPreset640x480];
    else
        [session setSessionPreset:AVCaptureSessionPresetPhoto];
    
 
    // 3 获取摄像头device,并且默认使用的后置摄像头,并且将摄像头加入到captureSession中
    AVCaptureDevice* device = [AVCaptureDevice defaultDeviceWithDeviceType:AVCaptureDeviceTypeBuiltInWideAngleCamera mediaType:AVMediaTypeVideo position:AVCaptureDevicePositionFront];
    AVCaptureDeviceInput *deviceInput = [AVCaptureDeviceInput deviceInputWithDevice:device error:&error];
    //    isUsingFrontFacingCamera = NO;
    if ([session canAddInput:deviceInput]){
        [session addInput:deviceInput];
    }
    // 4 创建预览output,设置预览videosetting,然后设置预览delegate使用的回调线程,将该预览output加入到session
    AVCaptureVideoDataOutput* videoOutput = [[AVCaptureVideoDataOutput alloc] init];
    videoOutput.alwaysDiscardsLateVideoFrames = YES;
    videoOutput.videoSettings = [NSDictionary dictionaryWithObject:[NSNumber numberWithInt:kCVPixelFormatType_32BGRA] forKey:(id)kCVPixelBufferPixelFormatTypeKey];//设置像素格式
    if ([session canAddOutput:videoOutput])
        [session addOutput:videoOutput];
    //    5 显示捕捉画面
    dispatch_queue_t queue = dispatch_queue_create("myQueue", NULL);
    [videoOutput setSampleBufferDelegate:self queue:queue];
    AVCaptureVideoPreviewLayer* preLayer = [AVCaptureVideoPreviewLayer layerWithSession: session];//相机拍摄预览图层
    preLayer.frame = CGRectMake(0, 0, 400,400);
    preLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;
    [self.view.layer addSublayer:preLayer];
    
    // 6 启动session,output开始接受samplebuffer回调
    [session startRunning];
    if (error) {
        UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:[NSString stringWithFormat:@"Failed with error %d", (int)[error code]]
                                                            message:[error localizedDescription]
                                                           delegate:nil
                                                  cancelButtonTitle:@"Dismiss"
                                                  otherButtonTitles:nil];
        [alertView show];
        
    }
}

// 通过抽样缓存数据创建一个UIImage对象
- (UIImage *) imageFromSampleBuffer:(CMSampleBufferRef) sampleBuffer:(unsigned char**) pBGRA
{
    // 为媒体数据设置一个CMSampleBuffer的Core Video图像缓存对象
    CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);
    // 锁定pixel buffer的基地址
    CVPixelBufferLockBaseAddress(imageBuffer, 0);
    
    // 得到pixel buffer的基地址
    void *baseAddress = CVPixelBufferGetBaseAddress(imageBuffer);
    
    // 得到pixel buffer的行字节数
    size_t bytesPerRow = CVPixelBufferGetBytesPerRow(imageBuffer);
    // 得到pixel buffer的宽和高
    size_t width = CVPixelBufferGetWidth(imageBuffer);
    size_t height = CVPixelBufferGetHeight(imageBuffer);
    g_width = width;
    g_height = height;
    g_pitch = bytesPerRow;
    //return (unsigned char*)baseAddress;
    *pBGRA = (unsigned char*)malloc(g_pitch*g_height);
    memcpy(*pBGRA, baseAddress, g_pitch*g_height);
    // 创建一个依赖于设备的RGB颜色空间
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    
    // 用抽样缓存的数据创建一个位图格式的图形上下文(graphics context)对象
    CGContextRef context = CGBitmapContextCreate(baseAddress, width, height, 8,
                                                 bytesPerRow, colorSpace, kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst);
    //   unsigned char* pBGRA = CGBitmapContextGetData(context);
    //   return pBGRA;
    
    
    
    // 根据这个位图context中的像素数据创建一个Quartz image对象
    CGImageRef quartzImage = CGBitmapContextCreateImage(context);
    // 解锁pixel buffer
    CVPixelBufferUnlockBaseAddress(imageBuffer,0);
    
    // 释放context和颜色空间
    CGContextRelease(context);
    CGColorSpaceRelease(colorSpace);
    
    // 用Quartz image创建一个UIImage对象image
    UIImage *image = [UIImage imageWithCGImage:quartzImage];
    
    // 释放Quartz image对象
    CGImageRelease(quartzImage);
    
    return (image);
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}


@end

over,有用到请点赞谢谢

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2018年08月27日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档