iOS开发

UIImageView显示视频流

2017-04-05  本文已影响801人  逆风g

最近有个功能需要拿到视频流的帧转换成图片,对图片做处理再显示出来。先了解AVFoundation的一些基本类,后面会贴上代码,也会把遇到的坑写出来。

关键类
输出类

需要的功能不同,用到的数据输出管理对象也不同。

初始化
-(void)viewDidLoad
{
    AVCaptureSession *session = [[AVCaptureSession alloc] init];
    [session setSessionPreset:AVCaptureSessionPreset640x480];

    
    AVCaptureDevice *captureDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
    AVCaptureDeviceInput *deviceInput = [AVCaptureDeviceInput deviceInputWithDevice:captureDevice error:nil];
    if ( [session canAddInput:deviceInput] )
        [session addInput:deviceInput];
    AVCaptureVideoPreviewLayer *previewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:session];
    [previewLayer setVideoGravity:AVLayerVideoGravityResizeAspectFill];
    
    
    AVCaptureVideoDataOutput *dataOutput = [AVCaptureVideoDataOutput new];
    //一定得注意这个值kCVPixelBufferPixelFormatTypeKey 不然后面的sampleBuffer会有问题的
    dataOutput.videoSettings = [NSDictionary dictionaryWithObject:[NSNumber numberWithUnsignedInt:kCVPixelFormatType_32BGRA] forKey:(NSString *)kCVPixelBufferPixelFormatTypeKey];
    [dataOutput setAlwaysDiscardsLateVideoFrames:YES];
    if ( [session canAddOutput:dataOutput])
        [session addOutput:dataOutput];
    dispatch_queue_t queue =dispatch_queue_create("VideoDataOutputQueue", DISPATCH_QUEUE_SERIAL);
    [dataOutput setSampleBufferDelegate:self queue:queue];
    //设置方向
    for (AVCaptureVideoDataOutput* output in session.outputs) {
        for (AVCaptureConnection * av in output.connections) {
            av.videoOrientation = UIDeviceOrientationPortrait;
        }
    }
    
    //不加这个代理回调只执行一次
    CALayer *rootLayer = [[self view] layer];
    [rootLayer setMasksToBounds:YES];
    [previewLayer setFrame:CGRectMake(0, 0, rootLayer.bounds.size.width, rootLayer.bounds.size.height)];
    [rootLayer insertSublayer:previewLayer atIndex:0];
    
    [session startRunning];
}

代理协议回调

- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection
{
    CVImageBufferRef imageBuffer =  CMSampleBufferGetImageBuffer(sampleBuffer);
    CVPixelBufferLockBaseAddress(imageBuffer, 0);
    
    uint8_t *baseAddress =CVPixelBufferGetBaseAddress(imageBuffer);
    size_t width = CVPixelBufferGetWidthOfPlane(imageBuffer, 0);
    size_t height = CVPixelBufferGetHeightOfPlane(imageBuffer, 0);
    size_t bytesPerRow = CVPixelBufferGetBytesPerRowOfPlane(imageBuffer, 0);
    CGColorSpaceRef colorSpace= CGColorSpaceCreateDeviceRGB();
    CGContextRef cgContext= CGBitmapContextCreate(baseAddress, width, height, 8, bytesPerRow, colorSpace, kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst);

    CGImageRef cgImage = CGBitmapContextCreateImage(cgContext);
    UIImage *image=[UIImage imageWithCGImage:cgImage];
    dispatch_sync(dispatch_get_main_queue(), ^{
//        self.imageView.layer.contents = (__bridge id _Nullable)(cgImage);
            self.imageView.image=image;
    });

    CGImageRelease(cgImage);
    CGContextRelease(cgContext);
    CVPixelBufferUnlockBaseAddress(imageBuffer, 0);
}
遇到的坑
 for (AVCaptureVideoDataOutput* output in session.outputs) {
        for (AVCaptureConnection * av in output.connections) {
            av.videoOrientation = UIDeviceOrientationPortrait;
        }
    }

最后想说一句,网上CMSampleBufferRef转UIImage的例子有很多,直接拿过来回发现获取不到图片,官网的代码也是如此,不是这些代码有问题,而是可能自己的某些设置有问题,就像我遇到的那些坑。实在获取不到图片的话,使用下面的代码吧:

    CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);
    CIImage *ciImage=[CIImage imageWithCVPixelBuffer:imageBuffer];
    UIImage *image=[UIImage imageWithCIImage:ciImage];

这种方法生成的图片不能获取到NSData,或者用

    CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);
    CIImage *ciImage=[CIImage imageWithCVPixelBuffer:imageBuffer];
    CGImageRef cgImage=[[[CIContext alloc]init] createCGImage:ciImage fromRect:[ciImage extent]];
    UIImage *image=[UIImage imageWithCGImage:cgImage];
上一篇 下一篇

猜你喜欢

热点阅读