使用AVCapTureSession 获取每一帧sampleBuffer

定义 全局 变量

  ///设备协调输入输出中心

    AVCaptureSession *_captureSession;

    ///设备

    AVCaptureDevice *_captureDevice;

    /// 输入源

    AVCaptureDeviceInput *_videoCaptureDeviceInput;

    AVCaptureDeviceInput *_audioCaptureDeviceInput;

    

    ///  视频输出

    AVCaptureVideoDataOutput *_captureVideoDataOutput;

    /// 音频输出

    AVCaptureAudioDataOutput *_captureAudioDataOutput;

    /// 队列

    dispatch_queue_t my_Queue;

    /// 视频 连接

    AVCaptureConnection *_videoConnection;

    /// 音频连接

    AVCaptureConnection *_audioConnection; 

   // 用来显示 每一帧的 imageview

    UIImageView *bufferImageView;

 

 

 

 

//写入路径

@property(nonatomic,copy)NSString *path;

 

/// 写入

@property(nonatomic,strong)AVAssetWriter *assetWriter;

@property(nonatomic,strong) AVAssetWriterInputPixelBufferAdaptor *adaptor;

 

/// 视频写入

@property(nonatomic,strong)AVAssetWriterInput *videoInput;

/// 音频写入

@property(nonatomic,strong)AVAssetWriterInput *audioInput;

 

 

 

 

- (void)initDevice {

    bufferImageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 64, 375, 375)];

    [self.view addSubview:bufferImageView];

 

    _captureSession = [[AVCaptureSession alloc] init];

    if ([_captureSession canSetSessionPreset:AVCaptureSessionPreset640x480]) {

        [_captureSession setSessionPreset:AVCaptureSessionPreset640x480];

    }

    // 获取后置 摄像头   

    _captureDevice = [self backCamera];

  // 音频输入

    AVCaptureDevice *audioCaptureDevice = [[AVCaptureDevice devicesWithMediaType:AVMediaTypeAudio] firstObject];

    

    _audioCaptureDeviceInput = [[AVCaptureDeviceInput alloc] initWithDevice:audioCaptureDevice error:nil];

    //视频输入

    _videoCaptureDeviceInput = [AVCaptureDeviceInput deviceInputWithDevice:_captureDevice error:nil];

    

    [_captureSession addInput:_videoCaptureDeviceInput];

    [_captureSession addInput:_audioCaptureDeviceInput];

    

    [_captureDevice lockForConfiguration:nil];

    [_captureDevice setActiveVideoMaxFrameDuration:CMTimeMake(1,15)];

    [_captureDevice setActiveVideoMinFrameDuration:CMTimeMake(1,15)];

    [_captureDevice unlockForConfiguration];

    

    

    

    // 视频输出

    _captureVideoDataOutput = [[AVCaptureVideoDataOutput alloc] init];

    _captureVideoDataOutput.videoSettings = [NSDictionary dictionaryWithObject:[NSNumber numberWithInt:kCVPixelFormatType_32BGRA]

                                                                        forKey:(id)kCVPixelBufferPixelFormatTypeKey];

    [_captureSession addOutput:_captureVideoDataOutput];

    my_Queue = dispatch_queue_create("myqueue", NULL);

    [_captureVideoDataOutput setSampleBufferDelegate:self queue:my_Queue];

    _captureVideoDataOutput.alwaysDiscardsLateVideoFrames = YES;

    

    

    // 音频输出

    _captureAudioDataOutput = [[AVCaptureAudioDataOutput alloc] init];

    [_captureAudioDataOutput setSampleBufferDelegate:self queue:my_Queue];

    [_captureSession addOutput:_captureAudioDataOutput];

    

    /// 视频连接

    _videoConnection = [_captureVideoDataOutput connectionWithMediaType:AVMediaTypeVideo];

    _videoConnection.videoOrientation = AVCaptureVideoOrientationPortrait;

    /// 音频连接

    _audioConnection = [_captureAudioDataOutput connectionWithMediaType:AVMediaTypeAudio];

    [_captureSession startRunning];

 

/// 创建的时候 最好调用一下 切换前后 摄像头,这样进来 从samplebuffer转化的iamge都是向左旋转了90度,不知道为什么,好像是因为 苹果默认横向录 是正方向,以后有机会再解决

}

 实现代理

- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection{

   

    if (captureOutput == _captureVideoDataOutput) { // 只有是视频帧 过来才操作

        CFRetain(sampleBuffer);

  // 把samplebuffer 转化为图片 在方法里可做裁剪 

        UIImage *image = [self imageFromSampleBuffer:sampleBuffer];

  // 在这你可以对图片做一些算法操作 

        dispatch_async(dispatch_get_main_queue(), ^{

            bufferImageView.image = image;

        });

        CFRelease(sampleBuffer);

    }

 

#pramark 再写入文件

 

 if(开始写入 == NO){

        return;

    }

    BOOL isVideo = YES;

    

    CFRetain(sampleBuffer);

    

    if (captureOutput != _captureVideoDataOutput) {

        isVideo = NO;

    }

    if (writer == nil && !isVideo) {

        videoPath = [NSString stringWithFormat:@"%@/Documents/movie.mp4",NSHomeDirectory()];

        CMFormatDescriptionRef fmt = CMSampleBufferGetFormatDescription(sampleBuffer);

        const AudioStreamBasicDescription *asbd = CMAudioFormatDescriptionGetStreamBasicDescription(fmt);

        [[NSFileManager defaultManager] removeItemAtPath:videoPath error:nil];

         [self initPath:videoPath videoWidth:480 videoHeight:480 channels:asbd->mChannelsPerFrame samples:asbd->mSampleRate];

    }

    if (CMSampleBufferDataIsReady(sampleBuffer)) {

        

        if (writer.assetWriter.status == 0) {

            if (isVideo == YES) {

                [writer firstSamebuffer:sampleBuffer];

            }

        }

        if (writer.assetWriter.status == 3) {

            NSLog(@"写入失败 %@",writer.assetWriter.error);

        }

        if (isVideo) {

            if (writer.videoInput.readyForMoreMediaData == YES) {

                

                CMTime startTime = CMSampleBufferGetPresentationTimeStamp(sampleBuffer);

                

                [writer encodeImageDataToVideo:resultImage time:startTime];

    

            }

        }

        else{

            [writer encodeAudioFrame:sampleBuffer];

 

        }

        CFRelease(sampleBuffer);

        

    }

 

 

}

 

- (void)createWriter:(NSString *)path Width:(NSInteger)width Height:(NSInteger)height channels:(int)channels samples:(Float64)samples {

    /// 创建writer

    [[NSFileManager defaultManager] removeItemAtPath:path error:nil];

    NSURL *pathUrl = [NSURL fileURLWithPath:path];

    _assetWriter = [AVAssetWriter assetWriterWithURL:pathUrl fileType:AVFileTypeMPEG4 error:nil];

    _assetWriter.shouldOptimizeForNetworkUse = YES;

    

    

    [self initVideoInputHeight:height width:width];

    

    [self initAudioInputChannels:channels samples:samples];

}

//初始化视频输入

- (void)initVideoInputHeight:(NSInteger)cy width:(NSInteger)cx {

    //录制视频的一些配置,分辨率,编码方式等等

    NSDictionary* settings = [NSDictionary dictionaryWithObjectsAndKeys:

                              AVVideoCodecH264, AVVideoCodecKey,

                              [NSNumber numberWithInteger: cx], AVVideoWidthKey,

                              [NSNumber numberWithInteger: cy], AVVideoHeightKey,

                              nil];

    //初始化视频写入类

    _videoInput = [AVAssetWriterInput assetWriterInputWithMediaType:AVMediaTypeVideo outputSettings:settings];

    //表明输入是否应该调整其处理为实时数据源的数据

    _videoInput.expectsMediaDataInRealTime = YES;

    

  

    

    // 初始化写入图像类  add by david

    [self initVideoInputAdaptor];

    

    NSParameterAssert(_videoInput);

    NSParameterAssert([_assetWriter canAddInput:_videoInput]);

    //将视频输入源加入

    [_assetWriter addInput:_videoInput];

}

// 初始化写入图像类

- (void)initVideoInputAdaptor

{

    NSDictionary *sourcePixelBufferAttributesDictionary = [NSDictionary dictionaryWithObjectsAndKeys:

                                                           [NSNumber numberWithInt:kCVPixelFormatType_32BGRA], kCVPixelBufferPixelFormatTypeKey, nil];

    

    _adaptor = [AVAssetWriterInputPixelBufferAdaptor assetWriterInputPixelBufferAdaptorWithAssetWriterInput:_videoInput

                                                                                sourcePixelBufferAttributes:sourcePixelBufferAttributesDictionary];

    

}

 

//初始化音频输入

- (void)initAudioInputChannels:(int)ch samples:(Float64)rate {

    //音频的一些配置包括音频各种这里为AAC,音频通道、采样率和音频的比特率

    NSDictionary *settings = [NSDictionary dictionaryWithObjectsAndKeys:

                              [ NSNumber numberWithInt: kAudioFormatMPEG4AAC], AVFormatIDKey,

                              [ NSNumber numberWithInt: ch], AVNumberOfChannelsKey,

                              [ NSNumber numberWithFloat: rate], AVSampleRateKey,

                              [ NSNumber numberWithInt: 128000], AVEncoderBitRateKey,

                              nil];

    //初始化音频写入类

    _audioInput = [AVAssetWriterInput assetWriterInputWithMediaType:AVMediaTypeAudio outputSettings:settings];

    //表明输入是否应该调整其处理为实时数据源的数据

    _audioInput.expectsMediaDataInRealTime = YES;

    //将音频输入源加入

    [_assetWriter addInput:_audioInput];

    

}

 

- (CVPixelBufferRef )pixelBufferFromCGImage:(CGImageRef)image size:(CGSize)size

{

    NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:

                             [NSNumber numberWithBool:YES], kCVPixelBufferCGImageCompatibilityKey,

                             [NSNumber numberWithBool:YES], kCVPixelBufferCGBitmapContextCompatibilityKey, nil];

    CVPixelBufferRef pxbuffer = NULL;

    CVReturn status = CVPixelBufferCreate(kCFAllocatorDefault, size.width, size.height, kCVPixelFormatType_32BGRA, (__bridge CFDictionaryRef)options, &pxbuffer);

    

    

    NSParameterAssert(status == kCVReturnSuccess && pxbuffer != NULL);

    

    CVPixelBufferLockBaseAddress(pxbuffer, 0);

    void *pxdata = CVPixelBufferGetBaseAddress(pxbuffer);

    NSParameterAssert(pxdata != NULL);

    

    CGColorSpaceRef rgbColorSpace = CGColorSpaceCreateDeviceRGB();

    CGContextRef context = CGBitmapContextCreate(pxdata, size.width, size.height, 8, 4*size.width, rgbColorSpace, kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst);

    NSParameterAssert(context);

    

    CGContextDrawImage(context, CGRectMake(0, 0, size.width, size.height), image);

    

    CGColorSpaceRelease(rgbColorSpace);

    CGContextRelease(context);

    

    CVPixelBufferUnlockBaseAddress(pxbuffer, 0);

    

    return pxbuffer;

}

 

// 通过抽样缓存数据创建一个UIImage对象

- (UIImage *) imageFromSampleBuffer:(CMSampleBufferRef) sampleBuffer

{

    // 为媒体数据设置一个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);

    if (width == 0 || height == 0) {

        return nil;

    }

    // 创建一个依赖于设备的RGB颜色空间

    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();

    

    // 用抽样缓存的数据创建一个位图格式的图形上下文(graphics context)对象

    CGContextRef context = CGBitmapContextCreate(baseAddress, width, height, 8,

                                                 bytesPerRow, colorSpace, kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst);

//    

    CGAffineTransform transform = CGAffineTransformIdentity;

    

    CGContextConcatCTM(context, transform);

    

    // 根据这个位图context中的像素数据创建一个Quartz image对象

    CGImageRef quartzImage = CGBitmapContextCreateImage(context);

    // 裁剪 图片

    struct CGImage *cgImage = CGImageCreateWithImageInRect(quartzImage, CGRectMake(0, 0, height, height));

    // 解锁pixel buffer

    CVPixelBufferUnlockBaseAddress(imageBuffer,0);

    

    // 释放context和颜色空间

    CGContextRelease(context);

    CGColorSpaceRelease(colorSpace);

    

    // 用Quartz image创建一个UIImage对象image

    UIImage *image = [UIImage imageWithCGImage:cgImage];

    //    UIImage *image =  [UIImage imageWithCGImage:quartzImage scale:1.0 orientation:UIImageOrientationRight];

    

    // 释放Quartz image对象

    CGImageRelease(cgImage);

    CGImageRelease(quartzImage);

    //    NSLog(@"原来的%ld %f",(long)image.size.width,image.size.height);

    //    image = [self image:image rotation:UIImageOrientationRight];

    //    NSLog(@"变换过的%ld %f",(long)image.size.width,image.size.height);

    

    //    image.imageOrientation = 2;

    //    CGImageRelease(cgImage);

    

    

//    UIImage *resultImage = [[JBFaceDetectorHelper sharedInstance] rotateWithImage:image isFont:isFront];

    

    return (image);

}

 

posted @ 2016-08-24 16:25  小辉辉+  阅读(6080)  评论(0编辑  收藏  举报