GPUImage源码解读(十一)

GPUImageStillCamera主要用来进行拍照。它继承自 GPUImageVideoCamera,因此,除了具备GPUImageVideoCamera的功能,它还提供了一套丰富的拍照API,方便我们进行拍照的相关操作。

  • 属性列表。GPUImageStillCamera属性比较少,属性也主要是与图片相关

// jpeg图片的压缩率,默认是0.8
@property CGFloat jpegCompressionQuality;
// 图片的Metadata信息
@property (readonly) NSDictionary *currentCaptureMetadata;
  • 方法列表。方法主要是和拍照相关,输出的类型比较丰富,可以是CMSampleBuffer、UIImage、NSData 等。如果有滤镜需要,还可以传入相关滤镜(final Filter In Chain)。

- (void)capturePhotoAsSampleBufferWithCompletionHandler:(void (^)(CMSampleBufferRef imageSampleBuffer, NSError *error))block;
- (void)capturePhotoAsImageProcessedUpToFilter:(GPUImageOutput<GPUImageInput> *)finalFilterInChain withCompletionHandler:(void (^)(UIImage *processedImage, NSError *error))block;
- (void)capturePhotoAsImageProcessedUpToFilter:(GPUImageOutput<GPUImageInput> *)finalFilterInChain withOrientation:(UIImageOrientation)orientation withCompletionHandler:(void (^)(UIImage *processedImage, NSError *error))block;
- (void)capturePhotoAsJPEGProcessedUpToFilter:(GPUImageOutput<GPUImageInput> *)finalFilterInChain withCompletionHandler:(void (^)(NSData *processedJPEG, NSError *error))block;
- (void)capturePhotoAsJPEGProcessedUpToFilter:(GPUImageOutput<GPUImageInput> *)finalFilterInChain withOrientation:(UIImageOrientation)orientation withCompletionHandler:(void (^)(NSData *processedJPEG, NSError *error))block;
- (void)capturePhotoAsPNGProcessedUpToFilter:(GPUImageOutput<GPUImageInput> *)finalFilterInChain withCompletionHandler:(void (^)(NSData *processedPNG, NSError *error))block;
- (void)capturePhotoAsPNGProcessedUpToFilter:(GPUImageOutput<GPUImageInput> *)finalFilterInChain withOrientation:(UIImageOrientation)orientation withCompletionHandler:(void (^)(NSData *processedPNG, NSError *error))block;

这些方法最终都会下面这个内部方法

#pragma mark - Private Methods
- (void)capturePhotoProcessedUpToFilter:(GPUImageOutput<GPUImageInput> *)finalFilterInChain withImageOnGPUHandler:(void (^)(NSError *error))block
{
//dispatch_semaphore_wait等待信号,当信号总量少于0的时候就会一直等待,否则就可以正常的执行,并让信号总量-1
dispatch_semaphore_wait(frameRenderingSemaphore, DISPATCH_TIME_FOREVER);
//判断是否捕获图像
if(photoOutput.isCapturingStillImage){
block([NSError errorWithDomain:AVFoundationErrorDomain code:AVErrorMaximumStillImageCaptureRequestsExceeded userInfo:nil]);
return;
}
// 异步捕获图像
[photoOutput captureStillImageAsynchronouslyFromConnection:[[photoOutput connections] objectAtIndex:0] completionHandler:^(CMSampleBufferRef imageSampleBuffer, NSError *error) {
if(imageSampleBuffer == NULL){
block(error);
return;
}
// For now, resize photos to fix within the max texture size of the GPU
CVImageBufferRef cameraFrame = CMSampleBufferGetImageBuffer(imageSampleBuffer);
// 获取图像大小
CGSize sizeOfPhoto = CGSizeMake(CVPixelBufferGetWidth(cameraFrame), CVPixelBufferGetHeight(cameraFrame));
CGSize scaledImageSizeToFitOnGPU = [GPUImageContext sizeThatFitsWithinATextureForSize:sizeOfPhoto];
// 判断时候需要调整大小
if (!CGSizeEqualToSize(sizeOfPhoto, scaledImageSizeToFitOnGPU))
{
CMSampleBufferRef sampleBuffer = NULL;
/*
CVPixelBufferIsPlanar可得到像素的存储方式是Planar或Chunky。若是Planar,则通过CVPixelBufferGetPlaneCount获取YUV Plane数量。通常是两个Plane,Y为一个Plane,UV由VTDecompressionSessionCreate创建解码会话时通过destinationImageBufferAttributes指定需要的像素格式(可不同于视频源像素格式)决定是否同属一个Plane,每个Plane可当作表格按行列处理,像素是行顺序填充的。下面以Planar Buffer存储方式作说明
*/
if (CVPixelBufferGetPlaneCount(cameraFrame) > 0)
{
NSAssert(NO, @"Error: no downsampling for YUV input in the framework yet");
}
else
{
// 图像调整
GPUImageCreateResizedSampleBuffer(cameraFrame, scaledImageSizeToFitOnGPU, &sampleBuffer);
}
dispatch_semaphore_signal(frameRenderingSemaphore);
[finalFilterInChain useNextFrameForImageCapture];
// 调用父类进行图片处理,生成帧缓存对象
[self captureOutput:photoOutput didOutputSampleBuffer:sampleBuffer fromConnection:[[photoOutput connections] objectAtIndex:0]];
dispatch_semaphore_wait(frameRenderingSemaphore, DISPATCH_TIME_FOREVER);
if (sampleBuffer != NULL)
CFRelease(sampleBuffer);
}
else
{
// This is a workaround for the corrupt images that are sometimes returned when taking a photo with the front camera and using the iOS 5.0 texture caches
AVCaptureDevicePosition currentCameraPosition = [[videoInput device] position];
if ( (currentCameraPosition != AVCaptureDevicePositionFront) || (![GPUImageContext supportsFastTextureUpload]) || !requiresFrontCameraTextureCacheCorruptionWorkaround)
{
dispatch_semaphore_signal(frameRenderingSemaphore);
[finalFilterInChain useNextFrameForImageCapture];
// 调用父类进行图片处理,生成帧缓存对象
[self captureOutput:photoOutput didOutputSampleBuffer:imageSampleBuffer fromConnection:[[photoOutput connections] objectAtIndex:0]];
dispatch_semaphore_wait(frameRenderingSemaphore, DISPATCH_TIME_FOREVER);
}
}
//图片的metadate 信息
CFDictionaryRef metadata = CMCopyDictionaryOfAttachments(NULL, imageSampleBuffer, kCMAttachmentMode_ShouldPropagate);
_currentCaptureMetadata = (__bridge_transfer NSDictionary *)metadata;
block(nil);
_currentCaptureMetadata = nil;
}];
}