1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
#import "GPUImageUIElement.h"
@interface GPUImageUIElement ()
{
UIView *view;
CALayer *layer;
CGSize previousLayerSizeInPixels;
CMTime time;
NSTimeInterval actualTimeOfLastUpdate;
}
@end
@implementation GPUImageUIElement
#pragma mark -
#pragma mark Initialization and teardown
- (id)initWithView:(UIView *)inputView;
{
if (!(self = [super init]))
{
return nil;
}
view = inputView;
layer = inputView.layer;
previousLayerSizeInPixels = CGSizeZero;
[self update];
return self;
}
- (id)initWithLayer:(CALayer *)inputLayer;
{
if (!(self = [super init]))
{
return nil;
}
view = nil;
layer = inputLayer;
previousLayerSizeInPixels = CGSizeZero;
[self update];
return self;
}
#pragma mark -
#pragma mark Layer management
- (CGSize)layerSizeInPixels;
{
CGSize pointSize = layer.bounds.size;
return CGSizeMake(layer.contentsScale * pointSize.width, layer.contentsScale * pointSize.height);
}
- (void)update;
{
[self updateWithTimestamp:kCMTimeIndefinite];
}
- (void)updateUsingCurrentTime;
{
if(CMTIME_IS_INVALID(time)) {
time = CMTimeMakeWithSeconds(0, 600);
actualTimeOfLastUpdate = [NSDate timeIntervalSinceReferenceDate];
} else {
NSTimeInterval now = [NSDate timeIntervalSinceReferenceDate];
NSTimeInterval diff = now - actualTimeOfLastUpdate;
time = CMTimeAdd(time, CMTimeMakeWithSeconds(diff, 600));
actualTimeOfLastUpdate = now;
}
[self updateWithTimestamp:time];
}
- (void)updateWithTimestamp:(CMTime)frameTime;
{
[GPUImageContext useImageProcessingContext];
CGSize layerPixelSize = [self layerSizeInPixels];
GLubyte *imageData = (GLubyte *) calloc(1, (int)layerPixelSize.width * (int)layerPixelSize.height * 4);
CGColorSpaceRef genericRGBColorspace = CGColorSpaceCreateDeviceRGB();
CGContextRef imageContext = CGBitmapContextCreate(imageData, (int)layerPixelSize.width, (int)layerPixelSize.height, 8, (int)layerPixelSize.width * 4, genericRGBColorspace, kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst);
// CGContextRotateCTM(imageContext, M_PI_2);
CGContextTranslateCTM(imageContext, 0.0f, layerPixelSize.height);
CGContextScaleCTM(imageContext, layer.contentsScale, -layer.contentsScale);
// CGContextSetBlendMode(imageContext, kCGBlendModeCopy); // From Technical Q&A QA1708: http://developer.apple.com/library/ios/#qa/qa1708/_index.html
[layer renderInContext:imageContext];
CGContextRelease(imageContext);
CGColorSpaceRelease(genericRGBColorspace);
// TODO: This may not work
outputFramebuffer = [[GPUImageContext sharedFramebufferCache] fetchFramebufferForSize:layerPixelSize textureOptions:self.outputTextureOptions onlyTexture:YES];
glBindTexture(GL_TEXTURE_2D, [outputFramebuffer texture]);
// no need to use self.outputTextureOptions here, we always need these texture options
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (int)layerPixelSize.width, (int)layerPixelSize.height, 0, GL_BGRA, GL_UNSIGNED_BYTE, imageData);
free(imageData);
for (id<GPUImageInput> currentTarget in targets)
{
if (currentTarget != self.targetToIgnoreForUpdates)
{
NSInteger indexOfObject = [targets indexOfObject:currentTarget];
NSInteger textureIndexOfTarget = [[targetTextureIndices objectAtIndex:indexOfObject] integerValue];
[currentTarget setInputSize:layerPixelSize atIndex:textureIndexOfTarget];
[currentTarget newFrameReadyAtTime:frameTime atIndex:textureIndexOfTarget];
}
}
}
@end