// // ElisLayer.m // Elis Colors // // Created by 柳 on 09/09/12. // Copyright 2009 __MyCompanyName__. All rights reserved. // #import "ElisLayer.h" static float convertQTTimeToSecond(QTTime t) { return (float)t.timeValue/t.timeScale; } @implementation ElisLayer @synthesize media; - (id)init { self.media = nil; position.x = 0; position.y = 0; offset = QTZeroTime; effects = [[NSMutableArray alloc] init]; pxKeyframe = [[ElisKeyframe alloc] init]; pyKeyframe = [[ElisKeyframe alloc] init]; [pxKeyframe setValueForTime:0.0 time:QTZeroTime]; [pyKeyframe setValueForTime:0.0 time:QTZeroTime]; [self addEffect:@"CIOpacity"]; //デフォルトで透過度フィルタと // [self addEffect:@"CILanczosScaleTransform"]; // 拡大縮小フィルタと [self addEffect:@"CIAffineTransform"]; // アフィン変換フィルタはつけておく。 return self; } - (void)setAlayer:(CALayer *)layer { alayer = layer; [layer setValue:self forKey:@"ElisLayer"]; // layer.frameをバインド。 [layer addObserver:self forKeyPath:@"frame" options:(NSKeyValueObservingOptionNew) context:NULL]; } - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { [self changeMapping]; } - (void)addEffect:(NSString*)name { [effects addObject:[[ElisEffect alloc] initWithName:name]]; } - (void)changeMapping { CGRect frame = alayer.frame; QTTime begin = QTMakeTime(frame.origin.x*DEFAULT_FPS/timeLineScale, DEFAULT_FPS); QTTime d = QTMakeTime(frame.size.width*DEFAULT_FPS/timeLineScale, DEFAULT_FPS); trackNumber = floor(frame.origin.y/51.0); mapping = QTMakeTimeRange(begin, d); // mappingとtrackNumberを変化させる。 } - (void)changeOffset:(float)df { QTTime new_offset = QTTimeIncrement(offset, QTMakeTime(df*DEFAULT_FPS/timeLineScale, DEFAULT_FPS)); offset = new_offset; } - (BOOL)canChangeMapping:(CGRect)rect { QTTime duration = [media duration]; QTTime wantDuration = QTMakeTime(rect.size.width*DEFAULT_FPS/timeLineScale, DEFAULT_FPS); float d = convertQTTimeToSecond(duration) - convertQTTimeToSecond(offset); float wd = convertQTTimeToSecond(wantDuration); return 0.5 <= wd && wd <= d; } - (BOOL)canChangeOffset:(float)df { float now_offset = convertQTTimeToSecond(offset); float duration = convertQTTimeToSecond([media duration]); df /= timeLineScale; return 0.0 <= df + now_offset && df + now_offset <= duration; } - (BOOL)isInclude:(QTTime)time { float t = convertQTTimeToSecond(time); float begin = convertQTTimeToSecond(mapping.time); return begin <= t && t <= begin + convertQTTimeToSecond(mapping.duration); // return QTTimeInTimeRange(time, mapping); // これだとマルチスレッドにできなくね? } - (int)trackNumber { return trackNumber; } - (void)setPositionX:(float)x forTime:(QTTime)time { if(recording) [pxKeyframe setValueForTime:x time:time]; else [pxKeyframe setValueForTime:x time:QTZeroTime]; } - (void)setPositionY:(float)y forTime:(QTTime)time { if(recording) [pyKeyframe setValueForTime:y time:time]; else [pyKeyframe setValueForTime:y time:QTZeroTime]; } - (CIImage*)getEffectedImage:(CVTimeStamp*)timeStamp forTime:(QTTime)time { QTTime innerTime = QTTimeDecrement(time, mapping.time); CIImage* image = [media getFrameForTime:timeStamp]; if(image == nil) return nil; return [self applyEffects:image forTime:QTTimeIncrement(innerTime, offset)]; } - (CIImage*)getEffectedImageWithoutStamp:(QTTime)time { QTTime innerTime = QTTimeDecrement(time, mapping.time); CIImage* image = [media getFrameForQTTime:QTTimeIncrement(innerTime, offset)]; if(image == nil) return nil; return [self applyEffects:image forTime:QTTimeIncrement(innerTime, offset)]; } - (CIImage*)applyEffects:(CIImage*)image forTime:(QTTime)time { int i, size = [effects count]; ElisEffect* ef; for(i = 0; i < size; i++){ ef = [effects objectAtIndex:i]; [ef setInputImage:image]; image = [ef getImage:time]; } return image; } - (NSPoint)getPositionForTime:(QTTime)time { float x = [pxKeyframe getValueForTime:time]; float y = [pyKeyframe getValueForTime:time]; return NSMakePoint(x, y); } - (void)play { [media play]; } - (void)stop { [media stop]; } - (void)releaseContext { [media releaseContext]; } - (QTTimeRange)mapping { return mapping; } - (void)seek:(QTTime)time { if([self isInclude:time]){ QTTime innerTime = QTTimeDecrement(time, mapping.time); // レイヤー内相対時間へ変換 [media setCurrentTime:QTTimeIncrement(innerTime, offset)]; } else { [media setCurrentTime:offset]; } } // for Property Table - (void)createPropertyTableDataSource:(NSMutableArray*)t_effects property:(NSMutableArray*)t_propertyNames value:(NSMutableArray*)t_valueNames { NSMutableDictionary* params; NSArray* arr; NSString* paramName, *effectName; NSDictionary* dict; [t_propertyNames addObject:@"Position X"]; [t_effects addObject:self]; [t_valueNames addObject:@""]; [t_propertyNames addObject:@"Position Y"]; [t_effects addObject:self]; [t_valueNames addObject:@""]; int i, size = [effects count]; for(i = 0; i < size; i++){ params = [[effects objectAtIndex:i] getParamDictionary]; arr = [params allKeys]; arr = [arr sortedArrayUsingSelector:@selector(compare:)]; effectName = [[effects objectAtIndex:i] getName]; for(paramName in arr){ [t_propertyNames addObject:[NSString stringWithFormat:@"%@ %@", effectName, [paramName substringFromIndex:5]]]; [t_effects addObject:[effects objectAtIndex:i]]; [t_valueNames addObject:paramName]; } } } - (QTTime)convertToInnnerTime:(QTTime)globalTime { return QTTimeIncrement(QTTimeDecrement(globalTime, mapping.time), offset); } - (QTTime)plusOffsetTime:(QTTime)time { return QTTimeIncrement(time, offset); } - (void)finalize { [alayer removeObserver:self forKeyPath:@"frame"]; [super finalize]; } - (void)removePositionXKeyframe { pxKeyframe = [[ElisKeyframe alloc] init]; [pxKeyframe setValueForTime:0.0 time:QTZeroTime]; } - (void)removePositionYKerframe { pyKeyframe = [[ElisKeyframe alloc] init]; [pyKeyframe setValueForTime:0.0 time:QTZeroTime]; } - (void)removeEffect:(ElisEffect*)ef { [effects removeObject:ef]; } @end