[mani2/cocoa] * use thread instead of timer at drawing
@@ -28,10 +28,18 @@ | ||
28 | 28 | // |
29 | 29 | |
30 | 30 | #import "AppController.h" |
31 | +#import "AppController+Private.h" | |
31 | 32 | |
32 | 33 | @implementation AppController |
33 | 34 | |
34 | -@synthesize speed, frameCount, totalFrameCount, durationString, statusString, movieFrameCount, movieTotalFrameCount; | |
35 | +@synthesize speed; | |
36 | +@synthesize frameCount; | |
37 | +@synthesize totalFrameCount; | |
38 | +@synthesize durationString; | |
39 | +@synthesize statusString; | |
40 | +@synthesize movieFrameCount; | |
41 | +@synthesize movieTotalFrameCount; | |
42 | +@synthesize isActive; | |
35 | 43 | |
36 | 44 | - (id)init |
37 | 45 | { |
@@ -42,10 +50,9 @@ | ||
42 | 50 | durationString = @"0 / 0"; |
43 | 51 | beforeInput = @""; |
44 | 52 | player = [[MMPlayer alloc] init]; |
45 | - playTimer = nil; | |
46 | 53 | error = nil; |
47 | 54 | movieTimer = nil; |
48 | - active = NO; | |
55 | + isActive = NO; | |
49 | 56 | movieFrameCount = movieTotalFrameCount = 0; |
50 | 57 | } |
51 | 58 | return self; |
@@ -55,27 +62,39 @@ | ||
55 | 62 | { |
56 | 63 | [player release]; |
57 | 64 | [beforeInput release]; |
58 | - if (playTimer != nil) { | |
59 | - [playTimer invalidate]; | |
60 | - [playTimer release]; | |
61 | - playTimer = nil; | |
62 | - } | |
63 | 65 | [super dealloc]; |
64 | 66 | } |
65 | 67 | |
66 | 68 | - (IBAction)play:(id)sender |
67 | 69 | { |
68 | - // 単純な再生機能のみを持つ | |
69 | - [self initBeforePlaying]; | |
70 | + NSString *inputtedValue = [canvasIdInput stringValue]; | |
71 | + // 前回入力したキャンバスのIDと異なる | |
72 | + if (![inputtedValue isEqualToString:beforeInput]) { | |
73 | + self.isActive = NO; | |
74 | + [beforeInput release]; | |
75 | + beforeInput = [inputtedValue retain]; | |
76 | + // 前回のキャンバスを破棄する | |
77 | + if (player != nil) | |
78 | + [player release]; | |
79 | + player = [MMPlayer playerWithSource:inputtedValue | |
80 | + error:&error]; | |
81 | + self.durationString = @"0 / 0"; | |
82 | + self.frameCount = 0; | |
83 | + if (player != nil) { | |
84 | + self.totalFrameCount = player.totalFrameCount; | |
85 | + view.size = player.size; | |
86 | + [view scale]; | |
87 | + [self start]; | |
88 | + } | |
89 | + else { | |
90 | + self.statusString = [error localizedDescription]; | |
91 | + } | |
92 | + } | |
70 | 93 | } |
71 | 94 | |
72 | 95 | - (IBAction)togglePlaying:(id)sender |
73 | 96 | { |
74 | - // 呼び出す毎に再生及び停止を切り替えることが出来る | |
75 | - if (active) | |
76 | - playTimer == nil ? [self start] : [self stop]; | |
77 | - else | |
78 | - [self initBeforePlaying]; | |
97 | + self.isActive ? [self stop] : [self start]; | |
79 | 98 | } |
80 | 99 | |
81 | 100 | - (IBAction)exportAsImage:(id)sender |
@@ -167,7 +186,7 @@ | ||
167 | 186 | NSDictionary *userInfo = [timer userInfo]; |
168 | 187 | MMPlayer *play = [userInfo objectForKey:@"player"]; |
169 | 188 | QTMovie *movie = [userInfo objectForKey:@"movie"]; |
170 | - if ([play next]) { | |
189 | + if ([play nextFrame]) { | |
171 | 190 | QTTime duration = QTMakeTime(30, 600); |
172 | 191 | AddMovieFrame(movie, duration, [userInfo objectForKey:@"attrs"], play.bitmap); |
173 | 192 | self.movieFrameCount++; |
@@ -196,113 +215,52 @@ | ||
196 | 215 | } |
197 | 216 | } |
198 | 217 | |
199 | -- (void)initBeforePlaying | |
200 | -{ | |
201 | - NSString *inputtedValue = [canvasIdInput stringValue]; | |
202 | - // 前回入力したキャンバスのIDと異なる | |
203 | - if (![inputtedValue isEqualToString:beforeInput]) { | |
204 | - [beforeInput release]; | |
205 | - beforeInput = [inputtedValue retain]; | |
206 | - // 前回のキャンバスを破棄する | |
207 | - if (player != nil) | |
208 | - [player release]; | |
209 | - player = [MMPlayer playerWithSource:inputtedValue | |
210 | - error:&error]; | |
211 | - self.durationString = @"0 / 0"; | |
212 | - self.frameCount = 0; | |
213 | - if (player != nil) { | |
214 | - self.totalFrameCount = player.totalFrameCount; | |
215 | - view.size = player.size; | |
216 | - [view scale]; | |
217 | - [self start]; | |
218 | - } | |
219 | - else { | |
220 | - self.statusString = [error localizedDescription]; | |
221 | - } | |
222 | - } | |
223 | -} | |
224 | - | |
225 | 218 | - (void)start |
226 | 219 | { |
227 | - SEL selector = @selector(render); | |
228 | - NSMethodSignature *signature = [self methodSignatureForSelector:selector]; | |
229 | - NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature]; | |
230 | - [invocation setTarget:self]; | |
231 | - [invocation setSelector:selector]; | |
232 | - playTimer = [[NSTimer scheduledTimerWithTimeInterval:kFrameRate | |
233 | - invocation:invocation | |
234 | - repeats:YES] retain]; | |
220 | + self.isActive = YES; | |
235 | 221 | self.statusString = NSLocalizedString(@"Started", @""); |
222 | + [NSThread detachNewThreadSelector:@selector(render) | |
223 | + toTarget:self | |
224 | + withObject:nil]; | |
236 | 225 | } |
237 | 226 | |
238 | 227 | - (void)stop |
239 | 228 | { |
240 | - if (playTimer != nil) { | |
241 | - [playTimer invalidate]; | |
242 | - [playTimer release]; | |
243 | - playTimer = nil; | |
229 | + self.isActive = NO; | |
230 | + if (self.frameCount == self.totalFrameCount) | |
231 | + self.statusString = NSLocalizedString(@"Finished", @""); | |
232 | + else | |
244 | 233 | self.statusString = NSLocalizedString(@"Stopped", @""); |
245 | - } | |
246 | 234 | } |
247 | 235 | |
248 | -- (BOOL)prepareRenderingWithProgress:(BOOL)showProgress | |
249 | - error:(NSError **)err | |
236 | +- (void)update | |
250 | 237 | { |
251 | - NSUInteger speedCount = self.speed; | |
252 | - while (speedCount--) { | |
253 | - if (![player next]) | |
254 | - return NO; | |
255 | - if (showProgress) { | |
256 | - self.frameCount = self.frameCount + 1; | |
257 | - self.durationString = [[NSString alloc] initWithFormat:@"%d / %d", | |
258 | - self.frameCount, self.totalFrameCount]; | |
259 | - } | |
260 | - } | |
261 | - return YES; | |
238 | + [view setNeedsDisplay:YES]; | |
262 | 239 | } |
263 | 240 | |
264 | 241 | - (void)render |
265 | 242 | { |
266 | - NSError *err = nil; | |
267 | - if ([self prepareRenderingWithProgress:YES | |
268 | - error:&err]) { | |
269 | - CGContextRef bitmap = player.bitmap; | |
270 | - view.bitmap = bitmap; | |
271 | - [view setNeedsDisplay:YES]; | |
272 | - } | |
273 | - else if (err != nil) { | |
274 | - [self stop]; | |
275 | - self.statusString = [err localizedDescription]; | |
276 | - } | |
277 | - else { | |
278 | - [self stop]; | |
279 | - self.statusString = NSLocalizedString(@"Finished", @""); | |
280 | - active = NO; | |
281 | - } | |
282 | -} | |
283 | - | |
284 | -- (void)seek:(NSUInteger)position | |
285 | -{ | |
286 | - player = [MMPlayer playerWithSource:beforeInput | |
287 | - error:&error]; | |
288 | - if (player != nil) { | |
289 | - NSUInteger swappedSpeed = self.speed; | |
290 | - self.speed = position; | |
291 | - NSError *err = nil; | |
292 | - if ([self prepareRenderingWithProgress:NO | |
293 | - error:&err]) { | |
294 | - view.bitmap = player.bitmap; | |
295 | - [view setNeedsDisplay:YES]; | |
243 | + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; | |
244 | + while (self.isActive) { | |
245 | + NSUInteger speedCount = self.speed; | |
246 | + while (speedCount--) { | |
247 | + if (![player nextFrame]) { | |
248 | + [self stop]; | |
249 | + break; | |
250 | + } | |
251 | + self.frameCount = self.frameCount + 1; | |
252 | + self.durationString = [[NSString alloc] initWithFormat:@"%d / %d", | |
253 | + self.frameCount, self.totalFrameCount]; | |
296 | 254 | } |
297 | - else if (err != nil) { | |
298 | - error = err; | |
299 | - self.statusString = [err localizedDescription]; | |
300 | - } | |
301 | - self.speed = swappedSpeed; | |
255 | + view.bitmap = player.bitmap; | |
256 | + [self performSelectorOnMainThread:@selector(update) | |
257 | + withObject:nil | |
258 | + waitUntilDone:YES]; | |
259 | + NSDate *dateToWait = [[NSDate alloc] initWithTimeIntervalSinceNow:kFrameRate]; | |
260 | + [NSThread sleepUntilDate:dateToWait]; | |
261 | + [dateToWait release]; | |
302 | 262 | } |
303 | - else { | |
304 | - self.statusString = [error localizedDescription]; | |
305 | - } | |
263 | + [pool release]; | |
306 | 264 | } |
307 | 265 | |
308 | 266 | @end |
@@ -47,10 +47,9 @@ | ||
47 | 47 | NSString *durationString; |
48 | 48 | MMPlayer *player; |
49 | 49 | NSString *statusString; |
50 | - NSTimer *playTimer; | |
51 | 50 | NSError *error; |
52 | 51 | NSString *beforeInput; |
53 | - BOOL active; | |
52 | + BOOL isActive; | |
54 | 53 | NSTimer *movieTimer; |
55 | 54 | NSUInteger movieFrameCount; |
56 | 55 | NSUInteger movieTotalFrameCount; |
@@ -60,16 +59,7 @@ | ||
60 | 59 | - (IBAction)togglePlaying:(id)sender; |
61 | 60 | - (IBAction)exportAsImage:(id)sender; |
62 | 61 | - (IBAction)exportAsMovie:(id)sender; |
63 | -- (void)initBeforePlaying; | |
64 | 62 | - (void)start; |
65 | 63 | - (void)stop; |
66 | 64 | |
67 | -@property NSUInteger speed; | |
68 | -@property NSUInteger frameCount; | |
69 | -@property NSUInteger totalFrameCount; | |
70 | -@property NSUInteger movieFrameCount; | |
71 | -@property NSUInteger movieTotalFrameCount; | |
72 | -@property(retain) NSString *durationString; | |
73 | -@property(assign) NSString *statusString; | |
74 | - | |
75 | 65 | @end |