OSDN Git Service

add Text Layer
[eliscolors/main.git] / ElisLayer.m
1 //  Copyright (c) 2009 Yanagi Asakura
2 //
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.
6 //
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:
10 //
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.
15 //
16 //  2. Altered source versions must be plainly marked as such, and must not be
17 //  misrepresented as being the original software.
18 //
19 //  3. This notice may not be removed or altered from any source
20 //  distribution.
21
22 //
23 //  ElisLayer.m
24 //  Elis Colors
25 //
26 //  Created by 柳 on 09/09/12.
27 //  Copyright 2009 __MyCompanyName__. All rights reserved.
28 //
29
30 #import "ElisLayer.h"
31
32 #define TRACK_SIZE 32
33
34 static float convertQTTimeToSecond(QTTime t)
35 {
36     return (float)t.timeValue/t.timeScale;
37 }
38
39 @implementation ElisLayer
40
41 @synthesize media;
42
43 - (id)init
44 {
45     self.media = nil;
46 //    position.x = 0;
47 //    position.y = 0;
48     offset = QTZeroTime;
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];
54     
55     [self addEffect:@"CIOpacity"]; //デフォルトで透過度フィルタと
56 //    [self addEffect:@"CILanczosScaleTransform"]; // 拡大縮小フィルタと
57     [self addEffect:@"CIAffineTransform"]; // アフィン変換フィルタはつけておく。
58     
59   
60     return self;
61 }
62
63 - (void)setAlayer:(CALayer *)layer
64 {
65     alayer = layer;
66     
67     [layer setValue:self forKey:@"ElisLayer"];
68     
69     // layer.frameをバインド。
70     [layer addObserver:self 
71             forKeyPath:@"frame" 
72                options:(NSKeyValueObservingOptionNew) 
73                context:NULL];
74 }
75
76 - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
77 {
78     [self changeMapping];
79 }
80
81 - (void)addEffect:(NSString*)name
82 {
83     [effects addObject:[[ElisEffect alloc] initWithName:name]];
84 }
85
86 // mappingとtrackNumberを変化させる。
87 - (void)changeMapping
88 {
89     CGRect frame = alayer.frame;
90     QTTime begin = QTMakeTime(frame.origin.x*DEFAULT_FPS/timeLineScale, DEFAULT_FPS);
91     QTTime d = QTMakeTime(frame.size.width*DEFAULT_FPS/timeLineScale, DEFAULT_FPS);
92     
93 //    trackNumber = floor((frame.origin.y+1)/51.0);
94     trackNumber = round((floor(frame.origin.y/51.0) * 51 + 1 + 25)/51.0);
95     mapping = QTMakeTimeRange(begin, d);
96     
97     int i, center = frame.origin.y + frame.size.height/2;
98     for(i = 0; i < TRACK_SIZE; i++){ // これしきのことにループ回すってどういうことなの...
99         if(51.0*i+1 <= center && center <= 51.0*(i+1)+1){
100             trackNumber = i;
101             return;
102         }
103     }
104 }
105
106 - (void)changeOffset:(float)df
107 {
108     QTTime new_offset = QTTimeIncrement(offset, QTMakeTime(df*DEFAULT_FPS/timeLineScale, DEFAULT_FPS));
109     
110     offset = new_offset;
111 }
112
113 - (BOOL)canChangeMapping:(CGRect)rect
114 {
115     QTTime duration;
116     
117     if([[media type] isEqualToString:@"image"] || [[media type] isEqualToString:@"text"])
118         duration = QTMakeTime(60*10, 1);
119     else
120         duration = [media duration];
121     
122     QTTime wantDuration = QTMakeTime(rect.size.width*DEFAULT_FPS/timeLineScale, DEFAULT_FPS);
123     float d = convertQTTimeToSecond(duration) - convertQTTimeToSecond(offset);
124     float wd = convertQTTimeToSecond(wantDuration);
125     
126     return 0.5 <= wd && wd <= d;
127 }
128
129 - (BOOL)canChangeOffset:(float)df
130 {
131     float now_offset = convertQTTimeToSecond(offset);
132     float duration = convertQTTimeToSecond([media duration]);
133     df /= timeLineScale;
134     
135     return 0.0 <= df + now_offset && df + now_offset <= duration;
136 }
137
138 - (BOOL)isInclude:(QTTime)time
139 {
140     float t = convertQTTimeToSecond(time);
141     float begin = convertQTTimeToSecond(mapping.time);
142     return begin <= t && t <= begin + convertQTTimeToSecond(mapping.duration);
143 //    return QTTimeInTimeRange(time, mapping); // これだとマルチスレッドにできなくね?
144 }
145
146 - (int)trackNumber
147 {
148     return trackNumber;
149 }
150
151 - (void)setPositionX:(float)x forTime:(QTTime)time
152 {
153     if(recording)
154         [pxKeyframe setValueForTime:x time:time];
155     else
156         [pxKeyframe setValueForTime:x time:QTZeroTime];
157 }
158
159 - (void)setPositionY:(float)y forTime:(QTTime)time
160 {
161     if(recording)
162         [pyKeyframe setValueForTime:y time:time];
163     else 
164         [pyKeyframe setValueForTime:y time:QTZeroTime];
165 }
166
167 - (CIImage*)getEffectedImage:(CVTimeStamp*)timeStamp forTime:(QTTime)time
168 {
169     QTTime innerTime = QTTimeDecrement(time, mapping.time);
170     CIImage* image;
171     if([[media type] isEqualToString:@"sound"]) return nil;
172     if(usingStampMode){
173         image = [media getFrameForTime:timeStamp];
174     }else{
175         [media setCurrentTime:QTTimeIncrement(innerTime, offset)];
176         image = [media getFrameForTime:nil];
177     }
178     if(image == nil) return nil;
179     
180     return [self applyEffects:image forTime:QTTimeIncrement(innerTime, offset)];
181 }
182
183 - (CIImage*)getEffectedImageWithoutStamp:(QTTime)time
184 {
185     QTTime innerTime = QTTimeDecrement(time, mapping.time);
186     [media setCurrentTime:QTTimeIncrement(innerTime, offset)];
187 //    CIImage* image = [media getFrameForQTTime:QTTimeIncrement(innerTime, offset)];
188     CIImage* image = [media getFrameForTime:nil];
189     if(image == nil) return nil;
190     
191     return [self applyEffects:image forTime:QTTimeIncrement(innerTime, offset)];    
192 }
193
194 - (CIImage*)applyEffects:(CIImage*)image forTime:(QTTime)time
195 {
196     int i, size = [effects count];
197     ElisEffect* ef;
198     
199     for(i = 0; i < size; i++){
200         ef = [effects objectAtIndex:i];
201         [ef setInputImage:image];
202         image = [ef getImage:time];
203     }
204     
205     return image;
206 }    
207
208 - (NSPoint)getPositionForTime:(QTTime)time
209 {
210     float x = [pxKeyframe getValueForTime:time];
211     float y = [pyKeyframe getValueForTime:time];
212     
213     return NSMakePoint(x, y);
214 }
215
216 - (void)play
217 {
218     [media play];
219 }
220
221 - (void)stop
222 {
223     [media stop];
224 }
225
226 - (void)releaseContext
227 {
228     [media releaseContext];
229 }
230
231 - (QTTimeRange)mapping
232 {
233     return mapping;
234 }
235
236 - (void)seek:(QTTime)time
237 {
238     if([self isInclude:time]){
239         QTTime innerTime = QTTimeDecrement(time, mapping.time); // レイヤー内相対時間へ変換
240         [media setCurrentTime:QTTimeIncrement(innerTime, offset)];
241     } else {
242         [media setCurrentTime:offset];
243     }
244 }
245
246
247 // for Property Table
248 - (void)createPropertyTableDataSource:(NSMutableArray*)t_effects
249                              property:(NSMutableArray*)t_propertyNames
250                                 value:(NSMutableArray*)t_valueNames
251 {
252     NSMutableDictionary* params;
253     NSArray* arr;
254     NSString* paramName, *effectName;
255     NSDictionary* dict;
256     
257     [t_propertyNames addObject:@"Position X"];
258     [t_effects addObject:self];
259     [t_valueNames addObject:@""];
260     [t_propertyNames addObject:@"Position Y"];
261     [t_effects addObject:self];
262     [t_valueNames addObject:@""];
263     
264     int i, size = [effects count];
265     for(i = 0; i < size; i++){
266         params = [[effects objectAtIndex:i] getParamDictionary];
267         arr = [params allKeys];
268         arr = [arr sortedArrayUsingSelector:@selector(compare:)];
269         effectName = [[effects objectAtIndex:i] getName];
270         for(paramName in arr){
271             [t_propertyNames addObject:[NSString stringWithFormat:@"%@ %@", effectName, [paramName substringFromIndex:5]]];
272             [t_effects addObject:[effects objectAtIndex:i]];
273             [t_valueNames addObject:paramName];
274         }
275     }
276 }
277
278 - (QTTime)convertToInnnerTime:(QTTime)globalTime
279 {
280     return QTTimeIncrement(QTTimeDecrement(globalTime, mapping.time), offset);
281 }
282
283 - (QTTime)plusOffsetTime:(QTTime)time
284 {
285     return QTTimeIncrement(time, offset);
286 }
287
288 - (void)finalize
289 {
290     [alayer removeObserver:self forKeyPath:@"frame"];
291     [super finalize];
292 }
293
294 - (void)removePositionXKeyframe
295 {
296     pxKeyframe = [[ElisKeyframe alloc] init];
297     [pxKeyframe setValueForTime:0.0 time:QTZeroTime];
298 }
299
300 - (void)removePositionYKerframe
301 {
302     pyKeyframe = [[ElisKeyframe alloc] init];
303     [pyKeyframe setValueForTime:0.0 time:QTZeroTime];
304 }
305
306 - (void)removeEffect:(ElisEffect*)ef
307 {
308     [effects removeObject:ef];
309 }
310
311 - (void)getSoundTrack:(NSMutableArray*)soundTrack
312 {
313     QTTrack* t;
314     QTTime qtr;
315     t = [media getSoundTrack];
316     if(t){
317         [(QTMovie*)[media getSoundMovie] setAttribute:[NSNumber numberWithBool:YES] forKey:QTMovieEditableAttribute];
318         qtr = [media duration];
319         mapping.time = QTMakeTime(convertQTTimeToSecond(mapping.time)*qtr.timeScale, qtr.timeScale);
320         mapping.duration = QTMakeTime(convertQTTimeToSecond(mapping.duration)*qtr.timeScale, qtr.timeScale);
321         [[media getSoundMovie] deleteSegment:QTMakeTimeRange(QTZeroTime, offset)];
322         [[media getSoundMovie] insertEmptySegmentAt:QTMakeTimeRange(QTZeroTime, mapping.time)];
323 //        [[media getSoundMovie] scaleSegment:qtr newDuration:QTMakeTimeRange(offset, mapping.duration)];
324         [soundTrack addObject:[media getSoundMovie]];
325         [soundTrack addObject:t];
326         [soundTrack addObject:[NSValue valueWithQTTime:QTTimeIncrement(mapping.duration, mapping.time)]];
327 //        [soundTrack addObject:[NSValue valueWithQTTime:offset]];
328 //        [soundTrack addObject:[NSValue valueWithQTTimeRange:mapping]];
329     }
330 }
331
332 - (void)encodeWithCoder:(NSCoder*)encoder
333 {
334     [encoder encodeObject:media forKey:@"media"];
335     [encoder encodeInt:trackNumber forKey:@"trackNumber"];
336     [encoder encodeObject:QTStringFromTimeRange(mapping) forKey:@"mapping"];
337     [encoder encodeObject:QTStringFromTime(offset) forKey:@"offset"];
338     [encoder encodeObject:effects forKey:@"effects"];
339     [encoder encodeObject:pxKeyframe forKey:@"pxKeyframe"];
340     [encoder encodeObject:pyKeyframe forKey:@"pyKeyframe"];
341 }
342
343 - (id)initWithCoder:(NSCoder*)coder
344 {
345     media = [coder decodeObjectForKey:@"media"];
346     trackNumber = [coder decodeIntForKey:@"trackNumber"];
347     mapping = QTTimeRangeFromString([coder decodeObjectForKey:@"mapping"]);
348     offset = QTTimeFromString([coder decodeObjectForKey:@"offset"]);
349     effects = [coder decodeObjectForKey:@"effects"];
350     pxKeyframe = [coder decodeObjectForKey:@"pxKeyframe"];
351     pyKeyframe = [coder decodeObjectForKey:@"pyKeyframe"];
352     
353     return self;
354 }
355
356 - (void)saveToEncoder:(NSCoder*)encoder
357 {
358     [encoder encodeInt:trackNumber forKey:@"trackNumber"];
359     [encoder encodeObject:QTStringFromTimeRange(mapping) forKey:@"mapping"];
360     [encoder encodeObject:QTStringFromTime(offset) forKey:@"offset"];
361     [encoder encodeObject:effects forKey:@"effects"];
362     [encoder encodeObject:pxKeyframe forKey:@"pxKeyframe"];
363     [encoder encodeObject:pyKeyframe forKey:@"pyKeyframe"];
364 }
365
366 - (void)loadFromDecoder:(NSCoder*)coder
367 {
368     trackNumber = [coder decodeIntForKey:@"trackNumber"];
369     mapping = QTTimeRangeFromString([coder decodeObjectForKey:@"mapping"]);
370     offset = QTTimeFromString([coder decodeObjectForKey:@"offset"]);
371     effects = [coder decodeObjectForKey:@"effects"];
372     pxKeyframe = [coder decodeObjectForKey:@"pxKeyframe"];
373     pyKeyframe = [coder decodeObjectForKey:@"pyKeyframe"];
374     
375     [self setLayer:alayer];
376 }
377
378 - (void)setLayer:(CALayer*)layer
379 {
380     layer.frame = CGRectMake(convertQTTimeToSecond(mapping.time)*timeLineScale, trackNumber*51+1,
381                              (/*convertQTTimeToSecond(mapping.time) + */convertQTTimeToSecond(mapping.duration))*timeLineScale, 50);
382     [self setAlayer:layer];
383 }
384
385 - (float)duration
386 {
387     return convertQTTimeToSecond(mapping.time) + convertQTTimeToSecond(mapping.duration);
388 }
389
390 - (NSString*)getPath
391 {
392     return [[media path] lastPathComponent];
393 }
394
395 - (NSString*)getType
396 {
397     return [media type];
398 }
399
400 @end