diff --git a/examples/Mac/SimpleVideoFilter/SimpleVideoFilter.xcodeproj/project.pbxproj b/examples/Mac/SimpleVideoFilter/SimpleVideoFilter.xcodeproj/project.pbxproj index 3fdf2cf9b..520faa70b 100644 --- a/examples/Mac/SimpleVideoFilter/SimpleVideoFilter.xcodeproj/project.pbxproj +++ b/examples/Mac/SimpleVideoFilter/SimpleVideoFilter.xcodeproj/project.pbxproj @@ -7,6 +7,9 @@ objects = { /* Begin PBXBuildFile section */ + 4ADF8E481B02DB5000214002 /* PCDistortFilter.m in Sources */ = {isa = PBXBuildFile; fileRef = 4ADF8E471B02DB5000214002 /* PCDistortFilter.m */; }; + 4ADF8E4C1B02E7AE00214002 /* PCPolygonEditor.m in Sources */ = {isa = PBXBuildFile; fileRef = 4ADF8E4B1B02E7AE00214002 /* PCPolygonEditor.m */; }; + 4ADF8E4F1B02F09300214002 /* PCHandleView.m in Sources */ = {isa = PBXBuildFile; fileRef = 4ADF8E4E1B02F09300214002 /* PCHandleView.m */; }; 79C26E221A5EDD1C0054857C /* SLSSimpleVideoFilterWindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = 79C26E211A5EDD1C0054857C /* SLSSimpleVideoFilterWindowController.m */; }; 79C26E2E1A5F02B70054857C /* SLSSimpleVideoFilterWindowController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 79C26E2D1A5F02B70054857C /* SLSSimpleVideoFilterWindowController.xib */; }; 79E8A5FB1A5ED6A700E6A226 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 79E8A5FA1A5ED6A700E6A226 /* AppDelegate.m */; }; @@ -55,6 +58,12 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + 4ADF8E461B02DB5000214002 /* PCDistortFilter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PCDistortFilter.h; sourceTree = ""; }; + 4ADF8E471B02DB5000214002 /* PCDistortFilter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PCDistortFilter.m; sourceTree = ""; }; + 4ADF8E4A1B02E7AE00214002 /* PCPolygonEditor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PCPolygonEditor.h; sourceTree = ""; }; + 4ADF8E4B1B02E7AE00214002 /* PCPolygonEditor.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PCPolygonEditor.m; sourceTree = ""; }; + 4ADF8E4D1B02F09300214002 /* PCHandleView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PCHandleView.h; sourceTree = ""; }; + 4ADF8E4E1B02F09300214002 /* PCHandleView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PCHandleView.m; sourceTree = ""; }; 79C26E201A5EDD1C0054857C /* SLSSimpleVideoFilterWindowController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SLSSimpleVideoFilterWindowController.h; sourceTree = ""; }; 79C26E211A5EDD1C0054857C /* SLSSimpleVideoFilterWindowController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SLSSimpleVideoFilterWindowController.m; sourceTree = ""; }; 79C26E2D1A5F02B70054857C /* SLSSimpleVideoFilterWindowController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = SLSSimpleVideoFilterWindowController.xib; sourceTree = ""; }; @@ -119,6 +128,12 @@ 79E8A5FE1A5ED6A700E6A226 /* Images.xcassets */, 79E8A6001A5ED6A700E6A226 /* MainMenu.xib */, 79E8A5F71A5ED6A700E6A226 /* Supporting Files */, + 4ADF8E461B02DB5000214002 /* PCDistortFilter.h */, + 4ADF8E471B02DB5000214002 /* PCDistortFilter.m */, + 4ADF8E4A1B02E7AE00214002 /* PCPolygonEditor.h */, + 4ADF8E4B1B02E7AE00214002 /* PCPolygonEditor.m */, + 4ADF8E4D1B02F09300214002 /* PCHandleView.h */, + 4ADF8E4E1B02F09300214002 /* PCHandleView.m */, ); path = SimpleVideoFilter; sourceTree = ""; @@ -286,7 +301,10 @@ files = ( 79E8A5FD1A5ED6A700E6A226 /* main.m in Sources */, 79E8A5FB1A5ED6A700E6A226 /* AppDelegate.m in Sources */, + 4ADF8E481B02DB5000214002 /* PCDistortFilter.m in Sources */, 79C26E221A5EDD1C0054857C /* SLSSimpleVideoFilterWindowController.m in Sources */, + 4ADF8E4C1B02E7AE00214002 /* PCPolygonEditor.m in Sources */, + 4ADF8E4F1B02F09300214002 /* PCHandleView.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/examples/Mac/SimpleVideoFilter/SimpleVideoFilter/Base.lproj/MainMenu.xib b/examples/Mac/SimpleVideoFilter/SimpleVideoFilter/Base.lproj/MainMenu.xib index 63481a236..a8ccdba35 100644 --- a/examples/Mac/SimpleVideoFilter/SimpleVideoFilter/Base.lproj/MainMenu.xib +++ b/examples/Mac/SimpleVideoFilter/SimpleVideoFilter/Base.lproj/MainMenu.xib @@ -1,7 +1,7 @@ - + - + @@ -662,15 +662,5 @@ - - - - - - - - - - diff --git a/examples/Mac/SimpleVideoFilter/SimpleVideoFilter/PCDistortFilter.h b/examples/Mac/SimpleVideoFilter/SimpleVideoFilter/PCDistortFilter.h new file mode 100644 index 000000000..d31c05106 --- /dev/null +++ b/examples/Mac/SimpleVideoFilter/SimpleVideoFilter/PCDistortFilter.h @@ -0,0 +1,17 @@ +#import + +typedef struct PCDistortPolygon { + CGPoint topLeft; + CGPoint bottomLeft; + CGPoint topRight; + CGPoint bottomRight; +} PCDistortPolygon; + +@interface PCDistortFilter : GPUImageFilter { + GLint topLeft; + GLint bottomLeft; + GLint topRight; + GLint bottomRight; +} +- (void)setSourcePolygon:(PCDistortPolygon)polygon; +@end diff --git a/examples/Mac/SimpleVideoFilter/SimpleVideoFilter/PCDistortFilter.m b/examples/Mac/SimpleVideoFilter/SimpleVideoFilter/PCDistortFilter.m new file mode 100644 index 000000000..8edc8219f --- /dev/null +++ b/examples/Mac/SimpleVideoFilter/SimpleVideoFilter/PCDistortFilter.m @@ -0,0 +1,51 @@ +#import "PCDistortFilter.h" + +NSString *const kPCDistortFilterFragmentShaderString = SHADER_STRING +( + varying vec2 textureCoordinate; + + uniform sampler2D inputImageTexture; + + uniform vec2 topLeft; + uniform vec2 bottomLeft; + uniform vec2 topRight; + uniform vec2 bottomRight; + + void main() + { + vec2 top = mix(topLeft, topRight, textureCoordinate.x); + vec2 bottom = mix(bottomLeft, bottomRight, textureCoordinate.x); + vec2 textureCoordinateToUse = mix(top, bottom, textureCoordinate.y); + gl_FragColor = texture2D(inputImageTexture, textureCoordinateToUse); + } + ); + + +@implementation PCDistortFilter +- (id)init; +{ + if (!(self = [super initWithFragmentShaderFromString:kPCDistortFilterFragmentShaderString])) + { + return nil; + } + + topLeft = [filterProgram uniformIndex:@"topLeft"]; + bottomLeft = [filterProgram uniformIndex:@"bottomLeft"]; + topRight = [filterProgram uniformIndex:@"topRight"]; + bottomRight = [filterProgram uniformIndex:@"bottomRight"]; + + return self; +} + +#pragma mark - +#pragma mark Accessors + +- (void)setSourcePolygon:(PCDistortPolygon)polygon { + [self setPoint:polygon.topLeft forUniform:topLeft program:filterProgram]; + [self setPoint:polygon.bottomLeft forUniform:bottomLeft program:filterProgram]; + [self setPoint:polygon.topRight forUniform:topRight program:filterProgram]; + [self setPoint:polygon.bottomRight forUniform:bottomRight program:filterProgram]; +} + + +@end diff --git a/examples/Mac/SimpleVideoFilter/SimpleVideoFilter/PCHandleView.h b/examples/Mac/SimpleVideoFilter/SimpleVideoFilter/PCHandleView.h new file mode 100644 index 000000000..45a2d3d29 --- /dev/null +++ b/examples/Mac/SimpleVideoFilter/SimpleVideoFilter/PCHandleView.h @@ -0,0 +1,13 @@ +// +// PCHandleView.h +// SimpleVideoFilter +// +// Created by Phil Calvin on 5/12/15. +// Copyright (c) 2015 Red Queen Coder, LLC. All rights reserved. +// + +#import + +@interface PCHandleView : NSView + +@end diff --git a/examples/Mac/SimpleVideoFilter/SimpleVideoFilter/PCHandleView.m b/examples/Mac/SimpleVideoFilter/SimpleVideoFilter/PCHandleView.m new file mode 100644 index 000000000..df311fe4f --- /dev/null +++ b/examples/Mac/SimpleVideoFilter/SimpleVideoFilter/PCHandleView.m @@ -0,0 +1,37 @@ +// +// PCHandleView.m +// SimpleVideoFilter +// +// Created by Phil Calvin on 5/12/15. +// Copyright (c) 2015 Red Queen Coder, LLC. All rights reserved. +// + +#import "PCHandleView.h" + +@implementation PCHandleView + +- (void)drawRect:(NSRect)dirtyRect { + // Get the graphics context that we are currently executing under + NSGraphicsContext* gc = [NSGraphicsContext currentContext]; + + // Save the current graphics context settings + [gc saveGraphicsState]; + + // Set the color in the current graphics context for future draw operations + [[NSColor blackColor] setStroke]; + [[NSColor redColor] setFill]; + + // Create our circle path + NSRect rect = NSMakeRect(10, 10, 10, 10); + NSBezierPath* circlePath = [NSBezierPath bezierPath]; + [circlePath appendBezierPathWithOvalInRect: rect]; + + // Outline and fill the path + [circlePath stroke]; + [circlePath fill]; + + // Restore the context to what it was before we messed with it + [gc restoreGraphicsState]; +} + +@end diff --git a/examples/Mac/SimpleVideoFilter/SimpleVideoFilter/PCPolygonEditor.h b/examples/Mac/SimpleVideoFilter/SimpleVideoFilter/PCPolygonEditor.h new file mode 100644 index 000000000..618ebf3ff --- /dev/null +++ b/examples/Mac/SimpleVideoFilter/SimpleVideoFilter/PCPolygonEditor.h @@ -0,0 +1,13 @@ +// +// PCPolygonEditor.h +// SimpleVideoFilter +// +// Created by Phil Calvin on 5/12/15. +// Copyright (c) 2015 Red Queen Coder, LLC. All rights reserved. +// + +#import + +@interface PCPolygonEditor : NSView + +@end diff --git a/examples/Mac/SimpleVideoFilter/SimpleVideoFilter/PCPolygonEditor.m b/examples/Mac/SimpleVideoFilter/SimpleVideoFilter/PCPolygonEditor.m new file mode 100644 index 000000000..64acad057 --- /dev/null +++ b/examples/Mac/SimpleVideoFilter/SimpleVideoFilter/PCPolygonEditor.m @@ -0,0 +1,20 @@ +#import "PCPolygonEditor.h" +#import "PCHandleView.h" + +@interface PCPolygonEditor () +@property NSView *picker; +@end + +@implementation PCPolygonEditor + +- (void)awakeFromNib { + [super awakeFromNib]; + PCHandleView *boxView = [[PCHandleView alloc] initWithFrame:NSMakeRect(20, 20, 20, 20)]; + // Uncomment these lines to show overlay, but break distorted view +// [[self superview] setWantsLayer:YES]; +// [self setWantsLayer:YES]; + [self addSubview:boxView]; + self.picker = boxView; +} + +@end diff --git a/examples/Mac/SimpleVideoFilter/SimpleVideoFilter/SLSSimpleVideoFilterWindowController.h b/examples/Mac/SimpleVideoFilter/SimpleVideoFilter/SLSSimpleVideoFilterWindowController.h index 98ffdd077..0c222862e 100644 --- a/examples/Mac/SimpleVideoFilter/SimpleVideoFilter/SLSSimpleVideoFilterWindowController.h +++ b/examples/Mac/SimpleVideoFilter/SimpleVideoFilter/SLSSimpleVideoFilterWindowController.h @@ -6,8 +6,10 @@ GPUImageAVCamera *videoCamera; GPUImageOutput *filter; GPUImageMovieWriter *movieWriter; + } @property (weak) IBOutlet GPUImageView *videoView; +@property (weak) IBOutlet GPUImageView *distortedView; @end diff --git a/examples/Mac/SimpleVideoFilter/SimpleVideoFilter/SLSSimpleVideoFilterWindowController.m b/examples/Mac/SimpleVideoFilter/SimpleVideoFilter/SLSSimpleVideoFilterWindowController.m index 502f7361c..d8ac79047 100644 --- a/examples/Mac/SimpleVideoFilter/SimpleVideoFilter/SLSSimpleVideoFilterWindowController.m +++ b/examples/Mac/SimpleVideoFilter/SimpleVideoFilter/SLSSimpleVideoFilterWindowController.m @@ -1,64 +1,67 @@ #import "SLSSimpleVideoFilterWindowController.h" +#import "PCDistortFilter.h" @interface SLSSimpleVideoFilterWindowController () - +@property GPUImageFilter *noopFilter; +@property PCDistortFilter *distortFilter; @end @implementation SLSSimpleVideoFilterWindowController - (void)windowDidLoad { - [super windowDidLoad]; - - // Implement this method to handle any initialization after your window controller's window has been loaded from its nib file. - - // Instantiate video camera - videoCamera = [[GPUImageAVCamera alloc] initWithSessionPreset:AVCaptureSessionPreset640x480 cameraDevice:nil]; - videoCamera.runBenchmark = YES; - - // Create filter and add it to target - filter = [[GPUImageSepiaFilter alloc] init]; - [videoCamera addTarget:filter]; - - // Save video to desktop - NSError *error = nil; - - NSURL *pathToDesktop = [[NSFileManager defaultManager] URLForDirectory:NSDesktopDirectory inDomain:NSUserDomainMask appropriateForURL:nil create:YES error:&error]; - NSURL *pathToMovieFile = [pathToDesktop URLByAppendingPathComponent:@"movie.mp4"]; - NSString *filePathString = [pathToMovieFile absoluteString]; - NSString *filePathSubstring = [filePathString substringFromIndex:7]; - unlink([filePathSubstring UTF8String]); - - // Instantiate movie writer and add targets - movieWriter = [[GPUImageMovieWriter alloc] initWithMovieURL:pathToMovieFile size:CGSizeMake(640.0, 480.0)]; - movieWriter.encodingLiveVideo = YES; - - self.videoView.fillMode = kGPUImageFillModePreserveAspectRatio; - [filter addTarget:movieWriter]; - [filter addTarget:self.videoView]; - - // Start capturing - [videoCamera startCameraCapture]; - - double delayToStartRecording = 0.5; - dispatch_time_t startTime = dispatch_time(DISPATCH_TIME_NOW, delayToStartRecording * NSEC_PER_SEC); - dispatch_after(startTime, dispatch_get_main_queue(), ^(void){ - NSLog(@"Start recording"); - - videoCamera.audioEncodingTarget = movieWriter; - [movieWriter startRecording]; - - double delayInSeconds = 10.0; - dispatch_time_t stopTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC); - dispatch_after(stopTime, dispatch_get_main_queue(), ^(void){ - - [filter removeTarget:movieWriter]; - videoCamera.audioEncodingTarget = nil; - [movieWriter finishRecording]; - NSLog(@"Movie completed"); + [super windowDidLoad]; + // Implement this method to handle any initialization after your window controller's window has been loaded from its nib file. + + // Instantiate video camera + videoCamera = [[GPUImageAVCamera alloc] initWithSessionPreset:AVCaptureSessionPreset640x480 cameraDevice:nil]; + videoCamera.runBenchmark = YES; + + filter = [PCDistortFilter new]; + PCDistortPolygon polygon; + polygon.topLeft = CGPointMake(0.3, 0.1); + polygon.topRight = CGPointMake(0.4, 0.1); + polygon.bottomLeft = CGPointMake(0.1, 0.8); + polygon.bottomRight = CGPointMake(0.6, 0.8); + [(PCDistortFilter *)filter setSourcePolygon:polygon]; + [videoCamera addTarget:filter]; + [videoCamera addTarget:self.videoView]; + + self.distortedView.fillMode = kGPUImageFillModePreserveAspectRatio; + self.videoView.fillMode = kGPUImageFillModePreserveAspectRatio; + + [filter addTarget:self.distortedView]; + + // Start capturing + [videoCamera startCameraCapture]; + + // Stupid workaround to capture one image + // [videoCamera addTarget:_noopFilter]; + // double delayToStartRecording = 2.5; + // dispatch_time_t startTime = dispatch_time(DISPATCH_TIME_NOW, delayToStartRecording * NSEC_PER_SEC); + // dispatch_after(startTime, dispatch_get_main_queue(), ^(void){ + // [_noopFilter useNextFrameForImageCapture]; + // + // dispatch_time_t startTime2 = dispatch_time(DISPATCH_TIME_NOW, 0.1 * NSEC_PER_SEC); + // dispatch_after(startTime2, dispatch_get_main_queue(), ^(void){ + // NSImage *image = [_noopFilter imageFromCurrentFramebuffer]; + // self.videoView.image = image; + // }); - }); - }); + // videoCamera.audioEncodingTarget = movieWriter; + // [movieWriter startRecording]; + // + // double delayInSeconds = 10.0; + // dispatch_time_t stopTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC); + // dispatch_after(stopTime, dispatch_get_main_queue(), ^(void){ + // + // [filter removeTarget:movieWriter]; + // videoCamera.audioEncodingTarget = nil; + // [movieWriter finishRecording]; + // NSLog(@"Movie completed"); + // + // }); + //}); } diff --git a/examples/Mac/SimpleVideoFilter/SimpleVideoFilter/SLSSimpleVideoFilterWindowController.xib b/examples/Mac/SimpleVideoFilter/SimpleVideoFilter/SLSSimpleVideoFilterWindowController.xib index eb91fd97b..91eaf09a6 100644 --- a/examples/Mac/SimpleVideoFilter/SimpleVideoFilter/SLSSimpleVideoFilterWindowController.xib +++ b/examples/Mac/SimpleVideoFilter/SimpleVideoFilter/SLSSimpleVideoFilterWindowController.xib @@ -1,12 +1,15 @@ - + - + + + - + + @@ -15,20 +18,58 @@ - - + + - + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +