iOS 信号量在GPUImage中的使用

来源:互联网 发布:华南师范大学网络自助 编辑:程序博客网 时间:2024/06/09 20:37


////  video_capture_external_demo.cpp//  ve_demo////  Created by robotding on 16/5/30.//  Copyright © 2016年 jjams. All rights reserved.//#import "video_capture_external_demo.h"#import "RosyWriterCPURenderer.h"@interface VideoCaptureDeviceDemo ()- (int)start;- (int)stop;- (int)restart;- (int)updateFrameRate;- (int)updateVideoSize;- (int)updateRotation;- (int)updateTorch;- (int)findDevice;- (NSString*)findPreset;- (int)createCam;- (int)releaseCam;- (AVCaptureVideoOrientation)findOrientation;- (CGImageRef)createCGImageFromCVPixelBuffer:(CVPixelBufferRef)pixels ;@endstatic void *openGLESContextQueueKey = &openGLESContextQueueKey;@implementation VideoCaptureDeviceDemo {    dispatch_queue_t m_oQueue;        AVCaptureSession *m_rCapSession;    AVCaptureDevice *m_rCapDevice;    AVCaptureDeviceInput *m_rDeviceInput;    AVCaptureVideoDataOutput *m_rDataOutput;        struct {        int fps;        int width;        int height;        bool front;        int rotation;        int torch;    } m_oSettings;        struct RunningState {        bool preview;        bool capture;    } m_oState;        id<ZegoVideoCaptureClientDelegate> client_;        bool is_take_photo_;            id<RosyWriterRenderer> _renderer;        dispatch_queue_t _serialQueue;        dispatch_queue_t _contextQueue;        dispatch_semaphore_t frameRenderingSemaphore;}-(id)init{    self = [super init];    if(nil != self){        m_oQueue = dispatch_queue_create("com.zego.ave.vcap.queue", DISPATCH_QUEUE_SERIAL);        _renderer = [[RosyWriterCPURenderer alloc] init];        _serialQueue = dispatch_queue_create("serialQueue", DISPATCH_QUEUE_SERIAL);        //        openGLESContextQueueKey = &openGLESContextQueueKey;        _contextQueue = dispatch_queue_create("com.sunsetlakesoftware.GPUImage.openGLESContextQueue", NULL);        #if OS_OBJECT_USE_OBJC        dispatch_queue_set_specific(_contextQueue, openGLESContextQueueKey, &openGLESContextQueueKey, NULL);#endif                frameRenderingSemaphore = dispatch_semaphore_create(1);    }    return self;  }- (void)allocateAndStart:(id<ZegoVideoCaptureClientDelegate>) client {    client_ = client;    is_take_photo_ = false;}- (void)stopAndDeAllocate {    [client_ destroy];    client_ = nil;        dispatch_sync(m_oQueue, ^ {        return ;    });}- (int)startCapture {    if(m_oState.capture) {        // * already started        return 0;    }        m_oState.capture = true;        if(!m_oState.preview) {        dispatch_async(m_oQueue, ^{            [self start];        });    }        return 0;}- (int)stopCapture {    if(!m_oState.capture) {        // * capture is not started        return 0;    }        m_oState.capture = false;        if(!m_oState.preview) {        // * stop the cam        dispatch_async(m_oQueue, ^{            [self stop];        });    }        return 0;}- (int)setFrameRate:(int)framerate {    // * no change    if(m_oSettings.fps == framerate) {        return 0;    }        m_oSettings.fps = framerate;        dispatch_async(m_oQueue, ^{        if(m_rCapSession) {            [self updateFrameRate];        }    });        return 0;}- (int)setWidth:(int)width andHeight:(int)height {    // * not changed    if ((m_oSettings.width == width) && (m_oSettings.height == height)) {        return 0;    }        m_oSettings.width = width;    m_oSettings.height = height;        dispatch_async(m_oQueue, ^{        if(m_rCapSession) {            [self updateVideoSize];            [self updateFrameRate];        }    });        return 0;}- (int)setFrontCam:(int)bFront {    if(m_oSettings.front == bFront) {        return 0;    }        m_oSettings.front = bFront;        dispatch_async(m_oQueue, ^{        // * just restart capture        if(m_rCapSession) {            [self stop];            [self start];        }    });        return 0;}- (int)setView:(UIView*)view {    dispatch_async(m_oQueue, ^{        // * restart cam        [self restart];    });        return 0;}- (int)setViewMode:(int)mode {    return 0;}- (int)setViewRotation:(int)rotation {    return 0;}- (int)setCaptureRotation:(int)rotaion {    if(m_oSettings.rotation == rotaion) {        return 0;    }        m_oSettings.rotation = rotaion;        dispatch_async(m_oQueue, ^{        if(m_rCapSession) {            [self updateRotation];        }    });        return 0;}- (int)startPreview {    if(m_oState.preview) {        // * preview already started        return 0;    }        m_oState.preview = true;        if(!m_oState.capture) {        // * let's start the cam        dispatch_async(m_oQueue, ^{            [self start];        });    }        return 0;}- (int)stopPreview {    if(!m_oState.preview) {        // * preview not started        return 0;    }        m_oState.preview = false;        if(!m_oState.capture) {        dispatch_async(m_oQueue, ^{            [self stop];        });    }        return 0;}- (int)enableTorch:(bool)enable {    if (m_oSettings.torch == enable) {        return 0;    } else {        m_oSettings.torch = enable;    }        dispatch_async(m_oQueue, ^{        if (m_rCapSession) {            [self updateTorch];        }    });        return 0;}- (int)takeSnapshot {    is_take_photo_ = true;    return 0;}- (int)setPowerlineFreq:(unsigned int)freq {    return 0;}- (int)createCam {    [self findDevice];        m_rCapSession = [[AVCaptureSession alloc] init];        [m_rCapSession beginConfiguration];        NSError *error = nil;    m_rDeviceInput = [[AVCaptureDeviceInput alloc] initWithDevice:m_rCapDevice error:&error];        if([m_rCapSession canAddInput:m_rDeviceInput]) {        [m_rCapSession addInput:m_rDeviceInput];    }        m_rDataOutput = [[AVCaptureVideoDataOutput alloc] init];    // * [m_rDataOutput setAlwaysDiscardsLateVideoFrames:NO];    [m_rDataOutput setAlwaysDiscardsLateVideoFrames:YES];    // * [m_rDataOutput setVideoSettings:@{(NSString*)kCVPixelBufferPixelFormatTypeKey:@(kCVPixelFormatType_32BGRA)}];        // * set output to 640x480    double dWidth = m_oSettings.width;    double dHeight = m_oSettings.height;        NSDictionary *videoSettings = [NSDictionary dictionaryWithObjectsAndKeys:                                   [NSNumber numberWithDouble:dWidth], (id)kCVPixelBufferWidthKey,                                   [NSNumber numberWithDouble:dHeight], (id)kCVPixelBufferHeightKey,                                   [NSNumber numberWithInt:kCVPixelFormatType_32BGRA], (id)kCVPixelBufferPixelFormatTypeKey,                                   nil                                   ];        // * [datOutput setVideoSettings: [NSDictionary dictionaryWithObject:[NSNumber numberWithInt:kCVPixelFormatType_32BGRA] forKey:(id)kCVPixelBufferPixelFormatTypeKey]];    [m_rDataOutput setVideoSettings:videoSettings];    [m_rDataOutput setSampleBufferDelegate:self queue:m_oQueue];        if([m_rCapSession canAddOutput:m_rDataOutput]) {        [m_rCapSession addOutput:m_rDataOutput];    }        // * [capSession setSessionPreset:AVCaptureSessionPresetMedium];    NSString *strPreset = [self findPreset];        if([m_rCapSession canSetSessionPreset:strPreset]) {        [m_rCapSession setSessionPreset:strPreset];    }        // * set video orientation    AVCaptureConnection *vconn = [m_rDataOutput connectionWithMediaType:AVMediaTypeVideo];    if([vconn isVideoOrientationSupported]) {        [vconn setVideoOrientation:[self findOrientation]];    }        [m_rCapSession commitConfiguration];        // * set framerate    [self updateFrameRate];        // * torch    [self updateTorch];        return 0;}- (int)releaseCam {    if(m_rDataOutput) {        [m_rDataOutput setSampleBufferDelegate:nil queue:dispatch_get_main_queue()];    }        if(m_rCapSession) {        if(m_rDeviceInput) {            [m_rCapSession removeInput:m_rDeviceInput];        }                if(m_rDataOutput) {            [m_rCapSession removeOutput:m_rDataOutput];        }    }        m_rDataOutput = nil;    m_rDeviceInput = nil;    m_rCapDevice = nil;    m_rCapSession = nil;        return 0;}- (int)start {    // * make sure we are stopped    [self stop];        [self createCam];        // * [m_rCapSession startRunning];    // * queue a async start        // * lock again    if(m_rCapSession)    {        [m_rCapSession startRunning];    }        return 0;}- (int)stop {    if (m_rCapSession) {        if([m_rCapSession isRunning]) {            [m_rCapSession stopRunning];        }    }        [self releaseCam];        return 0;}- (int)restart {    // * stop capture (without releasing capture)    if (m_rCapSession) {        if([m_rCapSession isRunning]) {            [m_rCapSession stopRunning];        }    }        // * queue a async start    if(m_rCapSession) {        [m_rCapSession startRunning];    }        return 0;}- (int)updateFrameRate {    // * set framerate    int framerate = m_oSettings.fps;    CMTime frameDuration;    if(framerate > 0) {        frameDuration = CMTimeMake(1, framerate);    } else {        frameDuration = kCMTimeInvalid;    }    NSError *err = nil;    [m_rCapDevice lockForConfiguration:&err];    m_rCapDevice.activeVideoMaxFrameDuration = frameDuration;    m_rCapDevice.activeVideoMinFrameDuration = frameDuration;    [m_rCapDevice unlockForConfiguration];    // * for(AVCaptureConnection *conn in datOutput.connections)    // * {    // * if([conn respondsToSelector:@selector(setVideoMinFrameDuration:)])    // * {    // * [conn setVideoMinFrameDuration:frameDuration];    // * }    // * }        return 0;}- (int)updateVideoSize {    [m_rCapSession beginConfiguration];        // * set output to 640x480    double dWidth = m_oSettings.width;    double dHeight = m_oSettings.height;        NSDictionary *videoSettings = [NSDictionary dictionaryWithObjectsAndKeys:                                   [NSNumber numberWithDouble:dWidth], (id)kCVPixelBufferWidthKey,                                   [NSNumber numberWithDouble:dHeight], (id)kCVPixelBufferHeightKey,                                   [NSNumber numberWithInt:kCVPixelFormatType_32BGRA], (id)kCVPixelBufferPixelFormatTypeKey,                                   nil                                   ];        // * [datOutput setVideoSettings: [NSDictionary dictionaryWithObject:[NSNumber numberWithInt:kCVPixelFormatType_32BGRA] forKey:(id)kCVPixelBufferPixelFormatTypeKey]];    [m_rDataOutput setVideoSettings:videoSettings];        NSString *strPreset = [self findPreset];        if([m_rCapSession canSetSessionPreset:strPreset])    {        [m_rCapSession setSessionPreset:strPreset];    }        [m_rCapSession commitConfiguration];        return 0;}- (int)updateRotation {    [m_rCapSession beginConfiguration];        AVCaptureConnection *vconn = [m_rDataOutput connectionWithMediaType:AVMediaTypeVideo];    if([vconn isVideoOrientationSupported]) {        [vconn setVideoOrientation:[self findOrientation]];    }        [m_rCapSession commitConfiguration];        return 0;}- (int)updateTorch {    AVCaptureTorchMode mode = m_oSettings.torch ? AVCaptureTorchModeOn : AVCaptureTorchModeOff;        if(m_rCapDevice && [m_rCapDevice hasTorch] && [m_rCapDevice isTorchModeSupported:mode]) {        [m_rCapDevice lockForConfiguration:nil];        [m_rCapDevice setTorchMode:mode];        [m_rCapDevice unlockForConfiguration];    }        return 0;}- (int)findDevice {    NSArray *devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo];    for(AVCaptureDevice *device in devices) {        if(m_oSettings.front) {            if(device.position == AVCaptureDevicePositionFront) {                m_rCapDevice = device;            }        } else {            if(device.position == AVCaptureDevicePositionBack) {                m_rCapDevice = device;            }        }    }        return 0;}- (NSString*)findPreset {    int width = m_oSettings.width;    int height = m_oSettings.height;        if((width >= 1920) || (height >= 1080))  {        return AVCaptureSessionPreset1920x1080;    } else if((width >= 1280) || (height >= 720)) {        return AVCaptureSessionPreset1280x720;    }    // * else if((width >= 960) || (height >= 540))    // * {    // * return AVCaptureSessionPreset960x540;    // * }    else if((width >= 640) || (height >= 480))    {        return AVCaptureSessionPreset640x480;    } else if((width >= 352) || (height >= 288)) {        return AVCaptureSessionPreset352x288;    }    // * else if((width >= 320) || (height >= 240))    // * {    // * return AVCaptureSessionPreset320x240;    // * }        // * ??????????    return AVCaptureSessionPreset640x480;}- (AVCaptureVideoOrientation)findOrientation {    AVCaptureVideoOrientation nOrientation = AVCaptureVideoOrientationPortrait;        if(m_oSettings.rotation == 0) {        nOrientation = AVCaptureVideoOrientationPortrait;    } else if(m_oSettings.rotation == 90) {        nOrientation = AVCaptureVideoOrientationLandscapeLeft;    } else if(m_oSettings.rotation == 180) {        nOrientation = AVCaptureVideoOrientationPortraitUpsideDown;    } else if(m_oSettings.rotation == 270) {        nOrientation = AVCaptureVideoOrientationLandscapeRight;    }        return nOrientation;}- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection {        [self processPixelBufferdidWithOutputSampleBuffer:sampleBuffer];    }- (void)processPixelBufferdidWithOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer{        CMTime pts = CMSampleBufferGetPresentationTimeStamp(sampleBuffer);    BOOL isWaitingTimeOut = dispatch_semaphore_wait(frameRenderingSemaphore, DISPATCH_TIME_NOW);    if (isWaitingTimeOut == YES) {        NSLog(@"等待超时");        return;    }        dispatch_async(_serialQueue, ^{        CVPixelBufferRef renderedPixelBuffer = NULL;        CVPixelBufferRef sourcePixelBuffer = CMSampleBufferGetImageBuffer( sampleBuffer );        renderedPixelBuffer = [_renderer copyRenderedPixelBuffer:sourcePixelBuffer];        [client_ onIncomingCapturedData:renderedPixelBuffer withPresentationTimeStamp:pts];        CFRelease( renderedPixelBuffer );    });        //方法1//    //等待超时-返回非零//    if (dispatch_semaphore_wait(frameRenderingSemaphore, DISPATCH_TIME_NOW) != 0)//    {//        //等待超时-则返回//        return;//    }//    //    CFRetain(sampleBuffer);//    [self runAsynchronouslyOnVideoProcessingQueue:^{//        //Feature Detection Hook.//        //        //[self processVideoSampleBuffer:sampleBuffer];//        //        CVPixelBufferRef renderedPixelBuffer = NULL;//        CVPixelBufferRef sourcePixelBuffer = CMSampleBufferGetImageBuffer( sampleBuffer );//        renderedPixelBuffer = [_renderer copyRenderedPixelBuffer:sourcePixelBuffer];//        [client_ onIncomingCapturedData:renderedPixelBuffer withPresentationTimeStamp:pts];//        CFRelease( renderedPixelBuffer );//        CFRelease(sampleBuffer);//        dispatch_semaphore_signal(frameRenderingSemaphore);//    }];        /*方法二    @synchronized (_renderer) {        CVPixelBufferRef renderedPixelBuffer = NULL;        CVPixelBufferRef sourcePixelBuffer = CMSampleBufferGetImageBuffer( sampleBuffer );        renderedPixelBuffer = [_renderer copyRenderedPixelBuffer:sourcePixelBuffer];        [client_ onIncomingCapturedData:renderedPixelBuffer withPresentationTimeStamp:pts];        CFRelease( renderedPixelBuffer );    };*/}- (void) runAsynchronouslyOnVideoProcessingQueue:(void (^)(void))block{    dispatch_queue_t videoProcessingQueue = _contextQueue;        if (dispatch_get_specific(openGLESContextQueueKey))    {        block();    }else    {        dispatch_async(videoProcessingQueue, block);    }}//void runAsynchronouslyOnVideoProcessingQueue(void (^block)(void))//{//    dispatch_queue_t videoProcessingQueue = [GPUImageContext sharedContextQueue];//    //#if !OS_OBJECT_USE_OBJC//#pragma clang diagnostic push//#pragma clang diagnostic ignored "-Wdeprecated-declarations"//    if (dispatch_get_current_queue() == videoProcessingQueue)//#pragma clang diagnostic pop//#else//        if (dispatch_get_specific([GPUImageContext contextKey]))//#endif//        {//            block();//        }else//        {//            dispatch_async(videoProcessingQueue, block);//        }//}- (CGImageRef)createCGImageFromCVPixelBuffer:(CVPixelBufferRef)pixels {    int width = (int)CVPixelBufferGetWidth(pixels);    int height = (int)CVPixelBufferGetHeight(pixels);    int stride = (int)CVPixelBufferGetBytesPerRow(pixels);        CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();        CVPixelBufferLockBaseAddress(pixels, kCVPixelBufferLock_ReadOnly);    unsigned char *bgra = (unsigned char*)CVPixelBufferGetBaseAddress(pixels);    CFDataRef data = CFDataCreate(kCFAllocatorDefault, bgra, CVPixelBufferGetBytesPerRow(pixels)*height);        unsigned char *rgba = (unsigned char*)CFDataGetBytePtr(data);    for(int h=0; h<height; h++) {        unsigned char *line = rgba + (h * stride);        for(int w=0; w<width; w++) {            unsigned char tmp = line[4*w+0];            line[4*w+0] = line[4*w+2];            line[4*w+2] = tmp;        }    }        CGDataProviderRef dp = CGDataProviderCreateWithCFData(data);    CGImageRef image = CGImageCreate(width, height, 8, 32, CVPixelBufferGetBytesPerRow(pixels), colorSpace, kCGImageAlphaPremultipliedLast, dp, NULL, NO, kCGRenderingIntentDefault);        CGDataProviderRelease(dp);    CFRelease(data);    CGColorSpaceRelease(colorSpace);    CVPixelBufferUnlockBaseAddress(pixels, kCVPixelBufferLock_ReadOnly);        return image;}@end@implementation VideoCaptureFactoryDemo {    VideoCaptureDeviceDemo* g_device_;}- (id<ZegoVideoCaptureDevice>)create:(NSString*)deviceId {    if (g_device_ == nil) {        g_device_ = [[VideoCaptureDeviceDemo alloc]init];    }    return g_device_;}- (void)destroy:(id<ZegoVideoCaptureDevice>)device {    }@end


0 0
原创粉丝点击