├── 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 | ![Image of Figure1](http://ptgmedia.pearsoncmg.com/images/art_buck_iosgreenscreen/elementLinks/buck1_fig01.jpg) 8 | 9 | Figure 1 Sample green-screen effect. 10 | 11 | 12 | ![Image of Figure2](http://ptgmedia.pearsoncmg.com/images/art_buck_iosgreenscreen/elementLinks/buck1_fig02.jpg) 13 | 14 | Figure 2 Images are composed of pixels with red, green, and blue elements. 15 | 16 | 17 | ![Image of Figure3](http://ptgmedia.pearsoncmg.com/images/art_buck_iosgreenscreen/elementLinks/buck1_fig03.jpg) 18 | 19 | Figure 3 There's an elephant outside the window. 20 | 21 | 22 | ![Image of Figure4](http://ptgmedia.pearsoncmg.com/images/art_buck_iosgreenscreen/elementLinks/buck1_fig04.jpg) 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 | --------------------------------------------------------------------------------