├── GreenScreen
├── en.lproj
│ ├── InfoPlist.strings
│ ├── MainStoryboard_iPad.storyboard
│ └── MainStoryboard_iPhone.storyboard
├── Elephant.jpg
├── GreenScreen-Prefix.pch
├── GSAppDelegate.m
├── GSAppDelegate.h
├── main.m
├── Shaders
│ ├── greenScreen.vsh
│ └── greenScreen.fsh
├── GSViewController.h
├── GSGreenScreenEffect.h
├── GreenScreen-Info.plist
├── UtilityEffect.h
├── GSVideoProcessor.h
├── GSGreenScreenEffect.m
├── UtilityEffect.m
├── GSVideoProcessor.m
└── GSViewController.m
├── Default-568h@2x.png
├── GreenScreen.xcodeproj
├── xcuserdata
│ └── erik.xcuserdatad
│ │ ├── xcdebugger
│ │ └── Breakpoints.xcbkptlist
│ │ └── xcschemes
│ │ ├── xcschememanagement.plist
│ │ └── GreenScreen.xcscheme
├── project.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcuserdata
│ │ └── erik.xcuserdatad
│ │ ├── UserInterfaceState.xcuserstate
│ │ └── WorkspaceSettings.xcsettings
└── project.pbxproj
├── License
└── README.md
/GreenScreen/en.lproj/InfoPlist.strings:
--------------------------------------------------------------------------------
1 | /* Localized versions of Info.plist keys */
2 |
3 |
--------------------------------------------------------------------------------
/Default-568h@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/erikbuck/RealTimeGreenScreen/HEAD/Default-568h@2x.png
--------------------------------------------------------------------------------
/GreenScreen/Elephant.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/erikbuck/RealTimeGreenScreen/HEAD/GreenScreen/Elephant.jpg
--------------------------------------------------------------------------------
/GreenScreen.xcodeproj/xcuserdata/erik.xcuserdatad/xcdebugger/Breakpoints.xcbkptlist:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
--------------------------------------------------------------------------------
/GreenScreen.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/GreenScreen.xcodeproj/project.xcworkspace/xcuserdata/erik.xcuserdatad/UserInterfaceState.xcuserstate:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/erikbuck/RealTimeGreenScreen/HEAD/GreenScreen.xcodeproj/project.xcworkspace/xcuserdata/erik.xcuserdatad/UserInterfaceState.xcuserstate
--------------------------------------------------------------------------------
/GreenScreen/GreenScreen-Prefix.pch:
--------------------------------------------------------------------------------
1 | //
2 | // Prefix header for all source files of the 'GreenScreen' target in the 'GreenScreen' project
3 | //
4 |
5 | #import
6 |
7 | #ifndef __IPHONE_5_0
8 | #warning "This project uses features only available in iOS SDK 5.0 and later."
9 | #endif
10 |
11 | #ifdef __OBJC__
12 | #import
13 | #import
14 | #endif
15 |
--------------------------------------------------------------------------------
/GreenScreen.xcodeproj/project.xcworkspace/xcuserdata/erik.xcuserdatad/WorkspaceSettings.xcsettings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | HasAskedToTakeAutomaticSnapshotBeforeSignificantChanges
6 |
7 | SnapshotAutomaticallyBeforeSignificantChanges
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/GreenScreen.xcodeproj/xcuserdata/erik.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | GreenScreen.xcscheme
8 |
9 | orderHint
10 | 0
11 |
12 |
13 | SuppressBuildableAutocreation
14 |
15 | 03AF043615C84C230061A0D7
16 |
17 | primary
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/License:
--------------------------------------------------------------------------------
1 | Copyright 2018 Erik M. Buck
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4 |
5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6 |
7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
8 |
--------------------------------------------------------------------------------
/GreenScreen/GSAppDelegate.m:
--------------------------------------------------------------------------------
1 | //
2 | // GSAppDelegate.m
3 | // GreenScreen
4 | //
5 | /*
6 | Copyright (c) 2012 Erik M. Buck
7 |
8 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
11 |
12 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
13 | */
14 |
15 | #import "GSAppDelegate.h"
16 |
17 | @implementation GSAppDelegate
18 |
19 | @end
20 |
--------------------------------------------------------------------------------
/GreenScreen/GSAppDelegate.h:
--------------------------------------------------------------------------------
1 | //
2 | // GSAppDelegate.h
3 | // GreenScreen
4 | //
5 | /*
6 | Copyright (c) 2012 Erik M. Buck
7 |
8 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
11 |
12 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
13 | */
14 |
15 | #import
16 |
17 | @interface GSAppDelegate : UIResponder
18 |
19 | @property (strong, nonatomic) UIWindow *window;
20 |
21 | @end
22 |
--------------------------------------------------------------------------------
/GreenScreen/main.m:
--------------------------------------------------------------------------------
1 | //
2 | // main.m
3 | // GreenScreen
4 | //
5 | /*
6 | Copyright (c) 2012 Erik M. Buck
7 |
8 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
11 |
12 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
13 | */
14 |
15 | #import
16 |
17 | #import "GSAppDelegate.h"
18 |
19 | int main(int argc, char *argv[])
20 | {
21 | @autoreleasepool {
22 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([GSAppDelegate class]));
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Real Time Green Screen Video Efect for iOS.
2 |
3 | This is the sample code that accompanies the InformIT article, *Green-Screen Video Effects for iOS: Video Processing with OpenGL ES*. www.informit.com/articles/article.aspx?p=1946398
4 |
5 | Wish you could use the green-screen effects from movies and TV shows with your iOS devices? You can! Erik Buck, author of *Learning OpenGL ES for iOS: A Hands-on Guide to Modern 3D Graphics Programming*, describes how to perform real-time video processing without impacting performance. Green-screen effects are just one of the cool capabilities! Experiment with the provided demo program and learn how to push out your boundaries.
6 |
7 | 
8 |
9 | Figure 1 Sample green-screen effect.
10 |
11 |
12 | 
13 |
14 | Figure 2 Images are composed of pixels with red, green, and blue elements.
15 |
16 |
17 | 
18 |
19 | Figure 3 There's an elephant outside the window.
20 |
21 |
22 | 
23 |
24 | Figure 4 The neighbor's lawn is very green.
25 |
--------------------------------------------------------------------------------
/GreenScreen/Shaders/greenScreen.vsh:
--------------------------------------------------------------------------------
1 | //
2 | // greenScreen.vsh
3 | // GreenScreen
4 | //
5 | /*
6 | Copyright (c) 2012 Erik M. Buck
7 |
8 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
11 |
12 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
13 | */
14 |
15 | attribute vec4 aPosition;
16 | attribute mediump vec4 aTextureCoordinate;
17 | varying highp vec2 vCoordinate;
18 | uniform sampler2D uVideoframe;
19 | uniform highp mat4 uMVPMatrix;
20 |
21 | void main()
22 | {
23 | gl_Position = aPosition * uMVPMatrix;
24 | vCoordinate = aTextureCoordinate.xy;
25 | }
26 |
--------------------------------------------------------------------------------
/GreenScreen/GSViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // GSViewController.h
3 | // GreenScreen
4 | //
5 | /*
6 | Copyright (c) 2012 Erik M. Buck
7 |
8 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
11 |
12 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
13 | */
14 |
15 | #import
16 |
17 | @interface GSViewController : GLKViewController
18 |
19 | @property (weak, nonatomic)
20 | IBOutlet UILabel *frameRateLabel;
21 | @property (weak, nonatomic)
22 | IBOutlet UILabel *dimensionsLabel;
23 | @property (weak, nonatomic)
24 | IBOutlet UILabel *typeLabel;
25 |
26 | @end
27 |
--------------------------------------------------------------------------------
/GreenScreen/GSGreenScreenEffect.h:
--------------------------------------------------------------------------------
1 | //
2 | // GSGreenScreenEffect.h
3 | // GreenScreen
4 | //
5 | /*
6 | Copyright (c) 2012 Erik M. Buck
7 |
8 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
11 |
12 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
13 | */
14 |
15 | #import "UtilityEffect.h"
16 | #import
17 |
18 | @interface GSGreenScreenEffect : UtilityEffect
19 |
20 | @property (nonatomic, readonly)
21 | GLKEffectPropertyTransform *transform;
22 |
23 | @property (nonatomic, readonly)
24 | GLKEffectPropertyTexture *texture2d0;
25 |
26 | @end
27 |
--------------------------------------------------------------------------------
/GreenScreen/GreenScreen-Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleDisplayName
8 | ${PRODUCT_NAME}
9 | CFBundleExecutable
10 | ${EXECUTABLE_NAME}
11 | CFBundleIdentifier
12 | $(PRODUCT_BUNDLE_IDENTIFIER)
13 | CFBundleInfoDictionaryVersion
14 | 6.0
15 | CFBundleName
16 | ${PRODUCT_NAME}
17 | CFBundlePackageType
18 | APPL
19 | CFBundleShortVersionString
20 | 1.0
21 | CFBundleSignature
22 | ????
23 | CFBundleVersion
24 | 1.0
25 | LSRequiresIPhoneOS
26 |
27 | UIMainStoryboardFile
28 | MainStoryboard_iPhone
29 | UIMainStoryboardFile~ipad
30 | MainStoryboard_iPad
31 | UIRequiredDeviceCapabilities
32 |
33 | armv7
34 |
35 | UISupportedInterfaceOrientations
36 |
37 | UIInterfaceOrientationPortrait
38 |
39 | UISupportedInterfaceOrientations~ipad
40 |
41 | UIInterfaceOrientationPortrait
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/GreenScreen/en.lproj/MainStoryboard_iPad.storyboard:
--------------------------------------------------------------------------------
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 |
--------------------------------------------------------------------------------
/GreenScreen/en.lproj/MainStoryboard_iPhone.storyboard:
--------------------------------------------------------------------------------
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 |
--------------------------------------------------------------------------------
/GreenScreen/UtilityEffect.h:
--------------------------------------------------------------------------------
1 | //
2 | // UtilityEffect.h
3 | //
4 | //
5 | /*
6 | Copyright (c) 2012 Erik M. Buck
7 |
8 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
11 |
12 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
13 | */
14 |
15 |
16 | #import
17 |
18 | @interface UtilityEffect : NSObject
19 |
20 | /////////////////////////////////////////////////////////////////
21 | // This type identifies the vertex attributes used to render
22 | // models, terrain, and billboard particles. Not all effects use
23 | // all attributes.
24 | typedef enum
25 | {
26 | UtilityVertexAttribPosition = GLKVertexAttribPosition,
27 | UtilityVertexAttribNormal = GLKVertexAttribNormal,
28 | UtilityVertexAttribColor = GLKVertexAttribColor,
29 | UtilityVertexAttribTexCoord0 = GLKVertexAttribTexCoord0,
30 | UtilityVertexAttribTexCoord1 = GLKVertexAttribTexCoord1,
31 | UtilityVertexAttribOpacity,
32 | UtilityVertexAttribJointMatrixIndices,
33 | UtilityVertexAttribJointNormalizedWeights,
34 | UtilityVertexNumberOfAttributes,
35 | } UtilityVertexAttribute;
36 |
37 |
38 | @property (assign, nonatomic, readonly) GLuint program;
39 |
40 | - (void)prepareOpenGL;
41 | - (void)updateUniformValues;
42 |
43 | // Required overrides
44 | - (void)bindAttribLocations;
45 | - (void)configureUniformLocations;
46 |
47 | - (BOOL)loadShadersWithName:(NSString *)aShaderName;
48 |
49 | @end
50 |
--------------------------------------------------------------------------------
/GreenScreen/Shaders/greenScreen.fsh:
--------------------------------------------------------------------------------
1 | //
2 | // greenScreen.fsh
3 | // GreenScreen
4 | //
5 | /*
6 | Copyright (c) 2012 Erik M. Buck
7 |
8 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
11 |
12 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
13 | */
14 |
15 | varying highp vec2 vCoordinate;
16 | uniform sampler2D uVideoframe;
17 | uniform highp mat4 uMVPMatrix;
18 |
19 |
20 | void main()
21 | {
22 | // lookup the color of the texel corresponding to the fragment being
23 | // generated while rendering a triangle
24 | lowp vec4 tempColor = texture2D(uVideoframe, vCoordinate);
25 |
26 | // Calculate the average intensity of the texel's red and blue components
27 | lowp float rbAverage = tempColor.r * 0.5 + tempColor.b * 0.5;
28 |
29 | // Calculate the difference between the green element intensity and the
30 | // average of red and blue intensities
31 | lowp float gDelta = tempColor.g - rbAverage;
32 |
33 | // If the green intensity is greater than the average of red and blue
34 | // intensities, calculate a transparency value in the range 0.0 to 1.0
35 | // based on how much more intense the green element is
36 | tempColor.a = 1.0 - smoothstep(0.0, 0.25, gDelta);
37 |
38 | // Use the cube of the of the transparency value. That way, a fragment that
39 | // is partially translucent becomes even more translucent. This sharpens
40 | // the final result by avoiding almost but not quite opaque fragments that
41 | // tend to form halos at color boundaries.
42 | tempColor.a = tempColor.a * tempColor.a * tempColor.a;
43 |
44 | gl_FragColor = tempColor;
45 | }
46 |
47 |
48 |
--------------------------------------------------------------------------------
/GreenScreen/GSVideoProcessor.h:
--------------------------------------------------------------------------------
1 | //
2 | // GSVideoProcessor.h
3 | // GreenScreen
4 | //
5 | /*
6 | Copyright (c) 2012 Erik M. Buck
7 |
8 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
11 |
12 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
13 | */
14 |
15 | #import
16 | #import
17 |
18 | @protocol GSVideoProcessorDelegate;
19 |
20 | @interface GSVideoProcessor : NSObject
21 | {
22 | id __weak delegate;
23 |
24 | NSMutableArray *previousSecondTimestamps;
25 | Float64 videoFrameRate;
26 | CMVideoDimensions videoDimensions;
27 | CMVideoCodecType videoType;
28 |
29 | AVCaptureSession *captureSession;
30 | AVCaptureConnection *videoConnection;
31 | CMBufferQueueRef previewBufferQueue;
32 |
33 | AVAssetWriter *assetWriter;
34 | AVAssetWriterInput *assetWriterVideoIn;
35 | dispatch_queue_t movieWritingQueue;
36 |
37 | AVCaptureVideoOrientation referenceOrientation;
38 | AVCaptureVideoOrientation videoOrientation;
39 |
40 | BOOL readyToRecordVideo;
41 | }
42 |
43 | @property (readwrite, weak) id delegate;
44 | @property (readonly) Float64 videoFrameRate;
45 | @property (readonly) CMVideoDimensions videoDimensions;
46 | @property (readonly) CMVideoCodecType videoType;
47 |
48 | @property (readwrite) AVCaptureVideoOrientation referenceOrientation;
49 |
50 | - (CGAffineTransform)transformForOrientation:(AVCaptureVideoOrientation)orientation;
51 |
52 | - (void) showError:(NSError*)error;
53 |
54 | - (void) setupAndStartCaptureSession;
55 | - (void) stopAndTearDownCaptureSession;
56 |
57 | @end
58 |
59 |
60 | @protocol GSVideoProcessorDelegate
61 |
62 | @required
63 | - (void)pixelBufferReadyForDisplay:(CVPixelBufferRef)pixelBuffer; // This method is always called on the main thread.
64 |
65 | @end
66 |
--------------------------------------------------------------------------------
/GreenScreen.xcodeproj/xcuserdata/erik.xcuserdatad/xcschemes/GreenScreen.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
39 |
40 |
41 |
42 |
43 |
44 |
54 |
56 |
62 |
63 |
64 |
65 |
66 |
67 |
73 |
75 |
81 |
82 |
83 |
84 |
86 |
87 |
90 |
91 |
92 |
--------------------------------------------------------------------------------
/GreenScreen/GSGreenScreenEffect.m:
--------------------------------------------------------------------------------
1 | //
2 | // GSGreenScreenEffect.m
3 | // GreenScreen
4 | //
5 | /*
6 | Copyright (c) 2012 Erik M. Buck
7 |
8 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
11 |
12 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
13 | */
14 |
15 | #import "GSGreenScreenEffect.h"
16 |
17 | /////////////////////////////////////////////////////////////////
18 | // GLSL program uniform indices.
19 | enum
20 | {
21 | GSamplers2D,
22 | GMVPMatrix,
23 | GNumUniforms
24 | };
25 |
26 |
27 | @interface GSGreenScreenEffect ()
28 | {
29 | GLint uniforms[GNumUniforms];
30 | GLKBaseEffect *foo;
31 | }
32 |
33 | @end
34 |
35 |
36 |
37 | @implementation GSGreenScreenEffect
38 |
39 | @synthesize texture2d0 = texture2d0_;
40 | @synthesize transform = transform_;
41 |
42 | /////////////////////////////////////////////////////////////////
43 | // Subclasses should override this implementation to load any
44 | // OpenGL ES 2.0 Shading Language programs prior to drawing any
45 | // geometry with the receiver. The override should typically
46 | // call [self loadShadersWithName:] specifying the
47 | // base name for the desired Shading Language programs.
48 | - (void)prepareOpenGL
49 | {
50 | texture2d0_ = [[GLKEffectPropertyTexture alloc] init];
51 | transform_ = [[GLKEffectPropertyTransform alloc] init];
52 | [self loadShadersWithName:@"greenScreen"];
53 | }
54 |
55 |
56 | /////////////////////////////////////////////////////////////////
57 | // Binds any OpenGL ES 2.0 Shading Language program attributes.
58 | - (void)bindAttribLocations;
59 | {
60 | glBindAttribLocation(
61 | self.program,
62 | UtilityVertexAttribPosition,
63 | "aPosition");
64 | glBindAttribLocation(
65 | self.program,
66 | UtilityVertexAttribTexCoord0,
67 | "aTextureCoordinate");
68 | }
69 |
70 |
71 | /////////////////////////////////////////////////////////////////
72 | // Subclasses should override this implementation to configure
73 | // OpenGL uniform values prior to drawing any geometry with the
74 | // receiver.
75 | - (void)updateUniformValues
76 | {
77 | // Precalculate the mvpMatrix
78 | GLKMatrix4 modelViewProjectionMatrix = GLKMatrix4Multiply(
79 | self.transform.projectionMatrix,
80 | self.transform.modelviewMatrix);
81 | glUniformMatrix4fv(uniforms[GMVPMatrix], 1, 0,
82 | modelViewProjectionMatrix.m);
83 |
84 | // Texture samplers
85 | const GLint samplerIDs[1] = {self.texture2d0.name};
86 | glUniform1iv(uniforms[GSamplers2D], 1,
87 | samplerIDs);
88 | }
89 |
90 |
91 | /////////////////////////////////////////////////////////////////
92 | //
93 | - (void)configureUniformLocations;
94 | {
95 | uniforms[GMVPMatrix] = glGetUniformLocation(
96 | self.program,
97 | "uMVPMatrix");
98 | uniforms[GSamplers2D] = glGetUniformLocation(
99 | self.program,
100 | "uVideoframe");
101 | }
102 |
103 | @end
104 |
--------------------------------------------------------------------------------
/GreenScreen/UtilityEffect.m:
--------------------------------------------------------------------------------
1 | //
2 | // UtilityEffect.m
3 | //
4 | //
5 | /*
6 | Copyright (c) 2012 Erik M. Buck
7 |
8 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
11 |
12 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
13 | */
14 |
15 | #import "UtilityEffect.h"
16 |
17 |
18 | @interface UtilityEffect ()
19 |
20 | @property (assign, nonatomic, readwrite) GLuint program;
21 |
22 | - (BOOL)compileShader:(GLuint *)shader
23 | type:(GLenum)type
24 | file:(NSString *)file;
25 | - (BOOL)linkProgram:(GLuint)prog;
26 | - (BOOL)validateProgram:(GLuint)prog;
27 |
28 | @end
29 |
30 |
31 | @implementation UtilityEffect
32 |
33 | @synthesize program = program_;
34 |
35 | /////////////////////////////////////////////////////////////////
36 | // Destroy OpenGl state used by the receiver
37 | - (void)dealloc
38 | {
39 | if(0 != program_)
40 | {
41 | glUseProgram(0);
42 | glDeleteProgram(program_);
43 | }
44 | }
45 |
46 |
47 | #pragma mark - Rendering
48 |
49 | /////////////////////////////////////////////////////////////////
50 | // Subclasses should override this implementation to load any
51 | // OpenGL ES 2.0 Shading Language programs prior to drawing any
52 | // geometry with the receiver. The override should typically
53 | // call [self loadShadersWithName:] specifying the
54 | // base name for the desired Shading Language programs.
55 | - (void)prepareOpenGL
56 | {
57 | }
58 |
59 |
60 | /////////////////////////////////////////////////////////////////
61 | // Subclasses should override this implementation to configure
62 | // OpenGL uniform values prior to drawing any geometry with the
63 | // receiver.
64 | - (void)updateUniformValues
65 | {
66 | }
67 |
68 |
69 | /////////////////////////////////////////////////////////////////
70 | // If the receiver's OpenGL ES 2.0 Shading Language programs have
71 | // not been loaded, this method calls -prepareOpenGL. This method
72 | // configures the OpenGL state to use the receiver's OpenGL ES
73 | // 2.0 Shading Language programs and then calls
74 | // -updateUniformValues to update any Shading Language program
75 | // specific state required for drawing.
76 | - (void)prepareToDraw;
77 | {
78 | if(0 == self.program)
79 | {
80 | [self prepareOpenGL];
81 |
82 | NSAssert(0 != self.program,
83 | @"prepareOpenGL failed to load shaders");
84 | }
85 |
86 | glUseProgram(self.program);
87 |
88 | [self updateUniformValues];
89 | }
90 |
91 | #pragma mark - OpenGL ES 2 shader compilation overloads
92 |
93 | /////////////////////////////////////////////////////////////////
94 | // Subclasses must override this implementation to bind any
95 | // OpenGL ES 2.0 Shading Language program attributes.
96 | - (void)bindAttribLocations;
97 | {
98 | NSAssert(0,
99 | @"Subclasses failed to override this implementation");
100 | }
101 |
102 |
103 | /////////////////////////////////////////////////////////////////
104 | // Subclasses must override this implementation to bind any
105 | // OpenGL ES 2.0 Shading Language program uniform locations.
106 | - (void)configureUniformLocations;
107 | {
108 | NSAssert(0,
109 | @"Subclasses failed to override this implementation");
110 | }
111 |
112 |
113 | #pragma mark - OpenGL ES 2 shader compilation
114 |
115 | /////////////////////////////////////////////////////////////////
116 | // This method loads and compiles OpenGL ES 2.0 Shading Language
117 | // programs with the root name aShaderName and the
118 | // suffixes/extensions "vsh" and "fsh".
119 | - (BOOL)loadShadersWithName:(NSString *)aShaderName;
120 | {
121 | NSParameterAssert(nil != aShaderName);
122 |
123 | GLuint vertShader, fragShader;
124 | NSString *vertShaderPathname, *fragShaderPathname;
125 |
126 | // Create shader program.
127 | self.program = glCreateProgram();
128 |
129 | // Create and compile vertex shader.
130 | vertShaderPathname = [[NSBundle mainBundle]
131 | pathForResource:aShaderName ofType:@"vsh"];
132 | if (![self compileShader:&vertShader type:GL_VERTEX_SHADER
133 | file:vertShaderPathname])
134 | {
135 | NSLog(@"Failed to compile vertex shader");
136 | return NO;
137 | }
138 |
139 | // Create and compile fragment shader.
140 | fragShaderPathname = [[NSBundle mainBundle]
141 | pathForResource:aShaderName ofType:@"fsh"];
142 | if (![self compileShader:&fragShader type:GL_FRAGMENT_SHADER
143 | file:fragShaderPathname])
144 | {
145 | NSLog(@"Failed to compile fragment shader");
146 | return NO;
147 | }
148 |
149 | // Attach vertex shader to program.
150 | glAttachShader(self.program, vertShader);
151 |
152 | // Attach fragment shader to program.
153 | glAttachShader(self.program, fragShader);
154 |
155 | // Bind attribute locations.
156 | // This needs to be done prior to linking.
157 | [self bindAttribLocations];
158 |
159 | // Link program.
160 | if (![self linkProgram:self.program])
161 | {
162 | NSLog(@"Failed to link program: %d", self.program);
163 |
164 | if (vertShader)
165 | {
166 | glDeleteShader(vertShader);
167 | vertShader = 0;
168 | }
169 | if (fragShader)
170 | {
171 | glDeleteShader(fragShader);
172 | fragShader = 0;
173 | }
174 | if (self.program)
175 | {
176 | glDeleteProgram(self.program);
177 | self.program = 0;
178 | }
179 |
180 | return NO;
181 | }
182 |
183 | // Get uniform locations.
184 | [self configureUniformLocations];
185 |
186 | // Delete vertex and fragment shaders.
187 | if (vertShader)
188 | {
189 | glDetachShader(self.program, vertShader);
190 | glDeleteShader(vertShader);
191 | }
192 | if (fragShader)
193 | {
194 | glDetachShader(self.program, fragShader);
195 | glDeleteShader(fragShader);
196 | }
197 |
198 | return YES;
199 | }
200 |
201 |
202 | /////////////////////////////////////////////////////////////////
203 | //
204 | - (BOOL)compileShader:(GLuint *)shader
205 | type:(GLenum)type
206 | file:(NSString *)file
207 | {
208 | GLint status;
209 | const GLchar *source;
210 |
211 | source = (GLchar *)[[NSString stringWithContentsOfFile:file
212 | encoding:NSUTF8StringEncoding error:nil] UTF8String];
213 | if (!source)
214 | {
215 | NSLog(@"Failed to load vertex shader");
216 | return NO;
217 | }
218 |
219 | *shader = glCreateShader(type);
220 | glShaderSource(*shader, 1, &source, NULL);
221 | glCompileShader(*shader);
222 |
223 | #if defined(DEBUG)
224 | GLint logLength;
225 | glGetShaderiv(*shader, GL_INFO_LOG_LENGTH, &logLength);
226 | if (logLength > 0)
227 | {
228 | GLchar *log = (GLchar *)malloc(logLength);
229 | glGetShaderInfoLog(*shader, logLength, &logLength, log);
230 | NSLog(@"Shader compile log:\n%s", log);
231 | free(log);
232 | }
233 | #endif
234 |
235 | glGetShaderiv(*shader, GL_COMPILE_STATUS, &status);
236 | if (status == 0)
237 | {
238 | glDeleteShader(*shader);
239 | return NO;
240 | }
241 |
242 | return YES;
243 | }
244 |
245 |
246 | /////////////////////////////////////////////////////////////////
247 | //
248 | - (BOOL)linkProgram:(GLuint)prog
249 | {
250 | GLint status;
251 | glLinkProgram(prog);
252 |
253 | #if defined(DEBUG)
254 | GLint logLength;
255 | glGetProgramiv(prog, GL_INFO_LOG_LENGTH, &logLength);
256 | if (logLength > 0)
257 | {
258 | GLchar *log = (GLchar *)malloc(logLength);
259 | glGetProgramInfoLog(prog, logLength, &logLength, log);
260 | NSLog(@"Program link log:\n%s", log);
261 | free(log);
262 | }
263 | #endif
264 |
265 | glGetProgramiv(prog, GL_LINK_STATUS, &status);
266 | if (status == 0)
267 | {
268 | return NO;
269 | }
270 |
271 | return YES;
272 | }
273 |
274 |
275 | /////////////////////////////////////////////////////////////////
276 | //
277 | - (BOOL)validateProgram:(GLuint)prog
278 | {
279 | GLint logLength, status;
280 |
281 | glValidateProgram(prog);
282 | glGetProgramiv(prog, GL_INFO_LOG_LENGTH, &logLength);
283 | if (logLength > 0)
284 | {
285 | GLchar *log = (GLchar *)malloc(logLength);
286 | glGetProgramInfoLog(prog, logLength, &logLength, log);
287 | NSLog(@"Program validate log:\n%s", log);
288 | free(log);
289 | }
290 |
291 | glGetProgramiv(prog, GL_VALIDATE_STATUS, &status);
292 | if (status == 0)
293 | {
294 | return NO;
295 | }
296 |
297 | return YES;
298 | }
299 |
300 | @end
301 |
--------------------------------------------------------------------------------
/GreenScreen/GSVideoProcessor.m:
--------------------------------------------------------------------------------
1 | //
2 | // GSVideoProcessor.m
3 | // GreenScreen
4 | //
5 | /*
6 | Copyright (c) 2012 Erik M. Buck
7 |
8 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
11 |
12 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
13 | */
14 |
15 | #import
16 | #import
17 | #import "GSVideoProcessor.h"
18 |
19 | @interface GSVideoProcessor ()
20 |
21 | // Redeclared as readwrite
22 | @property (readwrite) Float64 videoFrameRate;
23 | @property (readwrite) CMVideoDimensions videoDimensions;
24 | @property (readwrite) CMVideoCodecType videoType;
25 | @property (readwrite) AVCaptureVideoOrientation videoOrientation;
26 |
27 | @end
28 |
29 | @implementation GSVideoProcessor
30 |
31 | @synthesize delegate;
32 | @synthesize videoFrameRate, videoDimensions, videoType;
33 | @synthesize referenceOrientation;
34 | @synthesize videoOrientation;
35 |
36 |
37 | /////////////////////////////////////////////////////////////////
38 | //
39 | - (id) init
40 | {
41 | if (self = [super init])
42 | {
43 | previousSecondTimestamps = [[NSMutableArray alloc] init];
44 | referenceOrientation = AVCaptureVideoOrientationPortrait;
45 | }
46 | return self;
47 | }
48 |
49 |
50 | #pragma mark Utilities
51 |
52 | /////////////////////////////////////////////////////////////////
53 | //
54 | - (void) calculateFramerateAtTimestamp:(CMTime) timestamp
55 | {
56 | [previousSecondTimestamps addObject:[NSValue valueWithCMTime:timestamp]];
57 |
58 | CMTime oneSecond = CMTimeMake( 1, 1 );
59 | CMTime oneSecondAgo = CMTimeSubtract( timestamp, oneSecond );
60 |
61 | while( CMTIME_COMPARE_INLINE( [[previousSecondTimestamps objectAtIndex:0]
62 | CMTimeValue], <, oneSecondAgo ) )
63 | {
64 | [previousSecondTimestamps removeObjectAtIndex:0];
65 | }
66 |
67 | Float64 newRate = (Float64) [previousSecondTimestamps count];
68 | self.videoFrameRate = (self.videoFrameRate + newRate) / 2;
69 | }
70 |
71 |
72 | /////////////////////////////////////////////////////////////////
73 | //
74 | - (CGFloat)angleOffsetFromPortrait:(AVCaptureVideoOrientation)orientation
75 | {
76 | CGFloat angle = 0.0;
77 |
78 | switch (orientation)
79 | {
80 | case AVCaptureVideoOrientationPortrait:
81 | angle = 0.0;
82 | break;
83 | case AVCaptureVideoOrientationPortraitUpsideDown:
84 | angle = M_PI;
85 | break;
86 | case AVCaptureVideoOrientationLandscapeRight:
87 | angle = -M_PI_2;
88 | break;
89 | case AVCaptureVideoOrientationLandscapeLeft:
90 | angle = M_PI_2;
91 | break;
92 | default:
93 | break;
94 | }
95 |
96 | return angle;
97 | }
98 |
99 |
100 | /////////////////////////////////////////////////////////////////
101 | //
102 | - (CGAffineTransform)transformForOrientation:(AVCaptureVideoOrientation)orientation
103 | {
104 | CGAffineTransform transform = CGAffineTransformIdentity;
105 |
106 | // Calculate offsets from an arbitrary reference orientation (portrait)
107 | CGFloat orientationAngleOffset =
108 | [self angleOffsetFromPortrait:orientation];
109 | CGFloat videoOrientationAngleOffset =
110 | [self angleOffsetFromPortrait:self.videoOrientation];
111 |
112 | // Find the difference in angle between the passed in orientation and the
113 | // current video orientation
114 | CGFloat angleOffset = orientationAngleOffset - videoOrientationAngleOffset;
115 | transform = CGAffineTransformMakeRotation(angleOffset);
116 |
117 | return transform;
118 | }
119 |
120 |
121 | #pragma mark Video Input
122 |
123 | /////////////////////////////////////////////////////////////////
124 | //
125 | - (BOOL)setupAssetWriterVideoInput:(CMFormatDescriptionRef)currentFormatDescription
126 | {
127 | float bitsPerPixel;
128 | CMVideoDimensions dimensions =
129 | CMVideoFormatDescriptionGetDimensions(currentFormatDescription);
130 | int numPixels = dimensions.width * dimensions.height;
131 | int bitsPerSecond;
132 |
133 | // Assume that lower-than-SD resolutions are intended for streaming, and use
134 | // a lower bitrate
135 | if ( numPixels < (640 * 480) )
136 | {
137 | bitsPerPixel = 4.05; // matches quality of AVCaptureSessionPresetMedium.
138 | }
139 | else
140 | {
141 | bitsPerPixel = 11.4; // matches quality of AVCaptureSessionPresetHigh.
142 | }
143 |
144 | bitsPerSecond = numPixels * bitsPerPixel;
145 |
146 | NSDictionary *videoCompressionSettings =
147 | @{AVVideoCodecKey: AVVideoCodecH264,
148 | AVVideoWidthKey: @(dimensions.width),
149 | AVVideoHeightKey: @(dimensions.height),
150 | AVVideoCompressionPropertiesKey: @{AVVideoAverageBitRateKey:
151 | @(bitsPerSecond),
152 | AVVideoMaxKeyFrameIntervalKey: @30}};
153 |
154 | if ([assetWriter canApplyOutputSettings:videoCompressionSettings
155 | forMediaType:AVMediaTypeVideo])
156 | {
157 | assetWriterVideoIn = [[AVAssetWriterInput alloc]
158 | initWithMediaType:AVMediaTypeVideo
159 | outputSettings:videoCompressionSettings];
160 | assetWriterVideoIn.expectsMediaDataInRealTime = YES;
161 | assetWriterVideoIn.transform =
162 | [self transformForOrientation:self.referenceOrientation];
163 |
164 | if ([assetWriter canAddInput:assetWriterVideoIn])
165 | {
166 | [assetWriter addInput:assetWriterVideoIn];
167 | }
168 | else
169 | {
170 | NSLog(@"Couldn't add asset writer video input.");
171 | return NO;
172 | }
173 | }
174 | else
175 | {
176 | NSLog(@"Couldn't apply video output settings.");
177 | return NO;
178 | }
179 |
180 | return YES;
181 | }
182 |
183 |
184 | #pragma mark Capture
185 |
186 | /////////////////////////////////////////////////////////////////
187 | //
188 | - (void)captureOutput:(AVCaptureOutput *)captureOutput
189 | didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer
190 | fromConnection:(AVCaptureConnection *)connection
191 | {
192 | CMFormatDescriptionRef formatDescription =
193 | CMSampleBufferGetFormatDescription(sampleBuffer);
194 |
195 | if ( connection == videoConnection )
196 | {
197 | // Get framerate
198 | CMTime timestamp = CMSampleBufferGetPresentationTimeStamp( sampleBuffer );
199 | [self calculateFramerateAtTimestamp:timestamp];
200 |
201 | // Get frame dimensions (for onscreen display)
202 | if (self.videoDimensions.width == 0 && self.videoDimensions.height == 0)
203 | {
204 | self.videoDimensions =
205 | CMVideoFormatDescriptionGetDimensions( formatDescription );
206 | }
207 |
208 | // Get buffer type
209 | if ( self.videoType == 0 )
210 | {
211 | self.videoType =
212 | CMFormatDescriptionGetMediaSubType( formatDescription );
213 | }
214 |
215 | // Enqueue it for preview. This is a shallow queue, so if image
216 | // processing is taking too long, we'll drop this frame for preview (this
217 | // keeps preview latency low).
218 | OSStatus err = CMBufferQueueEnqueue(previewBufferQueue, sampleBuffer);
219 | if ( !err ) {
220 | dispatch_async(dispatch_get_main_queue(), ^{
221 | CMSampleBufferRef sbuf =
222 | (CMSampleBufferRef)CMBufferQueueDequeueAndRetain(
223 | previewBufferQueue);
224 |
225 | if (sbuf)
226 | {
227 | CVImageBufferRef pixBuf = CMSampleBufferGetImageBuffer(sbuf);
228 | [self.delegate pixelBufferReadyForDisplay:pixBuf];
229 | CFRelease(sbuf);
230 | }
231 | });
232 | }
233 | }
234 |
235 | CFRetain(sampleBuffer);
236 | CFRetain(formatDescription);
237 | dispatch_async(movieWritingQueue,
238 | ^{
239 | if ( assetWriter )
240 | {
241 | if (connection == videoConnection)
242 | {
243 | // Initialize the video input if this is not done yet
244 | if (!readyToRecordVideo)
245 | {
246 | readyToRecordVideo =
247 | [self setupAssetWriterVideoInput:formatDescription];
248 | }
249 | }
250 | }
251 |
252 | CFRelease(sampleBuffer);
253 | CFRelease(formatDescription);
254 | });
255 | }
256 |
257 |
258 | /////////////////////////////////////////////////////////////////
259 | //
260 | - (AVCaptureDevice *)videoDeviceWithPosition:(AVCaptureDevicePosition)position
261 | {
262 | NSArray *devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo];
263 | for (AVCaptureDevice *device in devices)
264 | if ([device position] == position)
265 | return device;
266 |
267 | return nil;
268 | }
269 |
270 |
271 | /////////////////////////////////////////////////////////////////
272 | //
273 | - (BOOL) setupCaptureSession
274 | {
275 | /*
276 | * Create capture session
277 | */
278 | captureSession = [[AVCaptureSession alloc] init];
279 |
280 | /*
281 | * Create video connection
282 | */
283 | AVCaptureDeviceInput *videoIn = [[AVCaptureDeviceInput alloc]
284 | initWithDevice:[self videoDeviceWithPosition:AVCaptureDevicePositionBack]
285 | error:nil];
286 |
287 | if ([captureSession canAddInput:videoIn])
288 | {
289 | [captureSession addInput:videoIn];
290 | }
291 |
292 | AVCaptureVideoDataOutput *videoOut = [[AVCaptureVideoDataOutput alloc] init];
293 | /*
294 | Processing can take longer than real-time on some platforms.
295 | Clients whose image processing is faster than real-time should consider
296 | setting AVCaptureVideoDataOutput's alwaysDiscardsLateVideoFrames property
297 | to NO.
298 | */
299 | [videoOut setAlwaysDiscardsLateVideoFrames:YES];
300 | [videoOut setVideoSettings:
301 | @{(id)kCVPixelBufferPixelFormatTypeKey: @(kCVPixelFormatType_32BGRA)}];
302 | dispatch_queue_t videoCaptureQueue =
303 | dispatch_queue_create("Video Capture Queue", DISPATCH_QUEUE_SERIAL);
304 | [videoOut setSampleBufferDelegate:self queue:videoCaptureQueue];
305 | //dispatch_release(videoCaptureQueue);
306 | if ([captureSession canAddOutput:videoOut])
307 | [captureSession addOutput:videoOut];
308 | videoConnection = [videoOut connectionWithMediaType:AVMediaTypeVideo];
309 | self.videoOrientation = [videoConnection videoOrientation];
310 |
311 | return YES;
312 | }
313 |
314 |
315 | /////////////////////////////////////////////////////////////////
316 | //
317 | - (void) setupAndStartCaptureSession
318 | {
319 | // Create a shallow queue for buffers going to the display for preview.
320 | OSStatus err = CMBufferQueueCreate(
321 | kCFAllocatorDefault,
322 | 1,
323 | CMBufferQueueGetCallbacksForUnsortedSampleBuffers(),
324 | &previewBufferQueue);
325 |
326 | if (err)
327 | {
328 | [self showError:[NSError errorWithDomain:NSOSStatusErrorDomain
329 | code:err
330 | userInfo:nil]];
331 | }
332 |
333 | // Create serial queue for movie writing
334 | movieWritingQueue =
335 | dispatch_queue_create("Movie Writing Queue", DISPATCH_QUEUE_SERIAL);
336 |
337 | if ( !captureSession )
338 | {
339 | [self setupCaptureSession];
340 | }
341 |
342 | [[NSNotificationCenter defaultCenter]
343 | addObserver:self
344 | selector:@selector(captureSessionStoppedRunningNotification:)
345 | name:AVCaptureSessionDidStopRunningNotification
346 | object:captureSession];
347 |
348 | if ( !captureSession.isRunning )
349 | {
350 | [captureSession startRunning];
351 | }
352 | }
353 |
354 |
355 | /////////////////////////////////////////////////////////////////
356 | //
357 | - (void)captureSessionStoppedRunningNotification:(NSNotification *)notification
358 | {
359 | dispatch_async(movieWritingQueue, ^{
360 | });
361 | }
362 |
363 |
364 | /////////////////////////////////////////////////////////////////
365 | //
366 | - (void) stopAndTearDownCaptureSession
367 | {
368 | [captureSession stopRunning];
369 | if (captureSession)
370 | {
371 | [[NSNotificationCenter defaultCenter]
372 | removeObserver:self
373 | name:AVCaptureSessionDidStopRunningNotification
374 | object:captureSession];
375 | }
376 |
377 | captureSession = nil;
378 | if (previewBufferQueue)
379 | {
380 | CFRelease(previewBufferQueue);
381 | previewBufferQueue = NULL;
382 | }
383 |
384 | if (movieWritingQueue)
385 | {
386 | //dispatch_release(movieWritingQueue);
387 | movieWritingQueue = NULL;
388 | }
389 | }
390 |
391 |
392 | #pragma mark Error Handling
393 |
394 | /////////////////////////////////////////////////////////////////
395 | //
396 | - (void)showError:(NSError *)error
397 | {
398 | CFRunLoopPerformBlock(
399 | CFRunLoopGetMain(),
400 | kCFRunLoopCommonModes,
401 | ^(void)
402 | {
403 | UIAlertView *alertView =
404 | [[UIAlertView alloc] initWithTitle:
405 | [error localizedDescription]
406 | message:[error localizedFailureReason]
407 | delegate:nil
408 | cancelButtonTitle:@"OK"
409 | otherButtonTitles:nil];
410 | [alertView show];
411 | });
412 | }
413 |
414 | @end
415 |
--------------------------------------------------------------------------------
/GreenScreen/GSViewController.m:
--------------------------------------------------------------------------------
1 | //
2 | // GSViewController.m
3 | // GreenScreen
4 | //
5 | /*
6 | Copyright (c) 2012 Erik M. Buck
7 |
8 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
11 |
12 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
13 | */
14 |
15 | #import "GSViewController.h"
16 | #import "GSVideoProcessor.h"
17 | #import "GSGreenScreenEffect.h"
18 | #include
19 |
20 | @interface GSViewController ()
21 |
22 |
23 | @property (nonatomic, readwrite, strong)
24 | GSVideoProcessor *videoProcessor;
25 | @property (nonatomic, readwrite, assign)
26 | CVOpenGLESTextureCacheRef videoTextureCache;
27 | @property (strong, nonatomic)
28 | GLKBaseEffect *baseEffect;
29 | @property (strong, nonatomic)
30 | GSGreenScreenEffect *greenScreenEffect;
31 | @property (strong, nonatomic)
32 | GLKTextureInfo *background;
33 |
34 | - (void)updateLabels;
35 | - (UILabel *)labelWithText:(NSString *)text yPosition:(CGFloat)yPosition;
36 |
37 | @end
38 |
39 |
40 | @implementation GSViewController
41 |
42 | @synthesize videoProcessor = videoProcessor_;
43 | @synthesize videoTextureCache = videoTextureCache_;
44 | @synthesize baseEffect = baseEffect_;
45 |
46 |
47 | /////////////////////////////////////////////////////////////////
48 | //
49 | - (void)viewDidLoad
50 | {
51 | [super viewDidLoad];
52 |
53 | // Verify the type of view created automatically by the
54 | // Interface Builder storyboard
55 | GLKView *view = (GLKView *)self.view;
56 | NSAssert([view isKindOfClass:[GLKView class]],
57 | @"View controller's view is not a GLKView");
58 |
59 | // Create an OpenGL ES 2.0 context and provide it to the
60 | // view
61 | view.context = [[EAGLContext alloc]
62 | initWithAPI:kEAGLRenderingAPIOpenGLES2];
63 | view.layer.opaque = YES;
64 |
65 | CAEAGLLayer *eaglLayer = (CAEAGLLayer *)view.layer;
66 | eaglLayer.drawableProperties = [NSDictionary dictionaryWithObjectsAndKeys:
67 | [NSNumber numberWithBool:NO], kEAGLDrawablePropertyRetainedBacking,
68 | kEAGLColorFormatRGBA8, kEAGLDrawablePropertyColorFormat,
69 | nil];
70 |
71 | // Make the new context current
72 | [EAGLContext setCurrentContext:view.context];
73 |
74 | // Create a base effect that provides standard OpenGL ES 2.0
75 | // Shading Language programs and set constants to be used for
76 | // all subsequent rendering
77 | self.greenScreenEffect = [[GSGreenScreenEffect alloc] init];
78 |
79 | // Create a base effect that provides standard OpenGL ES 2.0
80 | // Shading Language programs and set constants to be used for
81 | // all subsequent rendering
82 | self.baseEffect = [[GLKBaseEffect alloc] init];
83 |
84 | if(nil == self.background)
85 | {
86 | self.background = [GLKTextureLoader textureWithCGImage:
87 | [[UIImage imageNamed:@"Elephant.jpg"] CGImage]
88 | options:nil
89 | error:NULL];
90 | }
91 | self.baseEffect.texture2d0.name = self.background.name;
92 | self.baseEffect.texture2d0.target = self.background.target;
93 |
94 | // Set the background color
95 | glClearColor(
96 | 0.0f, // Red
97 | 0.0f, // Green
98 | 0.0f, // Blue
99 | 0.0f);// Alpha
100 | glEnable(GL_BLEND);
101 | glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
102 |
103 | // Create a new CVOpenGLESTexture cache
104 | CVReturn err = CVOpenGLESTextureCacheCreate(
105 | kCFAllocatorDefault,
106 | NULL,
107 | (__bridge CVEAGLContext)((__bridge void *)view.context),
108 | NULL,
109 | &videoTextureCache_);
110 |
111 | if (err)
112 | {
113 | NSLog(@"Error at CVOpenGLESTextureCacheCreate %d", err);
114 | }
115 |
116 | // Keep track of changes to the device orientation so we can
117 | // update the video processor
118 | NSNotificationCenter *notificationCenter =
119 | [NSNotificationCenter defaultCenter];
120 | [notificationCenter addObserver:self
121 | selector:@selector(deviceOrientationDidChange)
122 | name:UIDeviceOrientationDidChangeNotification
123 | object:nil];
124 | [[UIDevice currentDevice]
125 | beginGeneratingDeviceOrientationNotifications];
126 |
127 | // Setup video processor
128 | self.videoProcessor = [[GSVideoProcessor alloc] init];
129 | self.videoProcessor.delegate = self;
130 | [self.videoProcessor setupAndStartCaptureSession];
131 | }
132 |
133 |
134 | /////////////////////////////////////////////////////////////////
135 | //
136 | - (void)viewDidUnload
137 | {
138 | NSNotificationCenter *notificationCenter =
139 | [NSNotificationCenter defaultCenter];
140 | [notificationCenter removeObserver:self
141 | name:UIDeviceOrientationDidChangeNotification
142 | object:nil];
143 | [[UIDevice currentDevice]
144 | endGeneratingDeviceOrientationNotifications];
145 |
146 | [super viewDidUnload];
147 |
148 | // Make the view's context current
149 | GLKView *view = (GLKView *)self.view;
150 | [EAGLContext setCurrentContext:view.context];
151 |
152 | // Stop using the context created in -viewDidLoad
153 | [EAGLContext setCurrentContext:nil];
154 |
155 | self.greenScreenEffect = nil;
156 | self.baseEffect = nil;
157 | [self.videoProcessor stopAndTearDownCaptureSession];
158 | self.videoProcessor.delegate = nil;
159 | self.videoProcessor = nil;
160 | }
161 |
162 |
163 | /////////////////////////////////////////////////////////////////
164 | //
165 | - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
166 | {
167 | // Native video orientation is landscape with the button on the right.
168 | // The video processor rotates vide as needed, so don't autorotate also
169 | return (interfaceOrientation == UIInterfaceOrientationLandscapeRight);
170 | }
171 |
172 |
173 | /////////////////////////////////////////////////////////////////
174 | //
175 | - (void)deviceOrientationDidChange
176 | {
177 | UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation];
178 |
179 | // Don't update the reference orientation when the device orientation is
180 | // face up/down or unknown.
181 | if(UIDeviceOrientationIsPortrait(orientation))
182 | {
183 | [self.videoProcessor setReferenceOrientation:
184 | AVCaptureVideoOrientationPortrait];
185 | }
186 | else if(UIDeviceOrientationIsLandscape(orientation) )
187 | {
188 | [self.videoProcessor setReferenceOrientation:
189 | AVCaptureVideoOrientationLandscapeRight];
190 | }
191 | }
192 |
193 |
194 | #pragma mark - GLKView Delegate
195 |
196 | /////////////////////////////////////////////////////////////////
197 | //
198 | - (void)update
199 | {
200 | [self updateLabels];
201 | }
202 |
203 |
204 | #pragma mark - Render Support
205 |
206 | /////////////////////////////////////////////////////////////////
207 | //
208 | - (CGRect)textureSamplingRectForCroppingTextureWithAspectRatio:
209 | (CGSize)textureAspectRatio
210 | toAspectRatio:(CGSize)croppingAspectRatio
211 | {
212 | CGRect normalizedSamplingRect = CGRectZero;
213 | CGSize cropScaleAmount =
214 | CGSizeMake(croppingAspectRatio.width / textureAspectRatio.width,
215 | croppingAspectRatio.height / textureAspectRatio.height);
216 | CGFloat maxScale = fmax(cropScaleAmount.width, cropScaleAmount.height);
217 | CGSize scaledTextureSize =
218 | CGSizeMake(textureAspectRatio.width * maxScale,
219 | textureAspectRatio.height * maxScale);
220 |
221 | if ( cropScaleAmount.height > cropScaleAmount.width )
222 | {
223 | normalizedSamplingRect.size.width =
224 | croppingAspectRatio.width / scaledTextureSize.width;
225 | normalizedSamplingRect.size.height = 1.0;
226 | }
227 | else
228 | {
229 | normalizedSamplingRect.size.height =
230 | croppingAspectRatio.height / scaledTextureSize.height;
231 | normalizedSamplingRect.size.width = 1.0;
232 | }
233 |
234 | // Center crop
235 | normalizedSamplingRect.origin.x =
236 | (1.0 - normalizedSamplingRect.size.width)/2.0;
237 | normalizedSamplingRect.origin.y =
238 | (1.0 - normalizedSamplingRect.size.height)/2.0;
239 |
240 | return normalizedSamplingRect;
241 | }
242 |
243 |
244 | /////////////////////////////////////////////////////////////////
245 | //
246 | - (void)renderWithSquareVertices:(const GLfloat*)squareVertices
247 | textureVertices:(const GLfloat*)textureVertices
248 | {
249 | // Update attribute values.
250 | glVertexAttribPointer(GLKVertexAttribPosition,
251 | 2,
252 | GL_FLOAT,
253 | 0,
254 | 0,
255 | squareVertices);
256 | glEnableVertexAttribArray(GLKVertexAttribPosition);
257 | glVertexAttribPointer(GLKVertexAttribTexCoord0,
258 | 2,
259 | GL_FLOAT,
260 | 0,
261 | 0,
262 | textureVertices);
263 | glEnableVertexAttribArray(GLKVertexAttribTexCoord0);
264 |
265 | glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
266 | }
267 |
268 |
269 | #pragma mark - GSVideoProcessorDelegate
270 |
271 | /////////////////////////////////////////////////////////////////
272 | //
273 | - (void)pixelBufferReadyForDisplay:(CVPixelBufferRef)pixelBuffer
274 | {
275 | NSParameterAssert(pixelBuffer);
276 | NSAssert(nil != videoTextureCache_, @"nil texture cache");
277 |
278 | // Create a CVOpenGLESTexture from the CVImageBuffer
279 | size_t frameWidth = CVPixelBufferGetWidth(pixelBuffer);
280 | size_t frameHeight = CVPixelBufferGetHeight(pixelBuffer);
281 | CVOpenGLESTextureRef texture = NULL;
282 | CVReturn err = CVOpenGLESTextureCacheCreateTextureFromImage(
283 | kCFAllocatorDefault,
284 | videoTextureCache_,
285 | pixelBuffer,
286 | NULL,
287 | GL_TEXTURE_2D,
288 | GL_RGBA,
289 | frameWidth,
290 | frameHeight,
291 | GL_BGRA,
292 | GL_UNSIGNED_BYTE,
293 | 0,
294 | &texture);
295 |
296 |
297 | if (!texture || err)
298 | {
299 | NSLog(@"CVOpenGLESTextureCacheCreateTextureFromImage (error: %d)",
300 | err);
301 | return;
302 | }
303 |
304 | static const GLfloat squareVertices[] =
305 | {
306 | -1.0f, -1.0f,
307 | 1.0f, -1.0f,
308 | -1.0f, 1.0f,
309 | 1.0f, 1.0f,
310 | };
311 |
312 | // The texture vertices are set up such that we flip the texture vertically.
313 | // This is so that our top left origin buffers match OpenGL's bottom left texture coordinate system.
314 | CGRect textureSamplingRect =
315 | [self textureSamplingRectForCroppingTextureWithAspectRatio:
316 | CGSizeMake(frameWidth, frameHeight)
317 | toAspectRatio:self.view.bounds.size];
318 |
319 | GLfloat textureVertices[] =
320 | {
321 | CGRectGetMinX(textureSamplingRect), CGRectGetMaxY(textureSamplingRect),
322 | CGRectGetMaxX(textureSamplingRect), CGRectGetMaxY(textureSamplingRect),
323 | CGRectGetMinX(textureSamplingRect), CGRectGetMinY(textureSamplingRect),
324 | CGRectGetMaxX(textureSamplingRect), CGRectGetMinY(textureSamplingRect),
325 | };
326 |
327 | glBindTexture(
328 | CVOpenGLESTextureGetTarget(texture),
329 | CVOpenGLESTextureGetName(texture));
330 |
331 | // Set texture parameters
332 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
333 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
334 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
335 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
336 |
337 | // Draw the texture on the screen with OpenGL ES 2
338 | glDisable(GL_BLEND);
339 | [self.greenScreenEffect prepareToDraw];
340 | [self renderWithSquareVertices:squareVertices
341 | textureVertices:textureVertices];
342 |
343 | glBindTexture(CVOpenGLESTextureGetTarget(texture), 0);
344 |
345 | // Flush the CVOpenGLESTexture cache and release the texture
346 | CVOpenGLESTextureCacheFlush(videoTextureCache_, 0);
347 | CFRelease(texture);
348 |
349 | // Draw the texture on the screen with OpenGL ES 2
350 | glEnable(GL_BLEND);
351 | glBlendFunc(GL_ONE_MINUS_DST_ALPHA, GL_DST_ALPHA);
352 | [self.baseEffect prepareToDraw];
353 | [self renderWithSquareVertices:squareVertices
354 | textureVertices:textureVertices];
355 | glFlush();
356 |
357 | // Present
358 | GLKView *glkView = (GLKView *)self.view;
359 | [glkView.context presentRenderbuffer:GL_RENDERBUFFER];
360 | }
361 |
362 |
363 | #pragma mark - update video statistics
364 |
365 | /////////////////////////////////////////////////////////////////
366 | //
367 | - (void)updateLabels
368 | {
369 | NSString *frameRateString =
370 | [NSString stringWithFormat:@"%.2f FPS ",
371 | [self.videoProcessor videoFrameRate]];
372 | self.frameRateLabel.text = frameRateString;
373 | [self.frameRateLabel setBackgroundColor:
374 | [UIColor colorWithRed:0.0 green:0.0 blue:0.0 alpha:0.25]];
375 |
376 | NSString *dimensionsString =
377 | [NSString stringWithFormat:@"%d x %d ",
378 | [self.videoProcessor videoDimensions].width,
379 | [self.videoProcessor videoDimensions].height];
380 | self.dimensionsLabel.text = dimensionsString;
381 | [self.dimensionsLabel setBackgroundColor:
382 | [UIColor colorWithRed:0.0 green:0.0 blue:0.0 alpha:0.25]];
383 |
384 | CMVideoCodecType type = [self.videoProcessor videoType];
385 | type = OSSwapHostToBigInt32( type );
386 | NSString *typeString = [NSString stringWithFormat:@"%.4s ",
387 | (char*)&type];
388 | self.typeLabel.text = typeString;
389 | [self.typeLabel setBackgroundColor:
390 | [UIColor colorWithRed:0.0 green:0.0 blue:0.0 alpha:0.25]];
391 | }
392 |
393 |
394 | /////////////////////////////////////////////////////////////////
395 | //
396 | - (UILabel *)labelWithText:(NSString *)text yPosition:(CGFloat)yPosition
397 | {
398 | CGFloat labelWidth = 200.0;
399 | CGFloat labelHeight = 40.0;
400 | CGFloat xPosition = self.view.bounds.size.width - labelWidth - 10;
401 | CGRect labelFrame =
402 | CGRectMake(xPosition, yPosition, labelWidth, labelHeight);
403 | UILabel *label = [[UILabel alloc] initWithFrame:labelFrame];
404 | [label setFont:[UIFont systemFontOfSize:36]];
405 | [label setLineBreakMode:NSLineBreakByTruncatingMiddle];
406 | [label setTextAlignment:NSTextAlignmentRight];
407 | [label setTextColor:[UIColor whiteColor]];
408 | [label setBackgroundColor:
409 | [UIColor colorWithRed:0.0 green:0.0 blue:0.0 alpha:0.25]];
410 | [[label layer] setCornerRadius: 4];
411 | [label setText:text];
412 |
413 | return label;
414 | }
415 |
416 |
417 |
418 | @end
419 |
--------------------------------------------------------------------------------
/GreenScreen.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 46;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 036178A515C84F8300C838E8 /* GSGreenScreenEffect.m in Sources */ = {isa = PBXBuildFile; fileRef = 036178A115C84F8300C838E8 /* GSGreenScreenEffect.m */; };
11 | 036178A615C84F8300C838E8 /* greenScreen.fsh in Resources */ = {isa = PBXBuildFile; fileRef = 036178A315C84F8300C838E8 /* greenScreen.fsh */; };
12 | 036178A715C84F8300C838E8 /* greenScreen.vsh in Resources */ = {isa = PBXBuildFile; fileRef = 036178A415C84F8300C838E8 /* greenScreen.vsh */; };
13 | 036178AB15C8511100C838E8 /* UtilityEffect.m in Sources */ = {isa = PBXBuildFile; fileRef = 036178AA15C8511100C838E8 /* UtilityEffect.m */; };
14 | 036178AD15C8565000C838E8 /* Elephant.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 036178AC15C8565000C838E8 /* Elephant.jpg */; };
15 | 0387DE7B18317292002BC568 /* Default-568h@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 0387DE7A18317292002BC568 /* Default-568h@2x.png */; };
16 | 03AF043C15C84C230061A0D7 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 03AF043B15C84C230061A0D7 /* UIKit.framework */; };
17 | 03AF043E15C84C230061A0D7 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 03AF043D15C84C230061A0D7 /* Foundation.framework */; };
18 | 03AF044015C84C230061A0D7 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 03AF043F15C84C230061A0D7 /* CoreGraphics.framework */; };
19 | 03AF044615C84C230061A0D7 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 03AF044415C84C230061A0D7 /* InfoPlist.strings */; };
20 | 03AF044815C84C230061A0D7 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 03AF044715C84C230061A0D7 /* main.m */; };
21 | 03AF044C15C84C230061A0D7 /* GSAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 03AF044B15C84C230061A0D7 /* GSAppDelegate.m */; };
22 | 03AF044F15C84C230061A0D7 /* MainStoryboard_iPhone.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 03AF044D15C84C230061A0D7 /* MainStoryboard_iPhone.storyboard */; };
23 | 03AF045215C84C230061A0D7 /* MainStoryboard_iPad.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 03AF045015C84C230061A0D7 /* MainStoryboard_iPad.storyboard */; };
24 | 03AF045515C84C230061A0D7 /* GSViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 03AF045415C84C230061A0D7 /* GSViewController.m */; };
25 | 03AF045D15C84C760061A0D7 /* GLKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 03AF045B15C84C760061A0D7 /* GLKit.framework */; };
26 | 03AF045E15C84C760061A0D7 /* OpenGLES.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 03AF045C15C84C760061A0D7 /* OpenGLES.framework */; };
27 | 03AF046115C84CD10061A0D7 /* GSVideoProcessor.m in Sources */ = {isa = PBXBuildFile; fileRef = 03AF046015C84CD10061A0D7 /* GSVideoProcessor.m */; };
28 | 03AF046415C84CF70061A0D7 /* AVFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 03AF046215C84CF70061A0D7 /* AVFoundation.framework */; };
29 | 03AF046515C84CF70061A0D7 /* CoreMotion.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 03AF046315C84CF70061A0D7 /* CoreMotion.framework */; };
30 | 03AF046715C84D190061A0D7 /* CoreVideo.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 03AF046615C84D190061A0D7 /* CoreVideo.framework */; };
31 | 03AF046915C84D340061A0D7 /* AssetsLibrary.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 03AF046815C84D340061A0D7 /* AssetsLibrary.framework */; };
32 | 03AF046B15C84D690061A0D7 /* CoreMedia.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 03AF046A15C84D690061A0D7 /* CoreMedia.framework */; };
33 | 03AF046D15C84D8C0061A0D7 /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 03AF046C15C84D8C0061A0D7 /* QuartzCore.framework */; };
34 | 03AF046F15C84DA20061A0D7 /* MobileCoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 03AF046E15C84DA20061A0D7 /* MobileCoreServices.framework */; };
35 | /* End PBXBuildFile section */
36 |
37 | /* Begin PBXFileReference section */
38 | 036178A015C84F8300C838E8 /* GSGreenScreenEffect.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GSGreenScreenEffect.h; sourceTree = ""; };
39 | 036178A115C84F8300C838E8 /* GSGreenScreenEffect.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GSGreenScreenEffect.m; sourceTree = ""; };
40 | 036178A315C84F8300C838E8 /* greenScreen.fsh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.glsl; path = greenScreen.fsh; sourceTree = ""; };
41 | 036178A415C84F8300C838E8 /* greenScreen.vsh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.glsl; path = greenScreen.vsh; sourceTree = ""; };
42 | 036178A915C8511100C838E8 /* UtilityEffect.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UtilityEffect.h; sourceTree = ""; };
43 | 036178AA15C8511100C838E8 /* UtilityEffect.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UtilityEffect.m; sourceTree = ""; };
44 | 036178AC15C8565000C838E8 /* Elephant.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = Elephant.jpg; sourceTree = ""; };
45 | 0387DE7A18317292002BC568 /* Default-568h@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default-568h@2x.png"; sourceTree = ""; };
46 | 03AF043715C84C230061A0D7 /* GreenScreen.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = GreenScreen.app; sourceTree = BUILT_PRODUCTS_DIR; };
47 | 03AF043B15C84C230061A0D7 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; };
48 | 03AF043D15C84C230061A0D7 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
49 | 03AF043F15C84C230061A0D7 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; };
50 | 03AF044315C84C230061A0D7 /* GreenScreen-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "GreenScreen-Info.plist"; sourceTree = ""; };
51 | 03AF044515C84C230061A0D7 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; };
52 | 03AF044715C84C230061A0D7 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; };
53 | 03AF044915C84C230061A0D7 /* GreenScreen-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "GreenScreen-Prefix.pch"; sourceTree = ""; };
54 | 03AF044A15C84C230061A0D7 /* GSAppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GSAppDelegate.h; sourceTree = ""; };
55 | 03AF044B15C84C230061A0D7 /* GSAppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GSAppDelegate.m; sourceTree = ""; };
56 | 03AF044E15C84C230061A0D7 /* en */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = en; path = en.lproj/MainStoryboard_iPhone.storyboard; sourceTree = ""; };
57 | 03AF045115C84C230061A0D7 /* en */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = en; path = en.lproj/MainStoryboard_iPad.storyboard; sourceTree = ""; };
58 | 03AF045315C84C230061A0D7 /* GSViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GSViewController.h; sourceTree = ""; };
59 | 03AF045415C84C230061A0D7 /* GSViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GSViewController.m; sourceTree = ""; };
60 | 03AF045B15C84C760061A0D7 /* GLKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = GLKit.framework; path = System/Library/Frameworks/GLKit.framework; sourceTree = SDKROOT; };
61 | 03AF045C15C84C760061A0D7 /* OpenGLES.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGLES.framework; path = System/Library/Frameworks/OpenGLES.framework; sourceTree = SDKROOT; };
62 | 03AF045F15C84CD10061A0D7 /* GSVideoProcessor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GSVideoProcessor.h; sourceTree = ""; };
63 | 03AF046015C84CD10061A0D7 /* GSVideoProcessor.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GSVideoProcessor.m; sourceTree = ""; };
64 | 03AF046215C84CF70061A0D7 /* AVFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AVFoundation.framework; path = System/Library/Frameworks/AVFoundation.framework; sourceTree = SDKROOT; };
65 | 03AF046315C84CF70061A0D7 /* CoreMotion.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreMotion.framework; path = System/Library/Frameworks/CoreMotion.framework; sourceTree = SDKROOT; };
66 | 03AF046615C84D190061A0D7 /* CoreVideo.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreVideo.framework; path = System/Library/Frameworks/CoreVideo.framework; sourceTree = SDKROOT; };
67 | 03AF046815C84D340061A0D7 /* AssetsLibrary.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AssetsLibrary.framework; path = System/Library/Frameworks/AssetsLibrary.framework; sourceTree = SDKROOT; };
68 | 03AF046A15C84D690061A0D7 /* CoreMedia.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreMedia.framework; path = System/Library/Frameworks/CoreMedia.framework; sourceTree = SDKROOT; };
69 | 03AF046C15C84D8C0061A0D7 /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; };
70 | 03AF046E15C84DA20061A0D7 /* MobileCoreServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MobileCoreServices.framework; path = System/Library/Frameworks/MobileCoreServices.framework; sourceTree = SDKROOT; };
71 | /* End PBXFileReference section */
72 |
73 | /* Begin PBXFrameworksBuildPhase section */
74 | 03AF043415C84C230061A0D7 /* Frameworks */ = {
75 | isa = PBXFrameworksBuildPhase;
76 | buildActionMask = 2147483647;
77 | files = (
78 | 03AF046F15C84DA20061A0D7 /* MobileCoreServices.framework in Frameworks */,
79 | 03AF046D15C84D8C0061A0D7 /* QuartzCore.framework in Frameworks */,
80 | 03AF046B15C84D690061A0D7 /* CoreMedia.framework in Frameworks */,
81 | 03AF046915C84D340061A0D7 /* AssetsLibrary.framework in Frameworks */,
82 | 03AF046715C84D190061A0D7 /* CoreVideo.framework in Frameworks */,
83 | 03AF046415C84CF70061A0D7 /* AVFoundation.framework in Frameworks */,
84 | 03AF046515C84CF70061A0D7 /* CoreMotion.framework in Frameworks */,
85 | 03AF045D15C84C760061A0D7 /* GLKit.framework in Frameworks */,
86 | 03AF045E15C84C760061A0D7 /* OpenGLES.framework in Frameworks */,
87 | 03AF043C15C84C230061A0D7 /* UIKit.framework in Frameworks */,
88 | 03AF043E15C84C230061A0D7 /* Foundation.framework in Frameworks */,
89 | 03AF044015C84C230061A0D7 /* CoreGraphics.framework in Frameworks */,
90 | );
91 | runOnlyForDeploymentPostprocessing = 0;
92 | };
93 | /* End PBXFrameworksBuildPhase section */
94 |
95 | /* Begin PBXGroup section */
96 | 036178A215C84F8300C838E8 /* Shaders */ = {
97 | isa = PBXGroup;
98 | children = (
99 | 036178A315C84F8300C838E8 /* greenScreen.fsh */,
100 | 036178A415C84F8300C838E8 /* greenScreen.vsh */,
101 | );
102 | path = Shaders;
103 | sourceTree = "";
104 | };
105 | 03AF042C15C84C230061A0D7 = {
106 | isa = PBXGroup;
107 | children = (
108 | 0387DE7A18317292002BC568 /* Default-568h@2x.png */,
109 | 03AF044115C84C230061A0D7 /* GreenScreen */,
110 | 03AF043A15C84C230061A0D7 /* Frameworks */,
111 | 03AF043815C84C230061A0D7 /* Products */,
112 | );
113 | sourceTree = "";
114 | };
115 | 03AF043815C84C230061A0D7 /* Products */ = {
116 | isa = PBXGroup;
117 | children = (
118 | 03AF043715C84C230061A0D7 /* GreenScreen.app */,
119 | );
120 | name = Products;
121 | sourceTree = "";
122 | };
123 | 03AF043A15C84C230061A0D7 /* Frameworks */ = {
124 | isa = PBXGroup;
125 | children = (
126 | 03AF046E15C84DA20061A0D7 /* MobileCoreServices.framework */,
127 | 03AF046C15C84D8C0061A0D7 /* QuartzCore.framework */,
128 | 03AF046A15C84D690061A0D7 /* CoreMedia.framework */,
129 | 03AF046815C84D340061A0D7 /* AssetsLibrary.framework */,
130 | 03AF046615C84D190061A0D7 /* CoreVideo.framework */,
131 | 03AF046215C84CF70061A0D7 /* AVFoundation.framework */,
132 | 03AF046315C84CF70061A0D7 /* CoreMotion.framework */,
133 | 03AF045B15C84C760061A0D7 /* GLKit.framework */,
134 | 03AF045C15C84C760061A0D7 /* OpenGLES.framework */,
135 | 03AF043B15C84C230061A0D7 /* UIKit.framework */,
136 | 03AF043D15C84C230061A0D7 /* Foundation.framework */,
137 | 03AF043F15C84C230061A0D7 /* CoreGraphics.framework */,
138 | );
139 | name = Frameworks;
140 | sourceTree = "";
141 | };
142 | 03AF044115C84C230061A0D7 /* GreenScreen */ = {
143 | isa = PBXGroup;
144 | children = (
145 | 036178A915C8511100C838E8 /* UtilityEffect.h */,
146 | 036178AA15C8511100C838E8 /* UtilityEffect.m */,
147 | 036178A015C84F8300C838E8 /* GSGreenScreenEffect.h */,
148 | 036178A115C84F8300C838E8 /* GSGreenScreenEffect.m */,
149 | 036178A215C84F8300C838E8 /* Shaders */,
150 | 03AF045F15C84CD10061A0D7 /* GSVideoProcessor.h */,
151 | 03AF046015C84CD10061A0D7 /* GSVideoProcessor.m */,
152 | 03AF044A15C84C230061A0D7 /* GSAppDelegate.h */,
153 | 03AF044B15C84C230061A0D7 /* GSAppDelegate.m */,
154 | 03AF044D15C84C230061A0D7 /* MainStoryboard_iPhone.storyboard */,
155 | 03AF045015C84C230061A0D7 /* MainStoryboard_iPad.storyboard */,
156 | 03AF045315C84C230061A0D7 /* GSViewController.h */,
157 | 03AF045415C84C230061A0D7 /* GSViewController.m */,
158 | 03AF044215C84C230061A0D7 /* Supporting Files */,
159 | );
160 | path = GreenScreen;
161 | sourceTree = "";
162 | };
163 | 03AF044215C84C230061A0D7 /* Supporting Files */ = {
164 | isa = PBXGroup;
165 | children = (
166 | 036178AC15C8565000C838E8 /* Elephant.jpg */,
167 | 03AF044315C84C230061A0D7 /* GreenScreen-Info.plist */,
168 | 03AF044415C84C230061A0D7 /* InfoPlist.strings */,
169 | 03AF044715C84C230061A0D7 /* main.m */,
170 | 03AF044915C84C230061A0D7 /* GreenScreen-Prefix.pch */,
171 | );
172 | name = "Supporting Files";
173 | sourceTree = "";
174 | };
175 | /* End PBXGroup section */
176 |
177 | /* Begin PBXNativeTarget section */
178 | 03AF043615C84C230061A0D7 /* GreenScreen */ = {
179 | isa = PBXNativeTarget;
180 | buildConfigurationList = 03AF045815C84C230061A0D7 /* Build configuration list for PBXNativeTarget "GreenScreen" */;
181 | buildPhases = (
182 | 03AF043315C84C230061A0D7 /* Sources */,
183 | 03AF043415C84C230061A0D7 /* Frameworks */,
184 | 03AF043515C84C230061A0D7 /* Resources */,
185 | );
186 | buildRules = (
187 | );
188 | dependencies = (
189 | );
190 | name = GreenScreen;
191 | productName = GreenScreen;
192 | productReference = 03AF043715C84C230061A0D7 /* GreenScreen.app */;
193 | productType = "com.apple.product-type.application";
194 | };
195 | /* End PBXNativeTarget section */
196 |
197 | /* Begin PBXProject section */
198 | 03AF042E15C84C230061A0D7 /* Project object */ = {
199 | isa = PBXProject;
200 | attributes = {
201 | CLASSPREFIX = GS;
202 | LastUpgradeCheck = 0800;
203 | ORGANIZATIONNAME = "Erik Buck";
204 | TargetAttributes = {
205 | 03AF043615C84C230061A0D7 = {
206 | DevelopmentTeam = 8Z5LCWW649;
207 | };
208 | };
209 | };
210 | buildConfigurationList = 03AF043115C84C230061A0D7 /* Build configuration list for PBXProject "GreenScreen" */;
211 | compatibilityVersion = "Xcode 3.2";
212 | developmentRegion = English;
213 | hasScannedForEncodings = 0;
214 | knownRegions = (
215 | en,
216 | );
217 | mainGroup = 03AF042C15C84C230061A0D7;
218 | productRefGroup = 03AF043815C84C230061A0D7 /* Products */;
219 | projectDirPath = "";
220 | projectRoot = "";
221 | targets = (
222 | 03AF043615C84C230061A0D7 /* GreenScreen */,
223 | );
224 | };
225 | /* End PBXProject section */
226 |
227 | /* Begin PBXResourcesBuildPhase section */
228 | 03AF043515C84C230061A0D7 /* Resources */ = {
229 | isa = PBXResourcesBuildPhase;
230 | buildActionMask = 2147483647;
231 | files = (
232 | 036178A615C84F8300C838E8 /* greenScreen.fsh in Resources */,
233 | 036178A715C84F8300C838E8 /* greenScreen.vsh in Resources */,
234 | 03AF044615C84C230061A0D7 /* InfoPlist.strings in Resources */,
235 | 03AF044F15C84C230061A0D7 /* MainStoryboard_iPhone.storyboard in Resources */,
236 | 03AF045215C84C230061A0D7 /* MainStoryboard_iPad.storyboard in Resources */,
237 | 0387DE7B18317292002BC568 /* Default-568h@2x.png in Resources */,
238 | 036178AD15C8565000C838E8 /* Elephant.jpg in Resources */,
239 | );
240 | runOnlyForDeploymentPostprocessing = 0;
241 | };
242 | /* End PBXResourcesBuildPhase section */
243 |
244 | /* Begin PBXSourcesBuildPhase section */
245 | 03AF043315C84C230061A0D7 /* Sources */ = {
246 | isa = PBXSourcesBuildPhase;
247 | buildActionMask = 2147483647;
248 | files = (
249 | 03AF044815C84C230061A0D7 /* main.m in Sources */,
250 | 03AF044C15C84C230061A0D7 /* GSAppDelegate.m in Sources */,
251 | 03AF045515C84C230061A0D7 /* GSViewController.m in Sources */,
252 | 03AF046115C84CD10061A0D7 /* GSVideoProcessor.m in Sources */,
253 | 036178A515C84F8300C838E8 /* GSGreenScreenEffect.m in Sources */,
254 | 036178AB15C8511100C838E8 /* UtilityEffect.m in Sources */,
255 | );
256 | runOnlyForDeploymentPostprocessing = 0;
257 | };
258 | /* End PBXSourcesBuildPhase section */
259 |
260 | /* Begin PBXVariantGroup section */
261 | 03AF044415C84C230061A0D7 /* InfoPlist.strings */ = {
262 | isa = PBXVariantGroup;
263 | children = (
264 | 03AF044515C84C230061A0D7 /* en */,
265 | );
266 | name = InfoPlist.strings;
267 | sourceTree = "";
268 | };
269 | 03AF044D15C84C230061A0D7 /* MainStoryboard_iPhone.storyboard */ = {
270 | isa = PBXVariantGroup;
271 | children = (
272 | 03AF044E15C84C230061A0D7 /* en */,
273 | );
274 | name = MainStoryboard_iPhone.storyboard;
275 | sourceTree = "";
276 | };
277 | 03AF045015C84C230061A0D7 /* MainStoryboard_iPad.storyboard */ = {
278 | isa = PBXVariantGroup;
279 | children = (
280 | 03AF045115C84C230061A0D7 /* en */,
281 | );
282 | name = MainStoryboard_iPad.storyboard;
283 | sourceTree = "";
284 | };
285 | /* End PBXVariantGroup section */
286 |
287 | /* Begin XCBuildConfiguration section */
288 | 03AF045615C84C230061A0D7 /* Debug */ = {
289 | isa = XCBuildConfiguration;
290 | buildSettings = {
291 | ALWAYS_SEARCH_USER_PATHS = NO;
292 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
293 | CLANG_ENABLE_OBJC_ARC = YES;
294 | CLANG_WARN_BOOL_CONVERSION = YES;
295 | CLANG_WARN_CONSTANT_CONVERSION = YES;
296 | CLANG_WARN_EMPTY_BODY = YES;
297 | CLANG_WARN_ENUM_CONVERSION = YES;
298 | CLANG_WARN_INFINITE_RECURSION = YES;
299 | CLANG_WARN_INT_CONVERSION = YES;
300 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
301 | CLANG_WARN_UNREACHABLE_CODE = YES;
302 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
303 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
304 | COPY_PHASE_STRIP = NO;
305 | ENABLE_STRICT_OBJC_MSGSEND = YES;
306 | ENABLE_TESTABILITY = YES;
307 | GCC_C_LANGUAGE_STANDARD = gnu99;
308 | GCC_DYNAMIC_NO_PIC = NO;
309 | GCC_NO_COMMON_BLOCKS = YES;
310 | GCC_OPTIMIZATION_LEVEL = 0;
311 | GCC_PREPROCESSOR_DEFINITIONS = (
312 | "DEBUG=1",
313 | "$(inherited)",
314 | );
315 | GCC_SYMBOLS_PRIVATE_EXTERN = NO;
316 | GCC_VERSION = com.apple.compilers.llvm.clang.1_0;
317 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
318 | GCC_WARN_ABOUT_RETURN_TYPE = YES;
319 | GCC_WARN_UNDECLARED_SELECTOR = YES;
320 | GCC_WARN_UNINITIALIZED_AUTOS = YES;
321 | GCC_WARN_UNUSED_FUNCTION = YES;
322 | GCC_WARN_UNUSED_VARIABLE = YES;
323 | IPHONEOS_DEPLOYMENT_TARGET = 9.0;
324 | ONLY_ACTIVE_ARCH = YES;
325 | SDKROOT = iphoneos;
326 | TARGETED_DEVICE_FAMILY = "1,2";
327 | };
328 | name = Debug;
329 | };
330 | 03AF045715C84C230061A0D7 /* Release */ = {
331 | isa = XCBuildConfiguration;
332 | buildSettings = {
333 | ALWAYS_SEARCH_USER_PATHS = NO;
334 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
335 | CLANG_ENABLE_OBJC_ARC = YES;
336 | CLANG_WARN_BOOL_CONVERSION = YES;
337 | CLANG_WARN_CONSTANT_CONVERSION = YES;
338 | CLANG_WARN_EMPTY_BODY = YES;
339 | CLANG_WARN_ENUM_CONVERSION = YES;
340 | CLANG_WARN_INFINITE_RECURSION = YES;
341 | CLANG_WARN_INT_CONVERSION = YES;
342 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
343 | CLANG_WARN_UNREACHABLE_CODE = YES;
344 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
345 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
346 | COPY_PHASE_STRIP = YES;
347 | ENABLE_STRICT_OBJC_MSGSEND = YES;
348 | GCC_C_LANGUAGE_STANDARD = gnu99;
349 | GCC_NO_COMMON_BLOCKS = YES;
350 | GCC_VERSION = com.apple.compilers.llvm.clang.1_0;
351 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
352 | GCC_WARN_ABOUT_RETURN_TYPE = YES;
353 | GCC_WARN_UNDECLARED_SELECTOR = YES;
354 | GCC_WARN_UNINITIALIZED_AUTOS = YES;
355 | GCC_WARN_UNUSED_FUNCTION = YES;
356 | GCC_WARN_UNUSED_VARIABLE = YES;
357 | IPHONEOS_DEPLOYMENT_TARGET = 9.0;
358 | OTHER_CFLAGS = "-DNS_BLOCK_ASSERTIONS=1";
359 | SDKROOT = iphoneos;
360 | TARGETED_DEVICE_FAMILY = "1,2";
361 | VALIDATE_PRODUCT = YES;
362 | };
363 | name = Release;
364 | };
365 | 03AF045915C84C230061A0D7 /* Debug */ = {
366 | isa = XCBuildConfiguration;
367 | buildSettings = {
368 | DEVELOPMENT_TEAM = 8Z5LCWW649;
369 | GCC_PRECOMPILE_PREFIX_HEADER = YES;
370 | GCC_PREFIX_HEADER = "GreenScreen/GreenScreen-Prefix.pch";
371 | INFOPLIST_FILE = "GreenScreen/GreenScreen-Info.plist";
372 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
373 | PRODUCT_BUNDLE_IDENTIFIER = "GS.${PRODUCT_NAME:rfc1034identifier}";
374 | PRODUCT_NAME = "$(TARGET_NAME)";
375 | WRAPPER_EXTENSION = app;
376 | };
377 | name = Debug;
378 | };
379 | 03AF045A15C84C230061A0D7 /* Release */ = {
380 | isa = XCBuildConfiguration;
381 | buildSettings = {
382 | DEVELOPMENT_TEAM = 8Z5LCWW649;
383 | GCC_PRECOMPILE_PREFIX_HEADER = YES;
384 | GCC_PREFIX_HEADER = "GreenScreen/GreenScreen-Prefix.pch";
385 | INFOPLIST_FILE = "GreenScreen/GreenScreen-Info.plist";
386 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
387 | PRODUCT_BUNDLE_IDENTIFIER = "GS.${PRODUCT_NAME:rfc1034identifier}";
388 | PRODUCT_NAME = "$(TARGET_NAME)";
389 | WRAPPER_EXTENSION = app;
390 | };
391 | name = Release;
392 | };
393 | /* End XCBuildConfiguration section */
394 |
395 | /* Begin XCConfigurationList section */
396 | 03AF043115C84C230061A0D7 /* Build configuration list for PBXProject "GreenScreen" */ = {
397 | isa = XCConfigurationList;
398 | buildConfigurations = (
399 | 03AF045615C84C230061A0D7 /* Debug */,
400 | 03AF045715C84C230061A0D7 /* Release */,
401 | );
402 | defaultConfigurationIsVisible = 0;
403 | defaultConfigurationName = Release;
404 | };
405 | 03AF045815C84C230061A0D7 /* Build configuration list for PBXNativeTarget "GreenScreen" */ = {
406 | isa = XCConfigurationList;
407 | buildConfigurations = (
408 | 03AF045915C84C230061A0D7 /* Debug */,
409 | 03AF045A15C84C230061A0D7 /* Release */,
410 | );
411 | defaultConfigurationIsVisible = 0;
412 | defaultConfigurationName = Release;
413 | };
414 | /* End XCConfigurationList section */
415 | };
416 | rootObject = 03AF042E15C84C230061A0D7 /* Project object */;
417 | }
418 |
--------------------------------------------------------------------------------