zoukankan      html  css  js  c++  java
  • AVFoundation的使用

    AVFoundation的使用  

    2013-05-03 14:50:21|  分类: iphone_dev_note|举报|字号 订阅

     
     
    AVFoundation的使用 - 阿帕奇 - XGG  XGG
     
    AVFoundation的使用 - 阿帕奇 - XGG  XGG
     
     
    相机相关应用一般会用到AVFoundation. 这里简单做个整理。
     
    1. session
    AVFoundation是基于session(会话)概念的。 一个session用于控制数据从input设备到output设备的流向。
     
    声明一个session:
    AVCaptureSession *session = [[AVCaptureSession alloc] init];
     
    session允许定义音频视频录制的质量。
    [session setSessionPreset:AVCaptureSessionPresetLow];
     
    2. capture device
    定义好session后,就该定义session所使用的设备了。(使用AVMediaTypeVideo 来支持视频和图片)
    AVCaptureDevice *captureDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
     
    3. capture device input
    有了capture device, 然后就获取其input capture device, 并将该input device加到session上。
    AVCaptureDeviceInput *deviceInput = [AVCaptureDeviceInput deviceInputWithDevice:captureDevice error:&error];
    if ( [session canAddInput:deviceInput] )
        [session addInput:deviceInput];
     
    4. preview
    在定义output device之前,我们可以先使用preview layer来显示一下camera buffer中的内容。这也将是相机的“取景器”。
    AVCaptureVideoPreviewLayer可以用来快速呈现相机(摄像头)所收集到的原始数据。
    我们使用第一步中定义的session来创建preview layer, 并将其添加到main view layer上。
    AVCaptureVideoPreviewLayer *previewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:session]; 
    [previewLayer setVideoGravity:AVLayerVideoGravityResizeAspectFill];
     
    CALayer *rootLayer = [[self view] layer];
    [rootLayer setMasksToBounds:YES];
    [previewLayer setFrame:CGRectMake(-70, 0, rootLayer.bounds.size.height, rootLayer.bounds.size.height)];
    [rootLayer insertSublayer:previewLayer atIndex:0];
     
    5. start Run
    最后需要start the session.
    [session startRunning];
     
     
    ==============以下内容为“对视频进行实时处理”部分================
     
    6. the output buffer
    如果向对视频进行实时处理,则需要直接对camera buffer中的视频流进行处理。
    首先我们定义一个视频数据输出(AVCaptureVideoDataOutput), 并将其添加到session上。
    AVCaptureVideoDataOutput *dataOutput = [AVCaptureVideoDataOutput new];
    dataOutput.videoSettings = [NSDictionary dictionaryWithObject:[NSNumber numberWithUnsignedInt:kCVPixelFormatType_420YpCbCr8BiPlanarFullRange] forKey:(NSString *)kCVPixelBufferPixelFormatTypeKey];
    [dataOutput setAlwaysDiscardsLateVideoFrames:YES];
     
    if ( [captureSession canAddOutput:dataOutput]
        [captureSession addOutput:dataOutput];
     
     
    7. the destination layer
    若要显示实时处理后的视频效果,则需要自己创建一个layer(不能用AVCaptureVideoPreviewLayer),并将该labor添加到view.layer上。
    CALayer *customPreviewLayer = [CALayer layer];
    customPreviewLayer.bounds = CGRectMake(0, 0, self.view.frame.size.height, self.view.frame.size.width);
    customPreviewLayer.position = CGPointMake(self.view.frame.size.width/2., self.view.frame.size.height/2.);
    customPreviewLayer.affineTransform = CGAffineTransformMakeRotation(M_PI/2);
    [self.view.layer addSublayer:customPreviewLayer];
     
     
    8. 设置sampleBuffer的代理
    设置我们自己的controller作为视频数据输出缓冲区(sample buffer)的代理
    dispatch_queue_t queue = dispatch_queue_create("VideoQueue", DISPATCH_QUEUE_SERIAL);
    [dataOutput setSampleBufferDelegate:self queue:queue];
     
     
    9. 视频显示
    因为已经将我们的view controller作为capture video data output的代理,所以需要在view controller中实现其代理方法:
    - (void)captureOutput:(AVCaptureOutput *)captureOutput
    didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer
            fromConnection:(AVCaptureConnection *)connection
    这样,当数据缓冲区(data buffer)一有数据时,AVFoundation就调用该方法。
    在该代理方法中,我们可以获取视频帧、处理视频帧、显示视频帧(在第七步中创建的layer中显示)了。
     
    在该代理方法中,sampleBuffer是一个Core Media对象,可以引入Core Video供使用。
    CVImageBufferRef imageBuffer =  CMSampleBufferGetImageBuffer(sampleBuffer);
     
    锁住缓冲区基地址:
    CVPixelBufferLockBaseAddress(imageBuffer, 0);
     
    然后提取一些有用的图片信息:
    size_t width = CVPixelBufferGetWidthOfPlane(imageBuffer, 0);
    size_t height = CVPixelBufferGetHeightOfPlane(imageBuffer, 0);
    size_t bytesPerRow = CVPixelBufferGetBytesPerRowOfPlane(imageBuffer, 0);
     
    视频缓冲区中是YUV格式的,要从缓冲区中提取luma部分:
    Pixel_8 *lumaBuffer = CVPixelBufferGetBaseAddressOfPlane(imageBuffer, 0);
     
    然后我们将该缓冲区的数据显示(渲染)到layer上。(为此需要 创建color space, 创建 graphic context, 使用color space将buffer渲染到graphic context)
    CGColorSpaceRef grayColorSpace = CGColorSpaceCreateDeviceGray();
    CGContextRef context = CGBitmapContextCreate(lumaBuffer, width, height, 8, bytesPerRow, grayColorSpace, kCGImageAlphaNone);
    CGImageRef dstImage = CGBitmapContextCreateImage(context);
     
    这里dstImage是core graphics image, 由captured buffer中创建而来。 最后我们将该image渲染到layer上。
    dispatch_sync(dispatch_get_main_queue(), ^{
        customPreviewLayer.contents = (__bridge id)dstImage;
    });
     
    接下来做一些清理工作就OK了。
    CGImageRelease(dstImage);
    CGContextRelease(context);
    CGColorSpaceRelease(grayColorSpace);
     
    这样取景器上的实时图像就显示出来了。(这里仅仅是对视频做提取与渲染,没有对视频做处理)
    有关对imageBuffer进行处理,需要用到GPU相关知识。
  • 相关阅读:
    EF获取DbContext中已注册的所有实体类型
    使用一阶微分对图像锐化
    数字图像处理之直方图均衡
    【HDFS】相关概念及常用命令
    【Java】ConcurrentHashMap源码解析
    【Java】对foreach循环的思考
    php生成二维码
    spilt
    strtolower
    in_array
  • 原文地址:https://www.cnblogs.com/liyufeng2013/p/3595527.html
Copyright © 2011-2022 走看看