1 // Copyright (c) 2009 Yanagi Asakura
3 // This software is provided 'as-is', without any express or implied
4 // warranty. In no event will the authors be held liable for any damages
5 // arising from the use of this software.
7 // Permission is granted to anyone to use this software for any purpose,
8 // including commercial applications, and to alter it and redistribute it
9 // freely, subject to the following restrictions:
11 // 1. The origin of this software must not be misrepresented; you must not
12 // claim that you wrote the original software. If you use this software
13 // in a product, an acknowledgment in the product documentation would be
14 // appreciated but is not required.
16 // 2. Altered source versions must be plainly marked as such, and must not be
17 // misrepresented as being the original software.
19 // 3. This notice may not be removed or altered from any source
26 // Created by 柳 on 09/09/12.
27 // Copyright 2009 __MyCompanyName__. All rights reserved.
34 static float convertQTTimeToSecond(QTTime t)
36 return (float)t.timeValue/t.timeScale;
39 @implementation ElisLayer
49 effects = [[NSMutableArray alloc] init];
50 pxKeyframe = [[ElisKeyframe alloc] init];
51 pyKeyframe = [[ElisKeyframe alloc] init];
52 [pxKeyframe setValueForTime:0.0 time:QTZeroTime];
53 [pyKeyframe setValueForTime:0.0 time:QTZeroTime];
55 originSize = NSZeroRect;
60 - (void)setMedia:(ElisMedia *)m
63 if([[m type] isEqualToString:@"sound"]){
64 volumeKeyframe = [[ElisKeyframe alloc] init];
65 [volumeKeyframe setValueForTime:0.3 time:QTZeroTime];
69 [self addEffect:@"CIOpacity"]; //デフォルトで透過度フィルタと
70 [self addEffect:@"CIAffineTransform"]; // アフィン変換フィルタはつけておく。
74 - (void)setAlayer:(CALayer *)layer
78 [layer setValue:self forKey:@"ElisLayer"];
81 [layer addObserver:self
83 options:(NSKeyValueObservingOptionNew)
86 originSize = [media size];
89 - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
94 - (void)addEffect:(NSString*)name
96 ElisEffect* e = [[ElisEffect alloc] initWithName:name];
98 [effects addObject:e];
101 // mappingとtrackNumberを変化させる。
102 - (void)changeMapping
104 CGRect frame = alayer.frame;
105 QTTime begin = QTMakeTime(frame.origin.x*DEFAULT_FPS/timeLineScale, DEFAULT_FPS);
106 QTTime d = QTMakeTime(frame.size.width*DEFAULT_FPS/timeLineScale, DEFAULT_FPS);
108 // trackNumber = floor((frame.origin.y+1)/51.0);
109 trackNumber = round((floor(frame.origin.y/51.0) * 51 + 1 + 25)/51.0);
110 mapping = QTMakeTimeRange(begin, d);
112 int i, center = frame.origin.y + frame.size.height/2;
113 for(i = 0; i < TRACK_SIZE; i++){ // これしきのことにループ回すってどういうことなの...
114 if(51.0*i+1 <= center && center <= 51.0*(i+1)+1){
121 - (void)changeOffset:(float)df
123 QTTime new_offset = QTTimeIncrement(offset, QTMakeTime(df*DEFAULT_FPS/timeLineScale, DEFAULT_FPS));
128 - (BOOL)canChangeMapping:(CGRect)rect
132 if([[media type] isEqualToString:@"image"] || [[media type] isEqualToString:@"text"] || [media isQuartz])
133 duration = QTMakeTime(60*10, 1);
135 duration = [media duration];
137 QTTime wantDuration = QTMakeTime(rect.size.width*DEFAULT_FPS/timeLineScale, DEFAULT_FPS);
138 float d = convertQTTimeToSecond(duration) - convertQTTimeToSecond(offset);
139 float wd = convertQTTimeToSecond(wantDuration);
141 return 0.5 <= wd && wd <= d;
144 - (BOOL)canChangeOffset:(float)df
146 float now_offset = convertQTTimeToSecond(offset);
147 float duration = convertQTTimeToSecond([media duration]);
150 return 0.0 <= df + now_offset && df + now_offset <= duration;
153 - (BOOL)isInclude:(QTTime)time
155 float t = convertQTTimeToSecond(time);
156 float begin = convertQTTimeToSecond(mapping.time);
157 return begin <= t && t <= begin + convertQTTimeToSecond(mapping.duration);
158 // return QTTimeInTimeRange(time, mapping); // これだとマルチスレッドにできなくね?
166 - (ElisLayer*)cutAtTime:(QTTime)cutTime
168 QTTime innerCutTime = [self convertToInnnerTime:cutTime];
170 NSKeyedArchiver* corder;
171 NSKeyedUnarchiver* decoder;
172 NSMutableData* data = [NSMutableData data];
174 corder = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data];
175 [self encodeWithCoder:corder];
176 [corder finishEncoding];
178 new = [ElisLayer alloc];
179 decoder = [[NSKeyedUnarchiver alloc] initForReadingWithData:data];
180 new = [new initWithCoder:decoder];
181 [decoder finishDecoding];
183 mapping.duration = QTTimeDecrement(mapping.duration, cutTime);
184 [self setLayer:alayer];
186 [new cutBack:innerCutTime];
190 - (void)cutBack:(QTTime)time
194 mapping.duration = QTTimeDecrement(mapping.duration, time);
195 [self setLayer:alayer];
203 - (void)setPositionX:(float)x forTime:(QTTime)time
206 [pxKeyframe setValueForTime:x time:time];
208 [pxKeyframe setValueForTime:x time:QTZeroTime];
211 - (void)setPositionY:(float)y forTime:(QTTime)time
214 [pyKeyframe setValueForTime:y time:time];
216 [pyKeyframe setValueForTime:y time:QTZeroTime];
219 - (CIImage*)getEffectedImage:(CVTimeStamp*)timeStamp forTime:(QTTime)time
221 QTTime innerTime = QTTimeDecrement(time, mapping.time);
224 image = [media getFrameForTime:timeStamp];
226 [media setCurrentTime:QTTimeIncrement(innerTime, offset)];
227 image = [media getFrameForTime:nil];
230 [media setVolume:[volumeKeyframe getValueForTime:QTTimeIncrement(innerTime, offset)]];
234 return [self applyEffects:image forTime:QTTimeIncrement(innerTime, offset)];
237 - (CIImage*)getEffectedImageWithoutStamp:(QTTime)time
239 QTTime innerTime = QTTimeDecrement(time, mapping.time);
240 [media setCurrentTime:QTTimeIncrement(innerTime, offset)];
241 CIImage* image = [media getFrameForTime:nil];
243 [media setVolume:[volumeKeyframe getValueForTime:QTTimeIncrement(innerTime, offset)]];
247 return [self applyEffects:image forTime:QTTimeIncrement(innerTime, offset)];
250 - (CIImage*)applyEffects:(CIImage*)image forTime:(QTTime)time
252 int i, size = [effects count];
255 for(i = 0; i < size; i++){
256 ef = [effects objectAtIndex:i];
257 [ef setInputImage:image];
258 image = [ef getImage:time];
264 - (NSPoint)getPositionForTime:(QTTime)time
266 float x = [pxKeyframe getValueForTime:time];
267 float y = [pyKeyframe getValueForTime:time];
269 return NSMakePoint(x, y);
272 - (float)getVolumeForTime:(QTTime)time
274 return [volumeKeyframe getValueForTime:QTTimeIncrement(QTTimeDecrement(time, mapping.time), offset)];
277 - (float)getVolumeForInnerTime:(QTTime)time
279 return [volumeKeyframe getValueForTime:time];
292 - (void)releaseContext
294 [media releaseContext];
297 - (QTTimeRange)mapping
302 - (void)seek:(QTTime)time
304 if([self isInclude:time]){
305 QTTime innerTime = QTTimeDecrement(time, mapping.time); // レイヤー内相対時間へ変換
306 [media setCurrentTime:QTTimeIncrement(innerTime, offset)];
308 [media setCurrentTime:offset];
313 // for Property Table
314 - (void)createPropertyTableDataSource:(NSMutableArray*)t_effects
315 property:(NSMutableArray*)t_propertyNames
316 value:(NSMutableArray*)t_valueNames
318 NSMutableDictionary* params;
320 NSString* paramName, *effectName;
323 if(![[media type] isEqualToString:@"sound"]){
324 [t_propertyNames addObject:@"Position X"];
325 [t_effects addObject:self];
326 [t_valueNames addObject:@""];
327 [t_propertyNames addObject:@"Position Y"];
328 [t_effects addObject:self];
329 [t_valueNames addObject:@""];
331 int i, size = [effects count];
332 for(i = 0; i < size; i++){
333 params = [[effects objectAtIndex:i] getParamDictionary];
334 arr = [params allKeys];
335 arr = [arr sortedArrayUsingSelector:@selector(compare:)];
336 effectName = [[effects objectAtIndex:i] getName];
337 for(paramName in arr){
338 [t_propertyNames addObject:[NSString stringWithFormat:@"%@ %@", effectName, [paramName substringFromIndex:5]]];
339 [t_effects addObject:[effects objectAtIndex:i]];
340 [t_valueNames addObject:paramName];
344 [t_propertyNames addObject:@"Volume"];
345 [t_effects addObject:self];
346 [t_valueNames addObject:@""];
350 - (QTTime)convertToInnnerTime:(QTTime)globalTime
352 return QTTimeIncrement(QTTimeDecrement(globalTime, mapping.time), offset);
355 - (QTTime)plusOffsetTime:(QTTime)time
357 return QTTimeIncrement(time, offset);
362 [alayer removeObserver:self forKeyPath:@"frame"];
366 - (void)removePositionXKeyframe
368 pxKeyframe = [[ElisKeyframe alloc] init];
369 [pxKeyframe setValueForTime:0.0 time:QTZeroTime];
372 - (void)removePositionYKerframe
374 pyKeyframe = [[ElisKeyframe alloc] init];
375 [pyKeyframe setValueForTime:0.0 time:QTZeroTime];
378 - (void)removeVolumeKeyframe
380 volumeKeyframe = [[ElisKeyframe alloc] init];
381 [volumeKeyframe setValueForTime:0.3 time:QTZeroTime];
384 - (void)removeEffect:(ElisEffect*)ef
386 [effects removeObject:ef];
389 - (void)getSoundTrack:(NSMutableArray*)soundTrack
393 t = [media getSoundTrack];
395 [(QTMovie*)[media getSoundMovie] setAttribute:[NSNumber numberWithBool:YES] forKey:QTMovieEditableAttribute];
396 qtr = [media duration];
397 mapping.time = QTMakeTime(convertQTTimeToSecond(mapping.time)*qtr.timeScale, qtr.timeScale);
398 mapping.duration = QTMakeTime(convertQTTimeToSecond(mapping.duration)*qtr.timeScale, qtr.timeScale);
399 [[media getSoundMovie] deleteSegment:QTMakeTimeRange(QTZeroTime, offset)];
400 [[media getSoundMovie] insertEmptySegmentAt:QTMakeTimeRange(QTZeroTime, mapping.time)];
401 // [[media getSoundMovie] scaleSegment:qtr newDuration:QTMakeTimeRange(offset, mapping.duration)];
402 [soundTrack addObject:[media getSoundMovie]];
403 [soundTrack addObject:t];
404 [soundTrack addObject:[NSValue valueWithQTTime:QTTimeIncrement(mapping.duration, mapping.time)]];
405 // [soundTrack addObject:[NSValue valueWithQTTime:offset]];
406 // [soundTrack addObject:[NSValue valueWithQTTimeRange:mapping]];
410 - (void)encodeWithCoder:(NSCoder*)encoder
412 [encoder encodeObject:media forKey:@"media"];
413 [encoder encodeInt:trackNumber forKey:@"trackNumber"];
414 [encoder encodeObject:QTStringFromTimeRange(mapping) forKey:@"mapping"];
415 [encoder encodeObject:QTStringFromTime(offset) forKey:@"offset"];
416 [encoder encodeObject:effects forKey:@"effects"];
417 [encoder encodeObject:pxKeyframe forKey:@"pxKeyframe"];
418 [encoder encodeObject:pyKeyframe forKey:@"pyKeyframe"];
419 [encoder encodeObject:volumeKeyframe forKey:@"volumeKeyframe"];
422 - (id)initWithCoder:(NSCoder*)coder
424 media = [coder decodeObjectForKey:@"media"];
425 trackNumber = [coder decodeIntForKey:@"trackNumber"];
426 mapping = QTTimeRangeFromString([coder decodeObjectForKey:@"mapping"]);
427 offset = QTTimeFromString([coder decodeObjectForKey:@"offset"]);
428 effects = [coder decodeObjectForKey:@"effects"];
429 pxKeyframe = [coder decodeObjectForKey:@"pxKeyframe"];
430 pyKeyframe = [coder decodeObjectForKey:@"pyKeyframe"];
431 volumeKeyframe = [coder decodeObjectForKey:@"volumeKeyframe"];
436 - (void)saveToEncoder:(NSCoder*)encoder
438 [encoder encodeInt:trackNumber forKey:@"trackNumber"];
439 [encoder encodeObject:QTStringFromTimeRange(mapping) forKey:@"mapping"];
440 [encoder encodeObject:QTStringFromTime(offset) forKey:@"offset"];
441 [encoder encodeObject:effects forKey:@"effects"];
442 [encoder encodeObject:pxKeyframe forKey:@"pxKeyframe"];
443 [encoder encodeObject:pyKeyframe forKey:@"pyKeyframe"];
444 [encoder encodeObject:volumeKeyframe forKey:@"volumeKeyframe"];
445 [encoder encodeFloat:[media speed] forKey:@"speed"];
448 - (void)loadFromDecoder:(NSCoder*)coder
450 trackNumber = [coder decodeIntForKey:@"trackNumber"];
451 mapping = QTTimeRangeFromString([coder decodeObjectForKey:@"mapping"]);
452 offset = QTTimeFromString([coder decodeObjectForKey:@"offset"]);
453 effects = [coder decodeObjectForKey:@"effects"];
454 pxKeyframe = [coder decodeObjectForKey:@"pxKeyframe"];
455 pyKeyframe = [coder decodeObjectForKey:@"pyKeyframe"];
456 [media setSpeed:[coder decodeFloatForKey:@"speed"]];
457 volumeKeyframe = [coder decodeObjectForKey:@"volumeKeyframe"];
459 [self setLayer:alayer];
462 - (void)setLayer:(CALayer*)layer
464 layer.frame = CGRectMake(convertQTTimeToSecond(mapping.time)*timeLineScale, trackNumber*51+1,
465 (/*convertQTTimeToSecond(mapping.time) + */convertQTTimeToSecond(mapping.duration))*timeLineScale, 50);
466 [self setAlayer:layer];
471 return convertQTTimeToSecond(mapping.time) + convertQTTimeToSecond(mapping.duration);
476 return [[media path] lastPathComponent];
484 - (NSString*)printName
486 if([[media type] isEqualToString:@"text"])
489 return [self getPath];
494 return originSize.size;
499 return [media speed];
502 - (void)setSpeed:(float)s
504 if(s < 0.01 || s > 100.0) return;
506 mapping.duration = [media duration];
507 [self setLayer:alayer];
510 - (void)setVolume:(float)v forTime:(QTTime)time
513 [volumeKeyframe setValueForTime:v time:time];
515 [volumeKeyframe setValueForTime:v time:QTZeroTime];