diff --git a/xcode/CVCocoaLayer.h b/xcode/CVCocoaLayer.h index 08ca9f46..71cab048 100644 --- a/xcode/CVCocoaLayer.h +++ b/xcode/CVCocoaLayer.h @@ -47,7 +47,7 @@ public: char *fjName(); Context *context() { return freej; }; - virtual CVTexture *glTexture(); + virtual CVPixelBufferRef currentFrame(); NSDictionary *imageParams(); int width(); int height(); diff --git a/xcode/CVCocoaLayer.mm b/xcode/CVCocoaLayer.mm index d29ff050..957626f6 100644 --- a/xcode/CVCocoaLayer.mm +++ b/xcode/CVCocoaLayer.mm @@ -37,8 +37,8 @@ CVCocoaLayer::CVCocoaLayer(Layer *lay, CVLayerController *vin) CVCocoaLayer::~CVCocoaLayer() { deactivate(); - if (input) - [input setLayer:nil]; + //if (input) + //[input setLayer:nil]; } @@ -67,14 +67,12 @@ CVCocoaLayer::deactivate() } // accessor to get a texture from the CVLayerController class -CVTexture * -CVCocoaLayer::glTexture() +CVPixelBufferRef +CVCocoaLayer::currentFrame() { - CVTexture *texture = NULL; if (input) - texture = [input getTexture]; - - return texture; + return [input currentFrame]; + return NULL; } bool CVCocoaLayer::isActive() diff --git a/xcode/CVF0rLayerController.mm b/xcode/CVF0rLayerController.mm index e6ed73bd..a236664c 100644 --- a/xcode/CVF0rLayerController.mm +++ b/xcode/CVF0rLayerController.mm @@ -25,24 +25,18 @@ { CVCocoaLayer *toDelete; if (layer) { - [self deactivate]; - [lock lock]; - //toDelete->stop(); + [self stop]; if (currentFrame) { CVPixelBufferRelease(currentFrame); currentFrame = NULL; } - toDelete = (CVCocoaLayer *)layer; - layer = NULL; - [lock unlock]; - delete toDelete; } } - (void)setLayer:(CVCocoaLayer *)lay { if (layer) // ensure to remove/stop old genf0rlayer if we are setting a new one - [self reset]; + [self stop]; [super setLayer:lay]; } diff --git a/xcode/CVFFmpegLayer.h b/xcode/CVFFmpegLayer.h index 18b8bfba..c8925b33 100644 --- a/xcode/CVFFmpegLayer.h +++ b/xcode/CVFFmpegLayer.h @@ -35,8 +35,6 @@ protected: void *feed(); public: - BOOL repeat; - CVFFmpegLayer(CVLayerController *controller); ~CVFFmpegLayer(); bool open(const char *movie); diff --git a/xcode/CVFFmpegLayer.mm b/xcode/CVFFmpegLayer.mm index db6bc64d..18e7bcbd 100644 --- a/xcode/CVFFmpegLayer.mm +++ b/xcode/CVFFmpegLayer.mm @@ -20,7 +20,6 @@ CVFFmpegLayer::CVFFmpegLayer(CVLayerController *controller) : CVLayer(controller { ff = NULL; pixelBuffer = NULL; - repeat = NO; } CVFFmpegLayer::~CVFFmpegLayer() @@ -40,54 +39,60 @@ void *CVFFmpegLayer::feed() if (!ff) { if (strlen(filename)) { // XXX - (argh!, find a better way) + if (open_movie(&ff, filename) == 0) { init_moviebuffer(ff, geo.w, geo.h, PIX_FMT_ARGB); decode_frame(ff); } else { close_and_free_ff(&ff); - if (!repeat) + if (![(CVFFmpegLayerController *)input wantsRepeat]) { memset(filename, 0, sizeof(filename)); // XXX + [input stop]; + return NULL; + } } - } - } else { - uint8_t *ffbuffer = get_bufptr(ff); - if (!ffbuffer) - return NULL; - CVReturn err = CVPixelBufferCreateWithBytes ( - NULL, - geo.w, - geo.h, - k32ARGBPixelFormat, - ffbuffer, - geo.w*4, - NULL, - NULL, - NULL, - &pixelBuffer - ); - if (err == kCVReturnSuccess) { - // first decode the frame - if (!decode_frame(ff)) { - close_and_free_ff(&ff); - //buffer = NULL; - // XXX - find a cleaner way instead of blindly resetting the filename - // TODO - allow looping on a stream by reopening it - if (!repeat) { - memset(filename, 0, sizeof(filename)); - if (input) { - [(CVFFmpegLayerController *)input deactivate]; - [(CVFFmpegLayerController *)input clearPreview]; - } - } - } - // and than provide it to our controller - [input feedFrame:pixelBuffer]; - CVPixelBufferRelease(pixelBuffer); - } else { - // TODO - Error messages - } - } + [input stop]; + return NULL; + } + } + uint8_t *ffbuffer = get_bufptr(ff); + if (!ffbuffer) + return NULL; + CVReturn err = CVPixelBufferCreateWithBytes ( + NULL, + geo.w, + geo.h, + k32ARGBPixelFormat, + ffbuffer, + geo.w*4, + NULL, + NULL, + NULL, + &pixelBuffer + ); + if (err == kCVReturnSuccess) { + // first decode the frame + if (!decode_frame(ff)) { + close_and_free_ff(&ff); + //buffer = NULL; + // XXX - find a cleaner way instead of blindly resetting the filename + // TODO - allow looping on a stream by reopening it + if (![input wantsRepeat]) { + memset(filename, 0, sizeof(filename)); + if (input) { + [(CVFFmpegLayerController *)input deactivate]; + [(CVFFmpegLayerController *)input clearPreview]; + } + } + } + // and than provide it to our controller + [input feedFrame:pixelBuffer]; + CVPixelBufferRelease(pixelBuffer); + + } else { + // TODO - Error messages + } return CVLayer::feed(); } @@ -100,12 +105,16 @@ bool CVFFmpegLayer::isDecoding() int CVFFmpegLayer::scaledWidth() { - return get_scaled_width(ff); + if (ff) + return get_scaled_width(ff); + return 0; } int CVFFmpegLayer::scaledHeight() { - return get_scaled_height(ff); + if (ff) + return get_scaled_height(ff); + return 0; } bool CVFFmpegLayer::hasFF() diff --git a/xcode/CVFFmpegLayerController.h b/xcode/CVFFmpegLayerController.h index fd092f3d..cab4f189 100644 --- a/xcode/CVFFmpegLayerController.h +++ b/xcode/CVFFmpegLayerController.h @@ -41,7 +41,6 @@ struct ffdec; } - (void)setStream:(NSString*)url; -- (void)setRepeat:(BOOL)repeat; - (void)reOpen; - (void)clearPreview; @end diff --git a/xcode/CVFFmpegLayerController.mm b/xcode/CVFFmpegLayerController.mm index 8815f1a8..a10705d4 100644 --- a/xcode/CVFFmpegLayerController.mm +++ b/xcode/CVFFmpegLayerController.mm @@ -52,6 +52,7 @@ previewImage = nil; timeout=1; currentFrame = nil; + wantsRepeat = NO; bufDict = [[NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:YES], kCVPixelBufferCGImageCompatibilityKey, [NSNumber numberWithBool:YES], kCVPixelBufferCGBitmapContextCompatibilityKey, [NSNumber numberWithBool:YES], kCVPixelBufferOpenGLCompatibilityKey, nil] retain]; return [super init]; @@ -109,18 +110,8 @@ layer = ffLayer; } ((CVFFmpegLayer *)layer)->open(movie); + layer->activate(); [lock unlock]; -/* - if (!currentFrame) { - CVPixelBufferCreate( - kCFAllocatorDefault, - ctx->screen->geo.w, - ctx->screen->geo.h, - k32ARGBPixelFormat, - (CFDictionaryRef)bufDict, - ¤tFrame); - } - */ } - (void)feedFrame:(CVPixelBufferRef)frame @@ -134,26 +125,11 @@ CVPixelBufferLockBaseAddress(frame, 0); uint8_t* buf= (uint8_t*) CVPixelBufferGetBaseAddress(frame); - /* - printf("%dx%d -> %dx%d\n", get_scaled_width(ff), get_scaled_height(ff), - ctx->screen->geo.w, ctx->screen->geo.h); - */ if (lay->scaledWidth() == ctx->screen->geo.w && lay->scaledHeight() == ctx->screen->geo.h) { uint8_t *ffbuf = (uint8_t *)lay->buffer; if (lay->buffer) { memcpy(buf, ffbuf, 4 * ctx->screen->geo.w * ctx->screen->geo.h *sizeof(uint8_t)); - /* - long blackness=(ctx->screen->geo.w * ctx->screen->geo.h); - // histogram - blackness=0; - int i; - for (i=0; i< 4 * ctx->screen->geo.w * ctx->screen->geo.h *sizeof(uint8_t);i+=4) { - blackness+=((buf[i+1]>>2) || (buf[i+2]>>2) || (buf[i+3]>>2))?1:0; - } - */ - //if (blackness >= (ctx->screen->geo.w * ctx->screen->geo.h)>>4) { if (skipCount > 50) { // TODO - implement properly - NSAutoreleasePool *pool; pool = [[NSAutoreleasePool alloc] init]; NSBitmapImageRep *imr = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:(unsigned char**)&buf @@ -171,14 +147,12 @@ previewImage = [[NSImage alloc] initWithSize:NSZeroSize]; [previewImage addRepresentation:imr]; [layerView setPosterImage:previewImage]; - //[previewImage release]; // XXX - this will be released by clearPreview [lock unlock]; [imr release]; [pool release]; } else { skipCount++; } - newFrame = YES; } } CVPixelBufferUnlockBaseAddress(frame, 0); @@ -203,11 +177,4 @@ } } -- (void)setRepeat:(BOOL)repeat -{ - CVFFmpegLayer *lay = (CVFFmpegLayer *)layer; - if (layer) - lay->repeat = repeat; -} - @end diff --git a/xcode/CVFFmpegLayerView.h b/xcode/CVFFmpegLayerView.h index dfe1d022..d9704a3d 100644 --- a/xcode/CVFFmpegLayerView.h +++ b/xcode/CVFFmpegLayerView.h @@ -32,6 +32,7 @@ - (IBAction)open:(id)sender; - (IBAction)close:(id)sender; +- (IBAction)toggleRepeat:(id)sender; @end #endif diff --git a/xcode/CVFFmpegLayerView.mm b/xcode/CVFFmpegLayerView.mm index 1ba09b27..4ad7deba 100644 --- a/xcode/CVFFmpegLayerView.mm +++ b/xcode/CVFFmpegLayerView.mm @@ -55,4 +55,12 @@ [super drawRect:theRect]; } +- (IBAction)toggleRepeat:(id)sender +{ + if ([sender state] == NSOnState) + [(CVFFmpegLayerController *)layerController setRepeat:YES]; + else + [(CVFFmpegLayerController *)layerController setRepeat:NO]; +} + @end diff --git a/xcode/CVFilterInstance.mm b/xcode/CVFilterInstance.mm index f26758bb..c222ea4f 100644 --- a/xcode/CVFilterInstance.mm +++ b/xcode/CVFilterInstance.mm @@ -43,18 +43,18 @@ CVFilterInstance::CVFilterInstance() } CVFilterInstance::CVFilterInstance(Filter *fr) + : FilterInstance() { cgContextRef = nil; ciContext = nil; ciFilter = nil; image = nil; - func("creating instance for filter %s",fr->name); init(fr); } void CVFilterInstance::init(Filter *fr) { - FilterInstance::init(fr); + FilterInstance::init(fr); ciFilter = [[CIFilter filterWithName:[NSString stringWithFormat:@"CI%s", fr->name]] retain]; [ciFilter setDefaults]; if (fr->type() == Filter::COREIMAGE) { diff --git a/xcode/CVFilterPanel.mm b/xcode/CVFilterPanel.mm index ee0ce8e1..3829b953 100644 --- a/xcode/CVFilterPanel.mm +++ b/xcode/CVFilterPanel.mm @@ -55,7 +55,7 @@ if(layer) { [layer setPreviewTarget:previewBox]; [showButton setState:[layer isVisible]?NSOnState:NSOffState]; - if ([layer needPreview]) { + if ([layer doPreview]) { [previewButton setState:NSOnState]; } else { [previewButton setState:NSOffState]; @@ -204,7 +204,7 @@ NSRect frame = NSMakeRect(0, [container frame].size.height - 25, 0, 20); // XXX while (param) { frame.origin.x = 0; - frame.size.width = [container frame].size.width / 2 - 10; // XXX + frame.size.width = [container frame].size.width / 2 - 5; // XXX NSTextView *newText = [[NSTextView alloc] initWithFrame:frame]; [newText setDrawsBackground:NO]; [newText setTextColor:[NSColor colorWithDeviceRed:1.0 green:1.0 blue:1.0 alpha:1.0]]; diff --git a/xcode/CVGenerator.m b/xcode/CVGenerator.m index 8ee7cf25..759dfdca 100644 --- a/xcode/CVGenerator.m +++ b/xcode/CVGenerator.m @@ -48,7 +48,7 @@ [lock unlock]; return freejImage; } - + - (void)prepareOpenGL { NSAutoreleasePool *pool; diff --git a/xcode/CVGeoLayer.h b/xcode/CVGeoLayer.h index 8d259442..32c6267e 100644 --- a/xcode/CVGeoLayer.h +++ b/xcode/CVGeoLayer.h @@ -31,7 +31,6 @@ public: CVGeoLayer(CVLayerController *vin); ~CVGeoLayer(); - int start(); void *do_filters(void *buf); protected: int currentIndex; diff --git a/xcode/CVGeoLayer.mm b/xcode/CVGeoLayer.mm index 4c4860ff..fe66acef 100644 --- a/xcode/CVGeoLayer.mm +++ b/xcode/CVGeoLayer.mm @@ -54,13 +54,6 @@ CVGeoLayer::~CVGeoLayer() free(frame); } -// ensure calling the start method from our CVLayer ancestor -// (and not from the GeoLayer one -int CVGeoLayer::start() -{ - return GeoLayer::start(); -} - void * CVGeoLayer::feed() { @@ -83,25 +76,21 @@ CVGeoLayer::feed() CVPixelBufferRelease(pixelBuffer); } NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - [input renderFrame]; - CVTexture *tx = [input getTexture]; - if (tx) { - // ensure providing the pixelbuffer to upper cocoa-related layers - CVPixelBufferRef pixelBuffer = [tx pixelBuffer]; - + CVPixelBufferRef pixelBuffer = [input currentFrame]; + if (pixelBuffer) { CVPixelBufferLockBaseAddress(pixelBuffer, 0); //void *frame = CVPixelBufferGetBaseAddress(pixelBuffer); if (!frame) frame = malloc(CVPixelBufferGetDataSize(pixelBuffer)); // TODO - try to avoid this copy!! + //lock(); memcpy(frame, CVPixelBufferGetBaseAddress(pixelBuffer), CVPixelBufferGetDataSize(pixelBuffer)); - - CVPixelBufferUnlockBaseAddress(pixelBuffer, 0); - //unlock(); - } + CVPixelBufferUnlockBaseAddress(pixelBuffer, 0); + CVPixelBufferRelease(pixelBuffer); + } [pool release]; return frame; } @@ -123,7 +112,7 @@ void *CVGeoLayer::do_filters(void *buf) { filters.unlock(); } // now that we have applied filters (if any) - // we can render the preview (if needed) - [input renderPreview]; + if ([input respondsToSelector:@selector(frameFiltered:)]) + [input frameFiltered:(void *)buf]; return buf; } diff --git a/xcode/CVLayer.h b/xcode/CVLayer.h index f4e65246..cb5fd8e0 100644 --- a/xcode/CVLayer.h +++ b/xcode/CVLayer.h @@ -54,8 +54,7 @@ protected: virtual void *feed(); private: - CVTexture *texture[2]; // double buffer - void *frame; + void *frame[2]; // double buffer unsigned int num; }; diff --git a/xcode/CVLayer.mm b/xcode/CVLayer.mm index c52ee7be..1d2e2074 100644 --- a/xcode/CVLayer.mm +++ b/xcode/CVLayer.mm @@ -23,20 +23,16 @@ CVLayer::CVLayer() : CVCocoaLayer(this), Layer() { type = Layer::GL_COCOA; buffer = NULL; - memset(texture, 0, sizeof(CVTexture *) * 2); - //texture = NULL; + memset(frame, 0, sizeof(void *) * 2); num = 0; - frame = NULL; } CVLayer::CVLayer(CVLayerController *vin) : Layer(), CVCocoaLayer(this, vin) { type = Layer::GL_COCOA; buffer = NULL; - frame = NULL; - memset(texture, 0, sizeof(CVTexture *) * 2); + memset(frame, 0, sizeof(void *) * 2); num = 0; - //texture = (CVTexture **)calloc(1, sizeof(CVTexture *) * 2); set_name([input name]); [input setLayer:this]; } @@ -45,14 +41,10 @@ CVLayer::~CVLayer() { stop(); close(); - if (frame) - free(frame); // release the double buffer if present for (int i = 0; i < 2; i++) { - if (texture[i]) { - [texture[i] release]; - texture[i] = NULL; - } + if (frame[i]) + free(frame[i]); } } @@ -120,34 +112,32 @@ CVLayer::relative_seek(double increment) void * CVLayer::feed() { + void *output = NULL; NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - [input renderFrame]; - - CVTexture *tx = [input getTexture]; - if (tx) { + + CVPixelBufferRef pixelBuffer = [input currentFrame]; + if (pixelBuffer) { num++; + int idx = num % 2; //lock(); - if (texture[num%2]) - [(CVTexture *)texture[num%2] release]; - - texture[num%2] = [tx retain]; // ensure providing the pixelbuffer to upper cocoa-related layers - CVPixelBufferRef pixelBuffer = [texture[num%2] pixelBuffer]; CVPixelBufferLockBaseAddress(pixelBuffer, 0); //void *frame = CVPixelBufferGetBaseAddress(pixelBuffer); - if (!frame) - frame = malloc(CVPixelBufferGetDataSize(pixelBuffer)); + if (!frame[idx]) + frame[idx] = malloc(CVPixelBufferGetDataSize(pixelBuffer)); // TODO - try to avoid this copy!! - memcpy(frame, CVPixelBufferGetBaseAddress(pixelBuffer), CVPixelBufferGetDataSize(pixelBuffer)); - + //lock(); + memcpy(frame[idx], CVPixelBufferGetBaseAddress(pixelBuffer), CVPixelBufferGetDataSize(pixelBuffer)); + //unlock(); CVPixelBufferUnlockBaseAddress(pixelBuffer, 0); - + output = frame[idx]; + CVPixelBufferRelease(pixelBuffer); //unlock(); } [pool release]; - return frame; + return output; } void *CVLayer::do_filters(void *buf) { @@ -165,8 +155,8 @@ void *CVLayer::do_filters(void *buf) { } filters.unlock(); } - // now that we have applied filters (if any) - // we can render the preview (if needed) - [input renderPreview]; + if ([input respondsToSelector:@selector(frameFiltered:)]) + [input frameFiltered:(void *)buf]; + return buf; } diff --git a/xcode/CVLayerController.h b/xcode/CVLayerController.h index c1304229..3bce6ce0 100644 --- a/xcode/CVLayerController.h +++ b/xcode/CVLayerController.h @@ -35,17 +35,11 @@ class CVCocoaLayer; CFreej *freej; NSRecursiveLock *lock; - bool newFrame; CVPixelBufferRef currentFrame; // the current frame from the movie CVTexture *cvTexture; CIImage *posterImage; - bool doPreview; CVTexture *currentPreviewTexture; CGLContextObj glContext; - - // display link - CVDisplayLinkRef displayLink; // the displayLink that runs the show - CGDirectDisplayID viewDisplayID; // filters for CI rendering CIFilter *colorCorrectionFilter; // hue saturation brightness control through one CI filter CIFilter *compositeFilter; // composites the timecode over the video @@ -62,32 +56,43 @@ class CVCocoaLayer; CVCocoaLayer *layer; CVPreview *previewTarget; IBOutlet CVLayerView *layerView; - bool doFilters; - bool filtersInitialized; + BOOL doPreview; + BOOL doFilters; + BOOL wantsRepeat; + BOOL filtersInitialized; } @property (readwrite, assign) CFreej *freej; @property (readwrite) CVCocoaLayer *layer; @property (readonly) CVLayerView *layerView; - // subclass implementation should override this method and update - // the currentFrame pointer only within the renderFrame implementation + @property (readwrite) BOOL doPreview; + @property (readwrite) BOOL doFilters; + @property (readwrite) BOOL wantsRepeat; + + // Subclasses can override this method to feed the current frame before returning it + // To provide the frame [self feedFrame:] must be called. + // The returned CVPixelBufferRef is retained and MUST be released by the caller. + // NOTE : usually this is called from the C++ layer implementation , within the feed() method. + // But some Cocoa-layers could lack a specific C++ class since the frame is created + // directly in the cocoa implementation. + // In such cases (for instance QTLayerController and CVTextLayerController) 'currentFrame' + // is overridden to provide the new pixel buffer before calling [super currentFrame] + - (CVPixelBufferRef)currentFrame; - (char *)name; + // applies image parameters (brightness, contrast, exposure, etc) and stores the new frame as 'current' on + // (to be later returned by [self currentFrame] - (void)feedFrame:(CVPixelBufferRef)frame; - - (CVReturn)renderFrame; + - (void)frameFiltered:(void *)buffer; - (id)initWithContext:(CFreej *)context; - (void)startPreview; // enable preview rendering - (void)stopPreview; // disable preview rendering - - (void)renderPreview; // render the preview frame + - (void)renderPreview:(CVPixelBufferRef)frame; // render the preview frame - (bool)isVisible; // query the layer to check if it's being sent to the Screen or not - (NSString *)blendMode; - (void)activate; /// activate the underlying CVLayer - (void)deactivate; /// deactivate the underlying CVLayer - // Retain currentFrame, apply filters and return a CVTexture - - (CVTexture *)getTexture; // query the layer to check if it needs to display a preview or not (used by CVPreview) - - (bool)needPreview; - (NSDictionary *)imageParams; - //- (void)setContext:(CFreej *)ctx; - (void)setPreviewTarget:(CVPreview *)targetView; - (CVPreview *)getPreviewTarget; - (void)lock; /// accessor to the internal mutex @@ -100,13 +105,13 @@ class CVCocoaLayer; - (void)toggleFilters; - (void)toggleVisibility; - (void)togglePreview; - - (bool)doPreview; + - (BOOL)doPreview; + - (BOOL)wantsRepeat; + - (void)setRepeat:(BOOL)repeat; - (void)setBlendMode:(NSString *)mode; - (void)initFilters; - (int)width; - (int)height; - //- (void)filterFrame:(CIFilter *)filter; - //- (void)filterFrame:(FilterInstance *)filter; - (Linklist *)activeFilters; - (IBAction)setImageParameter:(id)sender; /// tags from 0 to 10 - (IBAction)setValue:(NSNumber *)value forImageParameter:(NSString *)parameter; diff --git a/xcode/CVLayerController.mm b/xcode/CVLayerController.mm index 237bcd78..632b5606 100644 --- a/xcode/CVLayerController.mm +++ b/xcode/CVLayerController.mm @@ -99,7 +99,8 @@ static OSStatus SetNumberValue(CFMutableDictionaryRef inDict, [scaleFilter release]; [translateFilter release]; ///[timeCodeOverlay release]; - CVOpenGLTextureRelease(currentFrame); + if (currentFrame) + CVOpenGLTextureRelease(currentFrame); if (imageParams) [imageParams release]; [lock release]; @@ -109,23 +110,9 @@ static OSStatus SetNumberValue(CFMutableDictionaryRef inDict, - (void)prepareOpenGL { - CGOpenGLDisplayMask totalDisplayMask = 0; - int virtualScreen; - GLint displayMask; NSAutoreleasePool *pool; pool = [[NSAutoreleasePool alloc] init]; - // Create display link - if (layerView) { - NSOpenGLPixelFormat *openGLPixelFormat = [layerView pixelFormat]; - viewDisplayID = (CGDirectDisplayID)[[[[[layerView window] screen] deviceDescription] objectForKey:@"NSScreenNumber"] intValue]; // we start with our view on the main display - // build up list of displays from OpenGL's pixel format - for (virtualScreen = 0; virtualScreen < [openGLPixelFormat numberOfVirtualScreens]; virtualScreen++) - { - [openGLPixelFormat getValues:&displayMask forAttribute:NSOpenGLPFAScreenMask forVirtualScreen:virtualScreen]; - totalDisplayMask |= displayMask; - } - } // Setup the timecode overlay /* NSDictionary *fontAttributes = [[NSDictionary alloc] initWithObjectsAndKeys:[NSFont labelFontOfSize:24.0f], NSFontAttributeName, @@ -146,24 +133,28 @@ static OSStatus SetNumberValue(CFMutableDictionaryRef inDict, Layer *fjLayer = NULL; NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - + if (!filtersInitialized) + [self initFilters]; // initialize on first use + if (layer) fjLayer = layer->fjLayer(); else return; [lock lock]; - if (!currentFrame) { - CVReturn err = CVPixelBufferCreate ( - NULL, - fjLayer->geo.w, - fjLayer->geo.h, - k32ARGBPixelFormat, - NULL, - ¤tFrame - ); - } + if (currentFrame) + CVPixelBufferRelease(currentFrame); + + CVReturn err = CVPixelBufferCreate ( + NULL, + fjLayer->geo.w, + fjLayer->geo.h, + k32ARGBPixelFormat, + NULL, + ¤tFrame + ); //currentFrame = CVPixelBufferRetain(frame); // TODO - check error code + //fjLayer->lock(); CIImage *inputImage = [CIImage imageWithCVImageBuffer:frame]; CGRect bounds = CGRectMake(0, 0, fjLayer->geo.w, fjLayer->geo.h); @@ -185,15 +176,16 @@ static OSStatus SetNumberValue(CFMutableDictionaryRef inDict, ); CVPixelBufferUnlockBaseAddress(currentFrame, 0); if (!context) { + //fjLayer->unlock(); // todo - error messages return; } NSDictionary *ciContextOptions = [NSDictionary dictionaryWithObject:(NSString*)kCGColorSpaceGenericRGB forKey: kCIContextOutputColorSpace]; CIContext *ciCtx = [CIContext contextWithCGContext:context options:ciContextOptions]; - //CGContextRelease(context); + CGContextRelease(context); -// if (doFilters) { + if (doFilters) { [colorCorrectionFilter setValue:inputImage forKey:@"inputImage"]; [exposureAdjustFilter setValue:[colorCorrectionFilter valueForKey:@"outputImage"] forKey:@"inputImage"]; [alphaFilter setValue:[exposureAdjustFilter valueForKey:@"outputImage"] @@ -209,46 +201,15 @@ static OSStatus SetNumberValue(CFMutableDictionaryRef inDict, } else { renderedImage = [rotateFilter valueForKey:@"outputImage"]; } -// } else { -// renderedImage = inputImage; -// } + } else { + renderedImage = inputImage; + } [ciCtx drawImage:renderedImage inRect:bounds fromRect:bounds]; - newFrame = YES; [lock unlock]; [pool release]; - //[self renderFrame]; } - -- (CVReturn)renderFrame -{ - CIImage *inputImage = nil; - CIImage *renderedImage = nil; - Layer *fjLayer = NULL; - - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - - if (layer) - fjLayer = layer->fjLayer(); - else - return kCVReturnError; - - if (!filtersInitialized) - [self initFilters]; // initialize on first use - - if (newFrame) { - [lock lock]; - if (cvTexture) - [cvTexture release]; - cvTexture = [[CVTexture alloc] initWithCIImage:inputImage pixelBuffer:currentFrame]; - newFrame = NO; - [lock unlock]; - //[self renderPreview]; - } - [pool release]; - return kCVReturnSuccess; -} - + - (IBAction)toggleFilters:(id)sender { doFilters = doFilters?false:true; @@ -452,18 +413,13 @@ static OSStatus SetNumberValue(CFMutableDictionaryRef inDict, //[lock unlock]; } -- (void)renderPreview +- (void)renderPreview:(CVPixelBufferRef)frame { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; if ([self doPreview] && previewTarget) { // scale the frame to fit the preview - if (![previewTarget isHiddenOrHasHiddenAncestor]) { - Layer *fjLayer = layer->fjLayer(); - // XXX - it's too dangerous to access layer->buffer directly - if (fjLayer && fjLayer->buffer) - [previewTarget renderFrame:fjLayer]; - } - + if (![previewTarget isHiddenOrHasHiddenAncestor]) + [previewTarget renderFrame:frame]; } [pool release]; } @@ -519,20 +475,42 @@ static OSStatus SetNumberValue(CFMutableDictionaryRef inDict, filtersInitialized = true; } -- (CVTexture *)getTexture +- (CVPixelBufferRef)currentFrame { - CVTexture *texture = nil; + CVPixelBufferRef frame; [lock lock]; - texture = [cvTexture retain]; + frame = CVPixelBufferRetain(currentFrame); [lock unlock]; - - return [texture autorelease]; + + return frame; } - -- (bool)needPreview +- (void)frameFiltered:(void *)buffer { - return doPreview; + // we have been notified that the frame has been filtered + // and 'buffer' holds the data for the filtered image + // (it will still have the some pixelformat and dimensions of original image) + // XXX - actually we don't store the filtered image, but we use it just for preview + if (layer && doPreview) { + CVPixelBufferRef pixelBufferFiltered; + CVReturn cvRet = CVPixelBufferCreateWithBytes ( + NULL, + layer->width(), + layer->height(), + k32ARGBPixelFormat, + buffer, + layer->width()*4, + NULL, + NULL, + NULL, + &pixelBufferFiltered + ); + // TODO - Error Messages + if (cvRet == noErr) { + [self renderPreview:pixelBufferFiltered]; + CVPixelBufferRelease(pixelBufferFiltered); + } + } } - (void)startPreview @@ -665,7 +643,7 @@ static OSStatus SetNumberValue(CFMutableDictionaryRef inDict, doPreview = doPreview?NO:YES; } -- (bool)doPreview +- (BOOL)doPreview { return doPreview; } @@ -712,8 +690,22 @@ static OSStatus SetNumberValue(CFMutableDictionaryRef inDict, return 0; } + +- (void)setRepeat:(BOOL)repeat +{ + wantsRepeat = repeat; +} + +- (BOOL)wantsRepeat +{ + return wantsRepeat; +} + @synthesize freej; @synthesize layer; @synthesize layerView; +@synthesize wantsRepeat; +@synthesize doPreview; +@synthesize doFilters; @end diff --git a/xcode/CVLayerView.h b/xcode/CVLayerView.h index b2ac8ca4..93bdacef 100644 --- a/xcode/CVLayerView.h +++ b/xcode/CVLayerView.h @@ -55,7 +55,6 @@ class CVLayer; - (bool)needPreview; // true if we need to provide a preview, else otherwise - (void)startPreview; // enable preview rendering - (void)stopPreview; // disable preview rendering -- (void)renderPreview; // render the preview frame - (bool)isVisible; // query the layer to check if it's being sent to the Screen or not - (void)activate; /// activate the underlying CVLayer - (void)deactivate; /// deactivate the underlying CVLayer diff --git a/xcode/CVLayerView.mm b/xcode/CVLayerView.mm index e95b0cd7..23424c56 100644 --- a/xcode/CVLayerView.mm +++ b/xcode/CVLayerView.mm @@ -203,13 +203,6 @@ } -- (void)renderPreview -{ - if (layerController) - [layerController renderPreview]; -} - - - (void)mouseDown:(NSEvent *)theEvent { [filterPanel setLayer:layerController]; [filterPanel show]; diff --git a/xcode/CVPreview.h b/xcode/CVPreview.h index 7d27e78f..bc8d65dc 100644 --- a/xcode/CVPreview.h +++ b/xcode/CVPreview.h @@ -30,7 +30,7 @@ IBOutlet CFreej *freej; } -- (void)renderFrame:(Layer *)layer; +- (void)renderFrame:(CVPixelBufferRef)pixelBufferIn; - (void)clear; @end diff --git a/xcode/CVPreview.mm b/xcode/CVPreview.mm index 3770ffde..73d97ea2 100644 --- a/xcode/CVPreview.mm +++ b/xcode/CVPreview.mm @@ -135,72 +135,50 @@ [pool release]; } -- (void)renderFrame:(Layer *)layer +- (void)renderFrame:(CVPixelBufferRef)pixelBufferIn { NSRect frame = [self frame]; NSRect bounds = [self bounds]; float scaleFactor; //CVTexture *textureToRelease = nil; Context *ctx = (Context *)[freej getContext]; - CVPixelBufferRef pixelBufferIn; CIImage *ciImage; NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; @synchronized(self) { - layer->lock(); - CVReturn cvRet = CVPixelBufferCreateWithBytes ( - NULL, - layer->geo.w, - layer->geo.h, - k32ARGBPixelFormat, - layer->buffer, - layer->geo.w*4, - NULL, - NULL, - NULL, - &pixelBufferIn - ); - if (cvRet == kCVReturnSuccess) { - CIImage *inputImage = [CIImage imageWithCVImageBuffer:pixelBufferIn]; + CIImage *inputImage = [CIImage imageWithCVImageBuffer:pixelBufferIn]; - NSAffineTransform *scaleTransform = [NSAffineTransform transform]; + NSAffineTransform *scaleTransform = [NSAffineTransform transform]; - scaleFactor = frame.size.height/ctx->screen->geo.h; - [scaleTransform scaleBy:scaleFactor]; - CIFilter *scaleFilter = [CIFilter filterWithName:@"CIAffineTransform"]; - [scaleFilter setDefaults]; // set the filter to its default values + scaleFactor = frame.size.height/ctx->screen->geo.h; + [scaleTransform scaleBy:scaleFactor]; + CIFilter *scaleFilter = [CIFilter filterWithName:@"CIAffineTransform"]; + [scaleFilter setDefaults]; // set the filter to its default values - [scaleFilter setValue:scaleTransform forKey:@"inputTransform"]; - [scaleFilter setValue:inputImage forKey:@"inputImage"]; + [scaleFilter setValue:scaleTransform forKey:@"inputTransform"]; + [scaleFilter setValue:inputImage forKey:@"inputImage"]; - CIImage *previewImage = [scaleFilter valueForKey:@"outputImage"]; - // output the downscaled frame in the preview window - // XXX - I'm not sure we really need locking here + CIImage *previewImage = [scaleFilter valueForKey:@"outputImage"]; + // output the downscaled frame in the preview window + // XXX - I'm not sure we really need locking here - CGRect imageRect = CGRectMake(NSMinX(bounds), NSMinY(bounds), - NSWidth(bounds), NSHeight(bounds)); - if( kCGLNoError != CGLLockContext((CGLContextObj)[[self openGLContext] CGLContextObj]) ) - return; + CGRect imageRect = CGRectMake(NSMinX(bounds), NSMinY(bounds), + NSWidth(bounds), NSHeight(bounds)); + if( kCGLNoError != CGLLockContext((CGLContextObj)[[self openGLContext] CGLContextObj]) ) + return; - CGPoint origin; + CGPoint origin; - origin.x = (frame.size.width-(ctx->screen->geo.w * scaleFactor))/2; - origin.y = (frame.size.height-(ctx->screen->geo.h * scaleFactor))/2; - [ciContext drawImage:previewImage - atPoint: origin - fromRect: imageRect]; - //[self drawRect:NSZeroRect]; - CGLUnlockContext((CGLContextObj)[[self openGLContext] CGLContextObj]); - - [self setNeedsDisplay:YES]; - //if (textureToRelease) - // [textureToRelease release]; - CVPixelBufferRelease(pixelBufferIn); - } - layer->unlock(); + origin.x = (frame.size.width-(ctx->screen->geo.w * scaleFactor))/2; + origin.y = (frame.size.height-(ctx->screen->geo.h * scaleFactor))/2; + [ciContext drawImage:previewImage + atPoint: origin + fromRect: imageRect]; + //[self drawRect:NSZeroRect]; + CGLUnlockContext((CGLContextObj)[[self openGLContext] CGLContextObj]); + [self setNeedsDisplay:YES]; } - [pool release]; } diff --git a/xcode/CVQtLayerController.h b/xcode/CVQtLayerController.h index 055ca149..27726606 100644 --- a/xcode/CVQtLayerController.h +++ b/xcode/CVQtLayerController.h @@ -37,7 +37,6 @@ #endif uint64_t lastPTS; bool isPlaying; - bool wantsRepeat; } - (BOOL)setQTMovie:(QTMovie *)movie; - (void)unloadMovie; @@ -46,7 +45,6 @@ - (void)setTime:(QTTime)inTime; - (BOOL)togglePlay; - (void)task; -- (void)setRepeat:(BOOL)repeat; @end #endif diff --git a/xcode/CVQtLayerController.mm b/xcode/CVQtLayerController.mm index 8b2123a6..476202cb 100644 --- a/xcode/CVQtLayerController.mm +++ b/xcode/CVQtLayerController.mm @@ -286,9 +286,7 @@ static OSStatus SetNumberValue(CFMutableDictionaryRef inDict, #endif nil] error:nil]; - - // rendering (aka: applying filters) is now done in getTexture() - // implemented in CVLayerController (our parent) + // provide the frame to lower layers [self feedFrame:newPixelBuffer]; rv = YES; #else @@ -301,9 +299,10 @@ static OSStatus SetNumberValue(CFMutableDictionaryRef inDict, // rendering (aka: applying filters) is now done in getTexture() // implemented in CVLayerView (our parent) - - [self feedFrame:newPixelBuffer]; - rv = YES; + if (newPixelBuffeR) { + [self feedFrame:newPixelBuffer]; + rv = YES; + } } #endif [lock unlock]; @@ -316,8 +315,8 @@ static OSStatus SetNumberValue(CFMutableDictionaryRef inDict, return rv; } - -- (CVReturn)renderFrame +// we fetch the image from QTKit just when asked from upper layers +- (CVPixelBufferRef)currentFrame { NSAutoreleasePool *pool = nil; @@ -329,7 +328,7 @@ static OSStatus SetNumberValue(CFMutableDictionaryRef inDict, else rv = kCVReturnError; [pool release]; - return [super renderFrame]; + return [super currentFrame]; } - (void)task @@ -349,11 +348,6 @@ static OSStatus SetNumberValue(CFMutableDictionaryRef inDict, return true; } -- (void)setRepeat:(BOOL)repeat -{ - wantsRepeat = repeat; -} - //@synthesize qtMovie; //#endif // no __x86_64 diff --git a/xcode/CVQtLayerView.mm b/xcode/CVQtLayerView.mm index 3dd13c8f..7eef53e8 100644 --- a/xcode/CVQtLayerView.mm +++ b/xcode/CVQtLayerView.mm @@ -96,8 +96,10 @@ - (IBAction)toggleRepeat:(id)sender { - [(CVQtLayerController *)layerController setRepeat: - ([repeatButton state] == NSOnState)?YES:NO]; + if ([sender state] == NSOnState) + [(CVQtLayerController *)layerController setRepeat:YES]; + else + [(CVQtLayerController *)layerController setRepeat:NO]; } @end diff --git a/xcode/CVTextLayerController.mm b/xcode/CVTextLayerController.mm index 78df762f..9fa0f142 100644 --- a/xcode/CVTextLayerController.mm +++ b/xcode/CVTextLayerController.mm @@ -29,7 +29,7 @@ return [super init]; } -- (CVReturn)renderFrame +- (CVPixelBufferRef)currentFrame { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; Context *ctx = [freej getContext]; @@ -62,9 +62,8 @@ needsNewFrame = NO; } [lock unlock]; - //[self renderPreview]; [pool release]; - return [super renderFrame]; + return [super currentFrame]; } - (IBAction)setText:(NSString *)theText withAttributes:(NSDictionary *)attributes diff --git a/xcode/English.lproj/MainMenu.nib/designable.nib b/xcode/English.lproj/MainMenu.nib/designable.nib index 654fcd60..5d55ed3d 100644 --- a/xcode/English.lproj/MainMenu.nib/designable.nib +++ b/xcode/English.lproj/MainMenu.nib/designable.nib @@ -12,8 +12,8 @@ YES + - YES @@ -4930,48 +4930,6 @@ ARcABAAAAAEAAAACARwAAwAAAAEAAQAAAVIAAwAAAAEAAQAAAVMAAwAAAAIAAQABAAAAAA {{0, 0}, {1440, 878}} {1.79769e+308, 1.79769e+308} - - - -2147483392 - {430, 307} - 2 - 103 - YES - - -2079981824 - 131072 - - - - - - 3 - 50 - 0.0 - 0.0 - 0.0 - 0 - 1 - NO - NO - - - - - -2147483392 - {60, 18} - 2 - YES - - 67239424 - 4194304 - Param4 - - - - - - @@ -6408,22 +6366,6 @@ ARcABAAAAAEAAAACARwAAwAAAAEAAQAAAVIAAwAAAAEAAQAAAVMAAwAAAAIAAQABAAAAAA 3266 - - - nextKeyView - - - - 3287 - - - - setFilterParameter: - - - - 3291 - activeFilters @@ -6512,6 +6454,54 @@ ARcABAAAAAEAAAACARwAAwAAAAEAAQAAAVIAAwAAAAEAAQAAAVMAAwAAAAIAAQABAAAAAA 3307 + + + toggleRepeat: + + + + 3308 + + + + toggleRepeat: + + + + 3309 + + + + toggleRepeat: + + + + 3310 + + + + toggleRepeat: + + + + 3311 + + + + toggleRepeat: + + + + 3312 + + + + toggleRepeat: + + + + 3313 + @@ -8360,7 +8350,7 @@ ARcABAAAAAEAAAACARwAAwAAAAEAAQAAAVIAAwAAAAEAAQAAAVMAAwAAAAIAAQABAAAAAA 2824 - Grabber Controller + Grabber 2825 @@ -9451,34 +9441,6 @@ ARcABAAAAAEAAAACARwAAwAAAAEAAQAAAVIAAwAAAAEAAQAAAVMAAwAAAAIAAQABAAAAAA - - 3269 - - - YES - - - - - - 3280 - - - - - 3267 - - - YES - - - - - - 3282 - - - @@ -10042,14 +10004,6 @@ ARcABAAAAAEAAAACARwAAwAAAAEAAQAAAVIAAwAAAAEAAQAAAVMAAwAAAAIAAQABAAAAAA 3231.IBPluginDependency 3264.IBPluginDependency 3265.IBPluginDependency - 3267.IBEditorWindowLastContentRect - 3267.IBPluginDependency - 3267.ImportedFromIB2 - 3269.IBEditorWindowLastContentRect - 3269.IBPluginDependency - 3269.ImportedFromIB2 - 3280.IBPluginDependency - 3282.IBPluginDependency 344.IBPluginDependency 345.IBPluginDependency 346.IBPluginDependency @@ -10976,14 +10930,6 @@ ARcABAAAAAEAAAACARwAAwAAAAEAAQAAAVIAAwAAAAEAAQAAAVMAAwAAAAIAAQABAAAAAA com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin - {{42, 781}, {60, 18}} - com.apple.InterfaceBuilder.CocoaPlugin - - {{63, 469}, {430, 307}} - com.apple.InterfaceBuilder.CocoaPlugin - - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin @@ -11065,7 +11011,7 @@ ARcABAAAAAEAAAACARwAAwAAAAEAAQAAAVIAAwAAAAEAAQAAAVMAAwAAAAIAAQABAAAAAA - 3307 + 3313 @@ -11346,11 +11292,13 @@ ARcABAAAAAEAAAACARwAAwAAAAEAAQAAAVIAAwAAAAEAAQAAAVMAAwAAAAIAAQABAAAAAA YES close: open: + toggleRepeat: YES id id + id @@ -11359,6 +11307,7 @@ ARcABAAAAAEAAAACARwAAwAAAAEAAQAAAVIAAwAAAAEAAQAAAVMAAwAAAAIAAQABAAAAAA YES close: open: + toggleRepeat: YES @@ -11370,6 +11319,10 @@ ARcABAAAAAEAAAACARwAAwAAAAEAAQAAAVIAAwAAAAEAAQAAAVMAAwAAAAIAAQABAAAAAA open: id + + toggleRepeat: + id + @@ -11423,7 +11376,7 @@ ARcABAAAAAEAAAACARwAAwAAAAEAAQAAAVIAAwAAAAEAAQAAAVMAAwAAAAIAAQABAAAAAA CVFilterPanel - + IBProjectSource CVFilterPanel.h @@ -11519,51 +11472,12 @@ ARcABAAAAAEAAAACARwAAwAAAAEAAQAAAVIAAwAAAAEAAQAAAVMAAwAAAAIAAQABAAAAAA - + CVGrabber QTCaptureDecompressedVideoOutput - - YES - - YES - captureSize - freej - grabberController - - - YES - NSPopUpButton - CFreej - CVGrabberController - - - - YES - - YES - captureSize - freej - grabberController - - - YES - - captureSize - NSPopUpButton - - - freej - CFreej - - - grabberController - CVGrabberController - - - - + IBProjectSource CVGrabber.h @@ -11571,7 +11485,7 @@ ARcABAAAAAEAAAACARwAAwAAAAEAAQAAAVIAAwAAAAEAAQAAAVMAAwAAAAIAAQABAAAAAA CVGrabberController CVLayerController - + CVGrabberView @@ -12296,21 +12210,21 @@ ARcABAAAAAEAAAACARwAAwAAAAEAAQAAAVIAAwAAAAEAAQAAAVMAAwAAAAIAAQABAAAAAA NSApplication NSResponder - + IBFrameworkSource AppKit.framework/Headers/NSApplication.h NSApplication - + IBFrameworkSource AppKit.framework/Headers/NSApplicationScripting.h NSApplication - + IBFrameworkSource AppKit.framework/Headers/NSColorPanel.h @@ -12379,7 +12293,7 @@ ARcABAAAAAEAAAACARwAAwAAAAEAAQAAAVIAAwAAAAEAAQAAAVMAAwAAAAIAAQABAAAAAA NSControl NSView - + IBFrameworkSource AppKit.framework/Headers/NSControl.h @@ -12532,7 +12446,7 @@ ARcABAAAAAEAAAACARwAAwAAAAEAAQAAAVIAAwAAAAEAAQAAAVMAAwAAAAIAAQABAAAAAA NSMenu NSObject - + IBFrameworkSource AppKit.framework/Headers/NSMenu.h @@ -12540,7 +12454,7 @@ ARcABAAAAAEAAAACARwAAwAAAAEAAQAAAVIAAwAAAAEAAQAAAVMAAwAAAAIAAQABAAAAAA NSMenuItem NSObject - + IBFrameworkSource AppKit.framework/Headers/NSMenuItem.h @@ -12570,19 +12484,19 @@ ARcABAAAAAEAAAACARwAAwAAAAEAAQAAAVIAAwAAAAEAAQAAAVMAAwAAAAIAAQABAAAAAA NSObject - + NSObject - + NSObject - + NSObject - + NSObject @@ -12621,7 +12535,7 @@ ARcABAAAAAEAAAACARwAAwAAAAEAAQAAAVIAAwAAAAEAAQAAAVMAAwAAAAIAAQABAAAAAA NSObject - + NSObject @@ -12653,7 +12567,7 @@ ARcABAAAAAEAAAACARwAAwAAAAEAAQAAAVIAAwAAAAEAAQAAAVMAAwAAAAIAAQABAAAAAA NSObject - + IBFrameworkSource AppKit.framework/Headers/NSTableView.h @@ -12667,7 +12581,7 @@ ARcABAAAAAEAAAACARwAAwAAAAEAAQAAAVIAAwAAAAEAAQAAAVMAAwAAAAIAAQABAAAAAA NSObject - + IBFrameworkSource AppKit.framework/Headers/NSView.h @@ -12814,7 +12728,7 @@ ARcABAAAAAEAAAACARwAAwAAAAEAAQAAAVIAAwAAAAEAAQAAAVMAAwAAAAIAAQABAAAAAA NSObject - + IBFrameworkSource QTKit.framework/Headers/QTCaptureDecompressedVideoOutput.h @@ -12849,7 +12763,7 @@ ARcABAAAAAEAAAACARwAAwAAAAEAAQAAAVIAAwAAAAEAAQAAAVMAAwAAAAIAAQABAAAAAA NSObject - + IBFrameworkSource QTKit.framework/Headers/QTMovieView.h @@ -13005,7 +12919,7 @@ ARcABAAAAAEAAAACARwAAwAAAAEAAQAAAVIAAwAAAAEAAQAAAVMAAwAAAAIAAQABAAAAAA NSTableView NSControl - + NSText @@ -13048,7 +12962,7 @@ ARcABAAAAAEAAAACARwAAwAAAAEAAQAAAVIAAwAAAAEAAQAAAVMAAwAAAAIAAQABAAAAAA NSView - + NSView @@ -13060,7 +12974,7 @@ ARcABAAAAAEAAAACARwAAwAAAAEAAQAAAVIAAwAAAAEAAQAAAVMAAwAAAAIAAQABAAAAAA NSView NSResponder - + NSWindow @@ -13106,7 +13020,7 @@ ARcABAAAAAEAAAACARwAAwAAAAEAAQAAAVIAAwAAAAEAAQAAAVMAAwAAAAIAAQABAAAAAA QTCaptureDecompressedVideoOutput QTCaptureOutput - + QTCaptureOutput @@ -13270,7 +13184,7 @@ ARcABAAAAAEAAAACARwAAwAAAAEAAQAAAVIAAwAAAAEAAQAAAVMAAwAAAAIAAQABAAAAAA - + diff --git a/xcode/English.lproj/MainMenu.nib/keyedobjects.nib b/xcode/English.lproj/MainMenu.nib/keyedobjects.nib index 61a93549..bde3a25c 100644 Binary files a/xcode/English.lproj/MainMenu.nib/keyedobjects.nib and b/xcode/English.lproj/MainMenu.nib/keyedobjects.nib differ