[New] XspfQTPlayerMovieMode を追加 ムービーを連結してから再生する
@@ -70,6 +70,7 @@ | ||
70 | 70 | #import "XspfQTValueTransformers.h" |
71 | 71 | |
72 | 72 | #import "XspfQTPlayer.h" |
73 | +#import "XspfQTPlayerMovieMode.h" | |
73 | 74 | |
74 | 75 | |
75 | 76 |
@@ -110,7 +111,7 @@ | ||
110 | 111 | { |
111 | 112 | self = [super init]; |
112 | 113 | if(self) { |
113 | - _player = [[XspfQTPlayer alloc] init]; | |
114 | + _player = [[XspfQTPlayerMovieMode alloc] init]; | |
114 | 115 | } |
115 | 116 | |
116 | 117 | return self; |
@@ -0,0 +1,31 @@ | ||
1 | +// | |
2 | +// XspfQTPlayerMovieMode.h | |
3 | +// XspfQT | |
4 | +// | |
5 | +// Created by Hori,Masaki on 2013/06/25. | |
6 | +// Copyright (c) 2013年 masakih. All rights reserved. | |
7 | +// | |
8 | + | |
9 | +#import <Foundation/Foundation.h> | |
10 | + | |
11 | +@class HMXSPFComponent; | |
12 | +@class QTMovie; | |
13 | +@class XspfQTMovieLoader; | |
14 | + | |
15 | +@interface XspfQTPlayerMovieMode : NSObject | |
16 | +{ | |
17 | + HMXSPFComponent *_playlist; | |
18 | + QTMovie *_playingMovie; | |
19 | + NSTimeInterval _playingMovieDuration; | |
20 | + | |
21 | + NSArray *durations; | |
22 | + | |
23 | + XspfQTMovieLoader *_loader; | |
24 | + BOOL _didJoin; | |
25 | +} | |
26 | + | |
27 | +@property (retain) HMXSPFComponent *playlist; | |
28 | +@property (readonly) HMXSPFComponent *trackList; | |
29 | +@property (readonly, retain) QTMovie *playingMovie; | |
30 | + | |
31 | +@end |
@@ -0,0 +1,255 @@ | ||
1 | +// | |
2 | +// XspfQTPlayerMovieMode.m | |
3 | +// XspfQT | |
4 | +// | |
5 | +// Created by Hori,Masaki on 2013/06/25. | |
6 | +// Copyright (c) 2013年 masakih. All rights reserved. | |
7 | +// | |
8 | + | |
9 | +#import "XspfQTPlayerMovieMode.h" | |
10 | + | |
11 | + | |
12 | +#import <QTKit/QTKit.h> | |
13 | + | |
14 | +#import "HMXSPFComponent.h" | |
15 | +#import "NSURL-HMExtensions.h" | |
16 | +#import "XspfQTMovieLoader.h" | |
17 | +#import "XspfQTMovieTimer.h" | |
18 | +#import "XspfQTPreference.h" | |
19 | + | |
20 | + | |
21 | +static NSString *XspfQTCurrentTrackKey = @"currentTrack"; | |
22 | + | |
23 | + | |
24 | +@interface XspfQTPlayerMovieMode () | |
25 | + | |
26 | +@property (retain) XspfQTMovieLoader *loader; | |
27 | +@property BOOL didJoin; | |
28 | + | |
29 | +@end | |
30 | + | |
31 | +@implementation XspfQTPlayerMovieMode | |
32 | +@synthesize loader = _loader; | |
33 | +@synthesize didJoin = _didJoin; | |
34 | + | |
35 | + | |
36 | +static XspfQTMovieTimer* timer = nil; | |
37 | ++ (void)initialize | |
38 | +{ | |
39 | + static BOOL isFirst = YES; | |
40 | + if(isFirst) { | |
41 | + isFirst = NO; | |
42 | + timer = [[XspfQTMovieTimer movieTimerWithFireInterval:0.5] retain]; | |
43 | + } | |
44 | +} | |
45 | + | |
46 | +- (id)init | |
47 | +{ | |
48 | + self = [super init]; | |
49 | + if(self) { | |
50 | + _loader = [[XspfQTMovieLoader loaderWithMovieURL:nil] retain]; | |
51 | + [timer put:self]; | |
52 | + } | |
53 | + | |
54 | + return self; | |
55 | +} | |
56 | + | |
57 | +- (void)dealloc | |
58 | +{ | |
59 | + [_loader release]; | |
60 | + [timer remove:self]; | |
61 | + | |
62 | + [[_playlist childAtIndex:0] removeObserver:self forKeyPath:XspfQTCurrentTrackKey]; | |
63 | + [_playlist release]; | |
64 | + | |
65 | + NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; | |
66 | + [nc removeObserver:self]; | |
67 | + [_playingMovie release]; | |
68 | + | |
69 | + [durations release]; | |
70 | + | |
71 | + [super dealloc]; | |
72 | +} | |
73 | + | |
74 | +- (void)setPlaylist:(HMXSPFComponent *)newList | |
75 | +{ | |
76 | + if(_playlist == newList) return; | |
77 | + | |
78 | + [[_playlist childAtIndex:0] removeObserver:self forKeyPath:XspfQTCurrentTrackKey]; | |
79 | + [_playlist autorelease]; | |
80 | + _playlist = [newList retain]; | |
81 | + [[_playlist childAtIndex:0] addObserver:self | |
82 | + forKeyPath:XspfQTCurrentTrackKey | |
83 | + options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld | |
84 | + context:NULL]; | |
85 | + | |
86 | + if(!newList) { | |
87 | + [timer remove:self]; | |
88 | + } | |
89 | +} | |
90 | +- (HMXSPFComponent *)playlist | |
91 | +{ | |
92 | + return _playlist; | |
93 | +} | |
94 | + | |
95 | +- (HMXSPFComponent *)trackList | |
96 | +{ | |
97 | + return [self.playlist childAtIndex:0]; | |
98 | +} | |
99 | + | |
100 | ++ (NSSet *)keyPathsForValuesAffectingPlayingMovieDuration | |
101 | +{ | |
102 | + return [NSSet setWithObject:@"playingMovie"]; | |
103 | +} | |
104 | +- (void)setPlayingMovie:(QTMovie *)newMovie | |
105 | +{ | |
106 | + NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; | |
107 | + if(_playingMovie) { | |
108 | + [nc removeObserver:self | |
109 | + name:nil | |
110 | + object:_playingMovie]; | |
111 | + } | |
112 | + | |
113 | + [_playingMovie autorelease]; | |
114 | + _playingMovie = [newMovie retain]; | |
115 | + self.playingMovieDuration = 0; | |
116 | + | |
117 | + if(_playingMovie) { | |
118 | + [nc addObserver:self | |
119 | + selector:@selector(notifee:) | |
120 | + name:QTMovieRateDidChangeNotification | |
121 | + object:_playingMovie]; | |
122 | + } | |
123 | +} | |
124 | +- (QTMovie *)playingMovie | |
125 | +{ | |
126 | + return _playingMovie; | |
127 | +} | |
128 | +- (void)setPlayingMovieDuration:(NSTimeInterval)playingMovieDuration | |
129 | +{ | |
130 | + _playingMovieDuration = playingMovieDuration; | |
131 | +} | |
132 | +- (NSTimeInterval)playingMovieDuration | |
133 | +{ | |
134 | + if(_playingMovieDuration == 0) { | |
135 | + QTTime qttime = [self.playingMovie duration]; | |
136 | + if(!QTGetTimeInterval(qttime, &_playingMovieDuration)) _playingMovieDuration = 0; | |
137 | + } | |
138 | + | |
139 | + return _playingMovieDuration; | |
140 | +} | |
141 | + | |
142 | +- (void)buildStartPositionsWithDurations:(NSArray *)aDurations | |
143 | +{ | |
144 | + QTTime time = QTZeroTime; | |
145 | + NSMutableArray *aStartPoints = [NSMutableArray array]; | |
146 | + [aStartPoints addObject:[NSValue valueWithQTTime:time]]; | |
147 | + | |
148 | + for(id value in aDurations) { | |
149 | + QTTime aTime = [value QTTimeValue]; | |
150 | + time = QTTimeIncrement(time, aTime); | |
151 | + [aStartPoints addObject:[NSValue valueWithQTTime:time]]; | |
152 | + } | |
153 | + durations = [[NSArray alloc] initWithArray:aStartPoints]; | |
154 | +} | |
155 | +- (void)joinMovie | |
156 | +{ | |
157 | + QTMovie *theMovie = [QTMovie movie]; | |
158 | + [theMovie setMovieAttributes:@{QTMovieEditableAttribute:@YES}]; | |
159 | + | |
160 | + HMXSPFComponent *trackList = self.trackList; | |
161 | + | |
162 | + NSMutableArray *aDurations = [NSMutableArray array]; | |
163 | + | |
164 | + NSArray *children = [trackList children]; | |
165 | + BOOL firstTime = YES; | |
166 | + for(HMXSPFComponent *track in children) { | |
167 | + // | |
168 | + self.loader.movieURL = [track movieLocation]; | |
169 | + [self.loader load]; | |
170 | + QTMovie *aMovie = self.loader.qtMovie; | |
171 | + | |
172 | + QTTime qttime = [aMovie duration]; | |
173 | + [aDurations addObject:[NSValue valueWithQTTime:qttime]]; | |
174 | + id t = [NSValueTransformer valueTransformerForName:@"XspfQTTimeDateTransformer"]; | |
175 | + [track setCurrentTrackDuration:[t transformedValue:[NSValue valueWithQTTime:qttime]]]; | |
176 | + | |
177 | + QTTimeRange aMovieRange = QTMakeTimeRange(QTZeroTime, [aMovie duration]); | |
178 | + if(firstTime) { | |
179 | + [aMovie setSelection:aMovieRange]; | |
180 | + [theMovie appendSelectionFromMovie:aMovie]; | |
181 | + } else { | |
182 | + QTTime insertPoint = [theMovie duration]; | |
183 | + insertPoint = QTTimeDecrement(insertPoint, QTMakeTimeWithTimeInterval(0.05)); | |
184 | + [theMovie insertSegmentOfMovie:aMovie timeRange:aMovieRange atTime:insertPoint]; | |
185 | + } | |
186 | + firstTime = NO; | |
187 | + } | |
188 | + | |
189 | + [self buildStartPositionsWithDurations:aDurations]; | |
190 | + | |
191 | + self.playingMovie = theMovie; | |
192 | +} | |
193 | + | |
194 | +- (void)moveToStartPointNuber:(id)number | |
195 | +{ | |
196 | + NSUInteger index = [[self.trackList children] indexOfObject:number]; | |
197 | + QTTime time = [[durations objectAtIndex:index] QTTimeValue]; | |
198 | + [self.playingMovie setCurrentTime:time]; | |
199 | +} | |
200 | +- (void)observeValueForKeyPath:(NSString *)keyPath | |
201 | + ofObject:(id)object | |
202 | + change:(NSDictionary *)change | |
203 | + context:(void *)context | |
204 | +{ | |
205 | + if([keyPath isEqualToString:XspfQTCurrentTrackKey]) { | |
206 | + if(self.didJoin) { | |
207 | + id number = [change objectForKey:NSKeyValueChangeNewKey]; | |
208 | + [self moveToStartPointNuber:number]; | |
209 | + [self.playingMovie play]; | |
210 | + } else { | |
211 | + self.didJoin = YES; | |
212 | + [self joinMovie]; | |
213 | + } | |
214 | + } | |
215 | +} | |
216 | + | |
217 | + | |
218 | +- (void)notifee:(id)notification | |
219 | +{ | |
220 | + HMXSPFComponent *track = self.trackList.currentTrack; | |
221 | + NSNumber *rateValue = [[notification userInfo] objectForKey:QTMovieRateDidChangeNotificationParameter]; | |
222 | + if(rateValue) { | |
223 | + float rate = [rateValue floatValue]; | |
224 | + if(rate == 0) { | |
225 | + track.isPlayed = NO; | |
226 | + [timer suspend:self]; | |
227 | + } else { | |
228 | + track.isPlayed = YES; | |
229 | + [timer resume:self]; | |
230 | + } | |
231 | + } | |
232 | +} | |
233 | + | |
234 | +// call from XspfQTMovieTimer. | |
235 | +- (void)fire | |
236 | +{ | |
237 | + | |
238 | + // not implementation | |
239 | + // TODO: Must implement | |
240 | + // 現在のdurationを取得 | |
241 | + | |
242 | + // 選択トラックを取得 | |
243 | + | |
244 | + // 選択トラックが再生中か? | |
245 | + // 再生中ならreturn | |
246 | + | |
247 | + // durationに合うトラックを取得 | |
248 | + // [[_playlist childAtIndex:0] removeObserver:self forKeyPath:XspfQTCurrentTrackKey]; | |
249 | + // [track select] | |
250 | +// [[_playlist childAtIndex:0] addObserver:self | |
251 | +// forKeyPath:XspfQTCurrentTrackKey | |
252 | +// options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld | |
253 | +// context:NULL]; | |
254 | +} | |
255 | +@end |