概述
GPUImage是一個(gè)著名的圖像處理開源庫,它讓你能夠在圖片、視頻、相機(jī)上使用GPU加速的濾鏡和其它特效茂洒。與CoreImage框架相比,可以根據(jù)GPUImage提供的接口瓶竭,使用自定義的濾鏡。項(xiàng)目地址:https://github.com/BradLarson/GPUImage
這篇文章主要是閱讀GPUImage框架中的GPUImageInput協(xié)議以及GPUImageOutput類的源碼斤贰。這兩個(gè)是GPUImage響應(yīng)鏈的基礎(chǔ)。以下是源碼內(nèi)容:
*** GPUImageInput***
GPUImageOutput
GPUImageInput
GPUImageInput 是GPUImage中的一個(gè)重要的協(xié)議盏触,實(shí)現(xiàn)這個(gè)協(xié)議的類表示這個(gè)類能接受幀緩存的輸入渗蟹,在響應(yīng)鏈中每一個(gè)中間節(jié)點(diǎn)都能夠接受輸入經(jīng)過它的處理之后又能輸出給下一個(gè)節(jié)點(diǎn)块饺。正式這樣的過程構(gòu)成了一個(gè)響應(yīng)鏈條雌芽,這也是疊加濾鏡授艰、組合濾鏡的基礎(chǔ)。
- GPUImageInput 協(xié)議提供了方法列表世落,細(xì)節(jié)由實(shí)現(xiàn)的對(duì)象實(shí)現(xiàn)淮腾。GPUImage中實(shí)現(xiàn)GPUImageInput的協(xié)議的類比較多,常見的有
GPUImageFilter
屉佳、GPUImageView
、GPUImageRawDataOutput
圆凰、GPUImageMovieWriter
等体箕。
@protocol GPUImageInput <NSObject>
// 準(zhǔn)備下一個(gè)要使用的幀
- (void)newFrameReadyAtTime:(CMTime)frameTime atIndex:(NSInteger)textureIndex;
// 設(shè)置輸入的幀緩沖對(duì)象以及紋理索引
- (void)setInputFramebuffer:(GPUImageFramebuffer *)newInputFramebuffer atIndex:(NSInteger)textureIndex;
// 下一個(gè)有效的紋理索引
- (NSInteger)nextAvailableTextureIndex;
// 設(shè)置目標(biāo)的尺寸
- (void)setInputSize:(CGSize)newSize atIndex:(NSInteger)textureIndex;
// 設(shè)置旋轉(zhuǎn)模式
- (void)setInputRotation:(GPUImageRotationMode)newInputRotation atIndex:(NSInteger)textureIndex;
// 輸出緩沖區(qū)的最大尺寸
- (CGSize)maximumOutputSize;
// 輸入處理結(jié)束
- (void)endProcessing;
// 是否忽略渲染目標(biāo)的更新
- (BOOL)shouldIgnoreUpdatesToThisTarget;
// 是否啟用渲染目標(biāo)
- (BOOL)enabled;
// 是否為單色輸入
- (BOOL)wantsMonochromeInput;
// 設(shè)置單色輸入
- (void)setCurrentlyReceivingMonochromeInput:(BOOL)newValue;
@end
GPUImageOutput
GPUImageOutput 表示該類能夠作為輸出挑童,輸出的是 GPUImageFramebuffer
對(duì)象跃须。該類的實(shí)現(xiàn)比較簡單,主要是實(shí)現(xiàn)了一些最基本的方法尽楔,這些方法不需要依賴具體細(xì)節(jié)第练,細(xì)節(jié)處理在子類中完成翔试。繼承 GPUImageOutput 的類也比較多复旬,比如:GPUImageFilter
、GPUImageVideoCamera
壁涎、GPUImageStillCamera
志秃、GPUImagePicture
等
- 基本屬性
@interface GPUImageOutput : NSObject
{
// 輸出的幀緩存對(duì)象
GPUImageFramebuffer *outputFramebuffer;
// target列表,target紋理索引列表
NSMutableArray *targets, *targetTextureIndices;
// 紋理尺寸
CGSize inputTextureSize, cachedMaximumOutputSize, forcedMaximumSize;
BOOL overrideInputSize;
BOOL allTargetsWantMonochromeData;
// 設(shè)置下一幀提取圖片
BOOL usingNextFrameForImageCapture;
}
// 是否使用mipmaps
@property(readwrite, nonatomic) BOOL shouldSmoothlyScaleOutput;
// 是否忽略處理當(dāng)前Target
@property(readwrite, nonatomic) BOOL shouldIgnoreUpdatesToThisTarget;
@property(readwrite, nonatomic, retain) GPUImageMovieWriter *audioEncodingTarget;
// 當(dāng)前忽略處理的Target
@property(readwrite, nonatomic, unsafe_unretained) id<GPUImageInput> targetToIgnoreForUpdates;
// 每幀處理完回調(diào)
@property(nonatomic, copy) void(^frameProcessingCompletionBlock)(GPUImageOutput*, CMTime);
// 是否啟用渲染目標(biāo)
@property(nonatomic) BOOL enabled;
// 紋理選項(xiàng)
@property(readwrite, nonatomic) GPUTextureOptions outputTextureOptions;
- 方法列表竟坛。GPUImageOutput 提供方法主要是以下幾種類型:1钧舌、幀緩沖對(duì)象管理;2崭歧、響應(yīng)鏈的管理撞牢;3、圖像提取屋彪。
// 設(shè)置輸入的幀緩沖對(duì)象以及紋理索引
- (void)setInputFramebufferForTarget:(id<GPUImageInput>)target atIndex:(NSInteger)inputTextureIndex;
// 輸出的幀緩沖對(duì)象
- (GPUImageFramebuffer *)framebufferForOutput;
// 刪除幀緩沖對(duì)象
- (void)removeOutputFramebuffer;
// 通知所有的Target
- (void)notifyTargetsAboutNewOutputTexture;
// 所有的Target列表
- (NSArray*)targets;
// 增加Target
- (void)addTarget:(id<GPUImageInput>)newTarget;
- (void)addTarget:(id<GPUImageInput>)newTarget atTextureLocation:(NSInteger)textureLocation;
// 刪除Target
- (void)removeTarget:(id<GPUImageInput>)targetToRemove;
- (void)removeAllTargets;
// 強(qiáng)制按照傳入的尺寸處理
- (void)forceProcessingAtSize:(CGSize)frameSize;
- (void)forceProcessingAtSizeRespectingAspectRatio:(CGSize)frameSize;
// 從幀緩沖對(duì)象提取CGImage圖像
- (void)useNextFrameForImageCapture;
- (CGImageRef)newCGImageFromCurrentlyProcessedOutput;
// 使用靜態(tài)圖片做濾鏡紋理
- (CGImageRef)newCGImageByFilteringCGImage:(CGImageRef)imageToFilter;
// 從幀緩沖對(duì)象提取UIImage圖像
- (UIImage *)imageFromCurrentFramebuffer;
- (UIImage *)imageFromCurrentFramebufferWithOrientation:(UIImageOrientation)imageOrientation;
// 使用靜態(tài)圖片做濾鏡紋理
- (UIImage *)imageByFilteringImage:(UIImage *)imageToFilter;
- (CGImageRef)newCGImageByFilteringImage:(UIImage *)imageToFilter;
// 是否提供單色輸出
- (BOOL)providesMonochromeOutput;
- 幀緩沖對(duì)象管理。包含了設(shè)置輸入的幀緩沖對(duì)象畜挥,獲取輸出的幀緩沖對(duì)象,以及移除輸?shù)膸彌_對(duì)象砰嘁。
- (void)setInputFramebufferForTarget:(id<GPUImageInput>)target atIndex:(NSInteger)inputTextureIndex;
{
[target setInputFramebuffer:[self framebufferForOutput] atIndex:inputTextureIndex];
}
- (GPUImageFramebuffer *)framebufferForOutput;
{
return outputFramebuffer;
}
- (void)removeOutputFramebuffer;
{
outputFramebuffer = nil;
}
- 響應(yīng)鏈管理。包含了增加Target斟冕,刪除Target,處理完成后通知各個(gè)Target處理景描。
- (void)notifyTargetsAboutNewOutputTexture;
{
for (id<GPUImageInput> currentTarget in targets)
{
NSInteger indexOfObject = [targets indexOfObject:currentTarget];
NSInteger textureIndex = [[targetTextureIndices objectAtIndex:indexOfObject] integerValue];
[self setInputFramebufferForTarget:currentTarget atIndex:textureIndex];
}
}
- (NSArray*)targets;
{
return [NSArray arrayWithArray:targets];
}
- (void)addTarget:(id<GPUImageInput>)newTarget;
{
NSInteger nextAvailableTextureIndex = [newTarget nextAvailableTextureIndex];
[self addTarget:newTarget atTextureLocation:nextAvailableTextureIndex];
if ([newTarget shouldIgnoreUpdatesToThisTarget])
{
_targetToIgnoreForUpdates = newTarget;
}
}
- (void)addTarget:(id<GPUImageInput>)newTarget atTextureLocation:(NSInteger)textureLocation;
{
if([targets containsObject:newTarget])
{
return;
}
cachedMaximumOutputSize = CGSizeZero;
runSynchronouslyOnVideoProcessingQueue(^{
[self setInputFramebufferForTarget:newTarget atIndex:textureLocation];
[targets addObject:newTarget];
[targetTextureIndices addObject:[NSNumber numberWithInteger:textureLocation]];
allTargetsWantMonochromeData = allTargetsWantMonochromeData && [newTarget wantsMonochromeInput];
});
}
- (void)removeTarget:(id<GPUImageInput>)targetToRemove;
{
if(![targets containsObject:targetToRemove])
{
return;
}
if (_targetToIgnoreForUpdates == targetToRemove)
{
_targetToIgnoreForUpdates = nil;
}
cachedMaximumOutputSize = CGSizeZero;
NSInteger indexOfObject = [targets indexOfObject:targetToRemove];
NSInteger textureIndexOfTarget = [[targetTextureIndices objectAtIndex:indexOfObject] integerValue];
runSynchronouslyOnVideoProcessingQueue(^{
[targetToRemove setInputSize:CGSizeZero atIndex:textureIndexOfTarget];
[targetToRemove setInputRotation:kGPUImageNoRotation atIndex:textureIndexOfTarget];
[targetTextureIndices removeObjectAtIndex:indexOfObject];
[targets removeObject:targetToRemove];
[targetToRemove endProcessing];
});
}
- (void)removeAllTargets;
{
cachedMaximumOutputSize = CGSizeZero;
runSynchronouslyOnVideoProcessingQueue(^{
for (id<GPUImageInput> targetToRemove in targets)
{
NSInteger indexOfObject = [targets indexOfObject:targetToRemove];
NSInteger textureIndexOfTarget = [[targetTextureIndices objectAtIndex:indexOfObject] integerValue];
[targetToRemove setInputSize:CGSizeZero atIndex:textureIndexOfTarget];
[targetToRemove setInputRotation:kGPUImageNoRotation atIndex:textureIndexOfTarget];
}
[targets removeAllObjects];
[targetTextureIndices removeAllObjects];
allTargetsWantMonochromeData = YES;
});
}
- 提取圖像超棺。包含了提取得到 CGImage 和 UIImage 呵燕。
- (void)useNextFrameForImageCapture;
{
}
- (CGImageRef)newCGImageFromCurrentlyProcessedOutput;
{
return nil;
}
- (CGImageRef)newCGImageByFilteringCGImage:(CGImageRef)imageToFilter;
{
GPUImagePicture *stillImageSource = [[GPUImagePicture alloc] initWithCGImage:imageToFilter];
[self useNextFrameForImageCapture];
[stillImageSource addTarget:(id<GPUImageInput>)self];
[stillImageSource processImage];
CGImageRef processedImage = [self newCGImageFromCurrentlyProcessedOutput];
[stillImageSource removeTarget:(id<GPUImageInput>)self];
return processedImage;
}
- (UIImage *)imageFromCurrentFramebuffer;
{
UIDeviceOrientation deviceOrientation = [[UIDevice currentDevice] orientation];
UIImageOrientation imageOrientation = UIImageOrientationLeft;
switch (deviceOrientation)
{
case UIDeviceOrientationPortrait:
imageOrientation = UIImageOrientationUp;
break;
case UIDeviceOrientationPortraitUpsideDown:
imageOrientation = UIImageOrientationDown;
break;
case UIDeviceOrientationLandscapeLeft:
imageOrientation = UIImageOrientationLeft;
break;
case UIDeviceOrientationLandscapeRight:
imageOrientation = UIImageOrientationRight;
break;
default:
imageOrientation = UIImageOrientationUp;
break;
}
return [self imageFromCurrentFramebufferWithOrientation:imageOrientation];
}
- (UIImage *)imageFromCurrentFramebufferWithOrientation:(UIImageOrientation)imageOrientation;
{
CGImageRef cgImageFromBytes = [self newCGImageFromCurrentlyProcessedOutput];
UIImage *finalImage = [UIImage imageWithCGImage:cgImageFromBytes scale:1.0 orientation:imageOrientation];
CGImageRelease(cgImageFromBytes);
return finalImage;
}
- (UIImage *)imageByFilteringImage:(UIImage *)imageToFilter;
{
CGImageRef image = [self newCGImageByFilteringCGImage:[imageToFilter CGImage]];
UIImage *processedImage = [UIImage imageWithCGImage:image scale:[imageToFilter scale] orientation:[imageToFilter imageOrientation]];
CGImageRelease(image);
return processedImage;
}
總結(jié)
GPUImageInput 氧苍、GPUImageOutput 是構(gòu)成GPUImage響應(yīng)鏈的基礎(chǔ)泛范。如果一個(gè)類實(shí)現(xiàn)了 GPUImageInput 協(xié)議我們可以知道它能夠接收幀緩存對(duì)象的輸入,如果繼承了 GPUImageOutput 類罢荡,我們可以知道它能夠輸出幀緩存對(duì)象。如果兩個(gè)都具備惭缰,則表明既能處理輸入又可以輸出惧笛,比如 GPUImageFilter
逞泄,而這就是響應(yīng)鏈的基本要求。
源碼地址:GPUImage源碼閱讀系列 https://github.com/QinminiOS/GPUImage
系列文章地址:GPUImage源碼閱讀 http://www.reibang.com/nb/11749791