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
- iOS 信号量在GPUImage中的使用
- iOS GPUImage 的使用
- iOS GPUImage 的使用
- iOS GPUImage 的使用
- iOS GPUImage 的使用
- iOS GPUImage 的使用
- iOS GPUImage 的使用
- iOS开发--GPUImage的使用
- 在使用GPUImage的错误
- iOS GPUImage 添加到工程 使用GPUImage渲染图片教程
- ios中的GpuImage及相关滤镜介绍
- ios中的GpuImage及相关滤镜介绍
- iOS 中的 GpuImage 及相关滤镜介绍
- ios中的GpuImage及相关滤镜介绍
- GPUImage使用
- 使用GPUImage实现iOS 7的模糊效果
- iOS --- 使用GPUImage实现的简单滤镜效果
- 使用GPUImage实现iOS 7的模糊效果
- Android性能优化之使用线程池处理异步任务
- QUTOJ 1222检查金币 水题
- 中断处理过程和中断服务程序ISR的限制
- DAO基础功能实现
- BFS/DFS模板
- iOS 信号量在GPUImage中的使用
- 底部导航栏实现页面的切换(一):Fragment + LinearLayout + TextView
- 51nod 1009 数字1的数量(数位dp)
- MSSQL之二十二 CLR及SQL
- 迁移学习
- nginx配置2个tomcat做负载均衡
- android定位和地图开发实例
- 获得屏幕尺寸的几种方法
- 统计学习:泛化能力、生成模型、判别模型、分类、标注和回归问题