1 // PlaybackManager.cpp
2
3
4 #include <algorithm>
5 #include <stdio.h>
6
7 #include <Message.h>
8 #include <OS.h>
9 #include <Window.h>
10
11 #include "EventQueue.h"
12 #include "MessageEvent.h"
13 #include "PlaybackListener.h"
14
15 #include "PlaybackManager.h"
16
17
18 using namespace std;
19
20
21 //#define TRACE_NODE_MANAGER
22 #ifdef TRACE_NODE_MANAGER
23 # define TRACE(x...) printf(x)
24 # define ERROR(x...) fprintf(stderr, x)
25 #else
26 # define TRACE(x...)
27 # define ERROR(x...) fprintf(stderr, x)
28 #endif
29
30
31 void
tdebug(const char * str)32 tdebug(const char* str)
33 {
34 TRACE("[%lx, %lld] ", find_thread(NULL), system_time());
35 TRACE(str);
36 }
37
38
39 #define SUPPORT_SPEED_CHANGES 0
40
41
42 struct PlaybackManager::PlayingState {
43 int64 start_frame;
44 int64 end_frame;
45 int64 frame_count;
46 int64 first_visible_frame;
47 int64 last_visible_frame;
48 int64 max_frame_count;
49 int32 play_mode;
50 int32 loop_mode;
51 bool looping_enabled;
52 bool is_seek_request;
53 int64 current_frame; // Playlist frame
54 int64 range_index; // playing range index of current_frame
55 int64 activation_frame; // absolute video frame
56
PlayingStatePlaybackManager::PlayingState57 PlayingState()
58 {
59 }
60
PlayingStatePlaybackManager::PlayingState61 PlayingState(const PlayingState& other)
62 :
63 start_frame(other.start_frame),
64 end_frame(other.end_frame),
65 frame_count(other.frame_count),
66 first_visible_frame(other.first_visible_frame),
67 last_visible_frame(other.last_visible_frame),
68 max_frame_count(other.max_frame_count),
69 play_mode(other.play_mode),
70 loop_mode(other.loop_mode),
71 looping_enabled(other.looping_enabled),
72 is_seek_request(false),
73 current_frame(other.current_frame),
74 range_index(other.range_index),
75 activation_frame(other.activation_frame)
76 {
77 }
78 };
79
80
81 #if SUPPORT_SPEED_CHANGES
82 struct PlaybackManager::SpeedInfo {
83 int64 activation_frame; // absolute video frame
84 bigtime_t activation_time; // performance time
85 float speed; // speed to be used for calculations,
86 // is 1.0 if not playing
87 float set_speed; // speed set by the user
88 };
89 #endif
90
91
92 // #pragma mark - PlaybackManager
93
94
PlaybackManager()95 PlaybackManager::PlaybackManager()
96 :
97 BLooper("playback manager"),
98 fStates(10),
99 fSpeeds(10),
100 fCurrentAudioTime(0),
101 fCurrentVideoTime(0),
102 fPerformanceTime(0),
103 fPerformanceTimeEvent(NULL),
104 fFrameRate(1.0),
105 fStopPlayingFrame(-1),
106 fListeners(),
107 fNoAudio(false)
108 {
109 Run();
110 }
111
112
~PlaybackManager()113 PlaybackManager::~PlaybackManager()
114 {
115 Cleanup();
116 }
117
118
119 void
Init(float frameRate,bool initPerformanceTimes,int32 loopingMode,bool loopingEnabled,float playbackSpeed,int32 playMode,int32 currentFrame)120 PlaybackManager::Init(float frameRate, bool initPerformanceTimes,
121 int32 loopingMode, bool loopingEnabled, float playbackSpeed,
122 int32 playMode, int32 currentFrame)
123 {
124 // cleanup first
125 Cleanup();
126
127 // set the new frame rate
128 fFrameRate = frameRate;
129 if (initPerformanceTimes) {
130 fCurrentAudioTime = 0;
131 fCurrentVideoTime = 0;
132 fPerformanceTime = 0;
133 }
134 fStopPlayingFrame = -1;
135
136 #if SUPPORT_SPEED_CHANGES
137 // set up the initial speed
138 SpeedInfo* speed = new SpeedInfo;
139 speed->activation_frame = 0;
140 speed->activation_time = 0;
141 speed->speed = playbackSpeed;
142 speed->set_speed = playbackSpeed;
143 _PushSpeedInfo(speed);
144 #endif
145
146 // set up the initial state
147 PlayingState* state = new PlayingState;
148 state->frame_count = Duration();
149 state->start_frame = 0;
150 state->end_frame = 0;
151 state->first_visible_frame = 0;
152 state->last_visible_frame = 0;
153 state->max_frame_count = state->frame_count;
154
155 state->play_mode = MODE_PLAYING_PAUSED_FORWARD;
156 state->loop_mode = loopingMode;
157 state->looping_enabled = loopingEnabled;
158 state->is_seek_request = false;
159 state->current_frame = currentFrame;
160 state->activation_frame = 0;
161 fStates.AddItem(state);
162
163 TRACE("initial state pushed: state count: %ld\n", fStates.CountItems());
164
165 // notify the listeners
166 NotifyPlayModeChanged(PlayMode());
167 NotifyLoopModeChanged(LoopMode());
168 NotifyLoopingEnabledChanged(IsLoopingEnabled());
169 NotifyVideoBoundsChanged(VideoBounds());
170 NotifyFPSChanged(FramesPerSecond());
171 NotifySpeedChanged(Speed());
172 NotifyCurrentFrameChanged(CurrentFrame());
173 SetPlayMode(playMode);
174 }
175
176
177 void
Cleanup()178 PlaybackManager::Cleanup()
179 {
180 if (EventQueue::Default().RemoveEvent(fPerformanceTimeEvent))
181 delete fPerformanceTimeEvent;
182 fPerformanceTimeEvent = NULL;
183 // delete states
184 for (int32 i = 0; PlayingState* state = _StateAt(i); i++)
185 delete state;
186 fStates.MakeEmpty();
187
188 #if SUPPORT_SPEED_CHANGES
189 // delete speed infos
190 for (int32 i = 0; SpeedInfo* speed = _SpeedInfoAt(i); i++)
191 delete speed;
192 fSpeeds.MakeEmpty();
193 #endif
194 }
195
196
197 void
MessageReceived(BMessage * message)198 PlaybackManager::MessageReceived(BMessage* message)
199 {
200 switch (message->what) {
201 case MSG_EVENT:
202 {
203 if (fPerformanceTimeEvent == NULL) {
204 // Stale event message. There is a natural race
205 // condition when removing the event from the queue,
206 // it may have already fired, but we have not processed
207 // the message yet. Simply ignore the event.
208 break;
209 }
210
211 bigtime_t eventTime;
212 message->FindInt64("time", &eventTime);
213 // bigtime_t now = system_time();
214 fPerformanceTimeEvent = NULL;
215
216 // SetPerformanceTime(TimeForRealTime(now));
217 SetPerformanceTime(TimeForRealTime(eventTime));
218 //TRACE("MSG_EVENT: rt: %lld, pt: %lld\n", now, fPerformanceTime);
219 //printf("MSG_EVENT: et: %lld, rt: %lld, pt: %lld\n", eventTime, now, fPerformanceTime);
220 break;
221 }
222
223 case MSG_PLAYBACK_FORCE_UPDATE:
224 {
225 int64 frame;
226 if (message->FindInt64("frame", &frame) < B_OK)
227 frame = CurrentFrame();
228 SetCurrentFrame(frame);
229 break;
230 }
231
232 case MSG_PLAYBACK_SET_RANGE:
233 {
234 int64 startFrame = _LastState()->start_frame;
235 int64 endFrame = _LastState()->end_frame;
236 message->FindInt64("start frame", &startFrame);
237 message->FindInt64("end frame", &endFrame);
238 if (startFrame != _LastState()->start_frame
239 || endFrame != _LastState()->end_frame) {
240 PlayingState* state = new PlayingState(*_LastState());
241 state->start_frame = startFrame;
242 state->end_frame = endFrame;
243 _PushState(state, true);
244 }
245 break;
246 }
247
248 case MSG_PLAYBACK_SET_VISIBLE:
249 {
250 int64 startFrame = _LastState()->first_visible_frame;
251 int64 endFrame = _LastState()->last_visible_frame;
252 message->FindInt64("start frame", &startFrame);
253 message->FindInt64("end frame", &endFrame);
254 if (startFrame != _LastState()->first_visible_frame
255 || endFrame != _LastState()->last_visible_frame) {
256 PlayingState* state = new PlayingState(*_LastState());
257 state->first_visible_frame = startFrame;
258 state->last_visible_frame = endFrame;
259 _PushState(state, true);
260 }
261 break;
262 }
263
264 case MSG_PLAYBACK_SET_LOOP_MODE:
265 {
266 int32 loopMode = _LastState()->loop_mode;
267 message->FindInt32("mode", &loopMode);
268 if (loopMode != _LastState()->loop_mode) {
269 PlayingState* state = new PlayingState(*_LastState());
270 state->loop_mode = loopMode;
271 _PushState(state, true);
272 }
273 break;
274 }
275
276 // other messages
277 default:
278 BLooper::MessageReceived(message);
279 break;
280 }
281 }
282
283 // #pragma mark - playback control
284
285
286 void
StartPlaying(bool atBeginning)287 PlaybackManager::StartPlaying(bool atBeginning)
288 {
289 TRACE("PlaybackManager::StartPlaying()\n");
290 int32 playMode = PlayMode();
291 if (playMode == MODE_PLAYING_PAUSED_FORWARD)
292 SetPlayMode(MODE_PLAYING_FORWARD, !atBeginning);
293 if (playMode == MODE_PLAYING_PAUSED_BACKWARD)
294 SetPlayMode(MODE_PLAYING_BACKWARD, !atBeginning);
295 }
296
297
298 void
StopPlaying()299 PlaybackManager::StopPlaying()
300 {
301 TRACE("PlaybackManager::StopPlaying()\n");
302 int32 playMode = PlayMode();
303 if (playMode == MODE_PLAYING_FORWARD)
304 SetPlayMode(MODE_PLAYING_PAUSED_FORWARD, true);
305 if (playMode == MODE_PLAYING_BACKWARD)
306 SetPlayMode(MODE_PLAYING_PAUSED_BACKWARD, true);
307 }
308
309
310 void
TogglePlaying(bool atBeginning)311 PlaybackManager::TogglePlaying(bool atBeginning)
312 {
313 // playmodes (paused <-> playing) are the negative of each other
314 SetPlayMode(-PlayMode(), !atBeginning);
315 }
316
317
318 void
PausePlaying()319 PlaybackManager::PausePlaying()
320 {
321 if (PlayMode() > 0)
322 TogglePlaying();
323 }
324
325
326 bool
IsPlaying() const327 PlaybackManager::IsPlaying() const
328 {
329 return (PlayMode() > 0);
330 }
331
332
333 int32
PlayMode() const334 PlaybackManager::PlayMode() const
335 {
336 if (!_LastState())
337 return MODE_PLAYING_PAUSED_FORWARD;
338 return _LastState()->play_mode;
339 }
340
341
342 int32
LoopMode() const343 PlaybackManager::LoopMode() const
344 {
345 if (!_LastState())
346 return LOOPING_ALL;
347 return _LastState()->loop_mode;
348 }
349
350
351 bool
IsLoopingEnabled() const352 PlaybackManager::IsLoopingEnabled() const
353 {
354 if (!_LastState())
355 return true;
356 return _LastState()->looping_enabled;
357 }
358
359
360 int64
CurrentFrame() const361 PlaybackManager::CurrentFrame() const
362 {
363 return PlaylistFrameAtFrame(FrameForTime(fPerformanceTime));
364 }
365
366
367 float
Speed() const368 PlaybackManager::Speed() const
369 {
370 #if SUPPORT_SPEED_CHANGES
371 if (!_LastState())
372 return 1.0;
373 return _LastSpeedInfo()->set_speed;
374 #else
375 return 1.0;
376 #endif
377 }
378
379
380 void
SetFramesPerSecond(float framesPerSecond)381 PlaybackManager::SetFramesPerSecond(float framesPerSecond)
382 {
383 if (framesPerSecond != fFrameRate) {
384 fFrameRate = framesPerSecond;
385 NotifyFPSChanged(fFrameRate);
386 }
387 }
388
389
390 float
FramesPerSecond() const391 PlaybackManager::FramesPerSecond() const
392 {
393 return fFrameRate;
394 }
395
396
397 void
FrameDropped() const398 PlaybackManager::FrameDropped() const
399 {
400 NotifyFrameDropped();
401 }
402
403
404 void
DurationChanged()405 PlaybackManager::DurationChanged()
406 {
407 if (!_LastState())
408 return;
409 int32 frameCount = Duration();
410 if (frameCount != _LastState()->frame_count) {
411 PlayingState* state = new PlayingState(*_LastState());
412 state->frame_count = frameCount;
413 state->max_frame_count = frameCount;
414
415 _PushState(state, true);
416 }
417 }
418
419 /*! Creates a new playing state that equals the previous one aside from
420 its current frame which is set to /frame/.
421 The new state will be activated as soon as possible. */
422 void
SetCurrentFrame(int64 frame)423 PlaybackManager::SetCurrentFrame(int64 frame)
424 {
425 if (CurrentFrame() == frame) {
426 NotifySeekHandled(frame);
427 return;
428 }
429 PlayingState* newState = new PlayingState(*_LastState());
430 newState->current_frame = frame;
431 newState->is_seek_request = true;
432 _PushState(newState, false);
433 }
434
435
436 /*! Creates a new playing state that equals the previous one aside from
437 its playing mode which is set to /mode/.
438 The new state will be activated as soon as possible.
439 If /continuePlaying/ is true and the new state is a `not stopped'
440 state, playing continues at the frame the last state reaches when the
441 new state becomes active (or the next frame in the playing range).
442 If /continuePlaying/ is false, playing starts at the beginning of the
443 playing range (taking the playing direction into consideration). */
444 void
SetPlayMode(int32 mode,bool continuePlaying)445 PlaybackManager::SetPlayMode(int32 mode, bool continuePlaying)
446 {
447 //printf("PlaybackManager::SetPlayMode(%ld, %d)\n", mode, continuePlaying);
448 PlayingState* newState = new PlayingState(*_LastState());
449 newState->play_mode = mode;
450 // Jump to the playing start frame if we should not continue, where we
451 // stop.
452 if (!continuePlaying && !(_PlayingDirectionFor(newState) == 0))
453 newState->current_frame = _PlayingStartFrameFor(newState);
454 _PushState(newState, continuePlaying);
455 NotifyPlayModeChanged(mode);
456 }
457
458
459 /*! Creates a new playing state that equals the previous one aside from
460 its loop mode which is set to /mode/.
461 The new state will be activated as soon as possible.
462 If /continuePlaying/ is true and the new state is a `not stopped'
463 state, playing continues at the frame the last state reaches when the
464 new state becomes active (or the next frame in the playing range).
465 If /continuePlaying/ is false, playing starts at the beginning of the
466 playing range (taking the playing direction into consideration). */
467 void
SetLoopMode(int32 mode,bool continuePlaying)468 PlaybackManager::SetLoopMode(int32 mode, bool continuePlaying)
469 {
470 PlayingState* newState = new PlayingState(*_LastState());
471 newState->loop_mode = mode;
472 // Jump to the playing start frame if we should not continue, where we
473 // stop.
474 if (!continuePlaying && !(_PlayingDirectionFor(newState) == 0))
475 newState->current_frame = _PlayingStartFrameFor(newState);
476 _PushState(newState, continuePlaying);
477 NotifyLoopModeChanged(mode);
478 }
479
480
481 /* Creates a new playing state that equals the previous one aside from
482 its looping enabled flag which is set to /enabled/.
483 The new state will be activated as soon as possible.
484 If /continuePlaying/ is true and the new state is a `not stopped'
485 state, playing continues at the frame the last state reaches when the
486 new state becomes active (or the next frame in the playing range).
487 If /continuePlaying/ is false, playing starts at the beginning of the
488 playing range (taking the playing direction into consideration). */
489 void
SetLoopingEnabled(bool enabled,bool continuePlaying)490 PlaybackManager::SetLoopingEnabled(bool enabled, bool continuePlaying)
491 {
492 PlayingState* newState = new PlayingState(*_LastState());
493 newState->looping_enabled = enabled;
494 // Jump to the playing start frame if we should not continue, where we
495 // stop.
496 if (!continuePlaying && !(_PlayingDirectionFor(newState) == 0))
497 newState->current_frame = _PlayingStartFrameFor(newState);
498 _PushState(newState, continuePlaying);
499 NotifyLoopingEnabledChanged(enabled);
500 }
501
502
503 void
SetSpeed(float speed)504 PlaybackManager::SetSpeed(float speed)
505 {
506 #if SUPPORT_SPEED_CHANGES
507 SpeedInfo* lastSpeed = _LastSpeedInfo();
508 if (speed != lastSpeed->set_speed) {
509 SpeedInfo* info = new SpeedInfo(*lastSpeed);
510 info->activation_frame = NextFrame();
511 info->set_speed = speed;
512 if (_PlayingDirectionFor(_StateAtFrame(info->activation_frame)) != 0)
513 info->speed = info->set_speed;
514 else
515 info->speed = 1.0;
516 _PushSpeedInfo(info);
517 }
518 #endif
519 }
520
521
522 // #pragma mark -
523
524
525 /*! Returns the first frame at which a new playing state could become active,
526 that is the first frame for that neither the audio nor the video producer
527 have fetched data.*/
528 int64
NextFrame() const529 PlaybackManager::NextFrame() const
530 {
531 if (fNoAudio)
532 return FrameForTime(fCurrentVideoTime - 1) + 1;
533
534 return FrameForTime(max((bigtime_t)fCurrentAudioTime,
535 (bigtime_t)fCurrentVideoTime) - 1) + 1;
536 }
537
538
539 //! Returns the Playlist frame for NextFrame().
540 int64
NextPlaylistFrame() const541 PlaybackManager::NextPlaylistFrame() const
542 {
543 return PlaylistFrameAtFrame(NextFrame());
544 }
545
546
547 int64
FirstPlaybackRangeFrame()548 PlaybackManager::FirstPlaybackRangeFrame()
549 {
550 PlayingState* state = _StateAtFrame(CurrentFrame());
551 switch (state->loop_mode) {
552 case LOOPING_RANGE:
553 return state->start_frame;
554 case LOOPING_SELECTION:
555 // TODO: ...
556 return 0;
557 case LOOPING_VISIBLE:
558 return state->first_visible_frame;
559
560 case LOOPING_ALL:
561 default:
562 return 0;
563 }
564 }
565
566
567 int64
LastPlaybackRangeFrame()568 PlaybackManager::LastPlaybackRangeFrame()
569 {
570 PlayingState* state = _StateAtFrame(CurrentFrame());
571 switch (state->loop_mode) {
572 case LOOPING_RANGE:
573 return state->end_frame;
574 case LOOPING_SELECTION:
575 // TODO: ...
576 return state->frame_count - 1;
577 case LOOPING_VISIBLE:
578 return state->last_visible_frame;
579
580 case LOOPING_ALL:
581 default:
582 return state->frame_count - 1;
583 }
584 }
585
586
587 // #pragma mark -
588
589
590 int64
StartFrameAtFrame(int64 frame)591 PlaybackManager::StartFrameAtFrame(int64 frame)
592 {
593 return _StateAtFrame(frame)->start_frame;
594 }
595
596
597 int64
StartFrameAtTime(bigtime_t time)598 PlaybackManager::StartFrameAtTime(bigtime_t time)
599 {
600 return _StateAtTime(time)->start_frame;
601 }
602
603
604 int64
EndFrameAtFrame(int64 frame)605 PlaybackManager::EndFrameAtFrame(int64 frame)
606 {
607 return _StateAtTime(frame)->end_frame;
608 }
609
610
611 int64
EndFrameAtTime(bigtime_t time)612 PlaybackManager::EndFrameAtTime(bigtime_t time)
613 {
614 return _StateAtTime(time)->end_frame;
615 }
616
617
618 int64
FrameCountAtFrame(int64 frame)619 PlaybackManager::FrameCountAtFrame(int64 frame)
620 {
621 return _StateAtTime(frame)->frame_count;
622 }
623
624
625 int64
FrameCountAtTime(bigtime_t time)626 PlaybackManager::FrameCountAtTime(bigtime_t time)
627 {
628 return _StateAtTime(time)->frame_count;
629 }
630
631
632 int32
PlayModeAtFrame(int64 frame)633 PlaybackManager::PlayModeAtFrame(int64 frame)
634 {
635 return _StateAtTime(frame)->play_mode;
636 }
637
638
639 int32
PlayModeAtTime(bigtime_t time)640 PlaybackManager::PlayModeAtTime(bigtime_t time)
641 {
642 return _StateAtTime(time)->play_mode;
643 }
644
645
646 int32
LoopModeAtFrame(int64 frame)647 PlaybackManager::LoopModeAtFrame(int64 frame)
648 {
649 return _StateAtTime(frame)->loop_mode;
650 }
651
652
653 int32
LoopModeAtTime(bigtime_t time)654 PlaybackManager::LoopModeAtTime(bigtime_t time)
655 {
656 return _StateAtTime(time)->loop_mode;
657 }
658
659
660 /*! Returns which Playlist frame should be displayed at (performance) video
661 frame /frame/. Additionally the playing direction (0, 1, -1) is returned,
662 as well as if a new playing state becomes active with this frame.
663 A new playing state is installed, if either some data directly concerning
664 the playing (play mode, loop mode, playing ranges, selection...) or the
665 Playlist has changed. */
666 int64
PlaylistFrameAtFrame(int64 frame,int32 & playingDirection,bool & newState) const667 PlaybackManager::PlaylistFrameAtFrame(int64 frame, int32& playingDirection,
668 bool& newState) const
669 {
670 //TRACE("PlaybackManager::PlaylistFrameAtFrame(%lld)\n", frame);
671 PlayingState* state = _StateAtFrame(frame);
672 newState = (state->activation_frame == frame);
673 playingDirection = _PlayingDirectionFor(state);
674 //TRACE("playing state: activation frame: %lld, current frame: %lld, dir: %ld\n",
675 //state->activation_frame, state->current_frame, state->play_mode);
676 // The first part of the index calculation is invariable for a state. We
677 // could add it to the state data.
678 int64 result = state->current_frame;
679 if (playingDirection != 0) {
680 // int64 index = _RangeFrameForFrame(state, state->current_frame)
681 int64 index = state->range_index
682 + (frame - state->activation_frame) * playingDirection;
683 result = _FrameForRangeFrame(state, index);
684 }
685 //TRACE("PlaybackManager::PlaylistFrameAtFrame() done: %lld\n", result);
686 //printf("PlaybackManager::PlaylistFrameAtFrame(%lld): %lld, direction: %ld\n",
687 // frame, result, playingDirection);
688 return result;
689 }
690
691
692 int64
PlaylistFrameAtFrame(int64 frame,int32 & playingDirection) const693 PlaybackManager::PlaylistFrameAtFrame(int64 frame, int32& playingDirection) const
694 {
695 bool newState;
696 return PlaylistFrameAtFrame(frame, playingDirection, newState);
697 }
698
699
700 int64
PlaylistFrameAtFrame(int64 frame) const701 PlaybackManager::PlaylistFrameAtFrame(int64 frame) const
702 {
703 bool newState;
704 int32 playingDirection;
705 return PlaylistFrameAtFrame(frame, playingDirection, newState);
706 }
707
708
709 /*! Returns the index of the next frame after /startFrame/ at which a
710 playing state or speed change occurs or /endFrame/, if this happens to be
711 earlier. */
712 int64
NextChangeFrame(int64 startFrame,int64 endFrame) const713 PlaybackManager::NextChangeFrame(int64 startFrame, int64 endFrame) const
714 {
715 int32 startIndex = _IndexForFrame(startFrame);
716 int32 endIndex = _IndexForFrame(endFrame);
717 if (startIndex < endIndex)
718 endFrame = _StateAt(startIndex + 1)->activation_frame;
719 #if SUPPORT_SPEED_CHANGES
720 startIndex = _SpeedInfoIndexForFrame(startFrame);
721 endIndex = _SpeedInfoIndexForFrame(endFrame);
722 if (startIndex < endIndex)
723 endFrame = _SpeedInfoAt(startIndex + 1)->activation_frame;
724 #endif
725 return endFrame;
726 }
727
728
729 /*! Returns the next time after /startTime/ at which a playing state or
730 speed change occurs or /endTime/, if this happens to be earlier. */
731 bigtime_t
NextChangeTime(bigtime_t startTime,bigtime_t endTime) const732 PlaybackManager::NextChangeTime(bigtime_t startTime, bigtime_t endTime) const
733 {
734 int32 startIndex = _IndexForTime(startTime);
735 int32 endIndex = _IndexForTime(endTime);
736 if (startIndex < endIndex)
737 endTime = TimeForFrame(_StateAt(startIndex + 1)->activation_frame);
738 #if SUPPORT_SPEED_CHANGES
739 startIndex = _SpeedInfoIndexForTime(startTime);
740 endIndex = _SpeedInfoIndexForTime(endTime);
741 if (startIndex < endIndex)
742 endTime = TimeForFrame(_SpeedInfoAt(startIndex + 1)->activation_frame);
743 #endif
744 return endTime;
745 }
746
747
748 /*! Returns a contiguous Playlist frame interval for a given frame interval.
749 The returned interval may be smaller than the supplied one. Therefore
750 the supplied /endFrame/ is adjusted.
751 The value written to /xEndFrame/ is the first frame that doesn't belong
752 to the interval. /playingDirection/ may either be -1 for backward,
753 1 for forward or 0 for not playing. */
754 void
GetPlaylistFrameInterval(int64 startFrame,int64 & endFrame,int64 & xStartFrame,int64 & xEndFrame,int32 & playingDirection) const755 PlaybackManager::GetPlaylistFrameInterval(int64 startFrame, int64& endFrame,
756 int64& xStartFrame, int64& xEndFrame, int32& playingDirection) const
757 {
758 // limit the interval to one state and speed info
759 endFrame = NextChangeFrame(startFrame, endFrame);
760 // init return values
761 xStartFrame = PlaylistFrameAtFrame(startFrame);
762 xEndFrame = xStartFrame;
763 playingDirection = _PlayingDirectionFor(_StateAtFrame(startFrame));
764 // Step through the interval and check whether the respective Playlist
765 // frames belong to the Playlist interval.
766 bool endOfInterval = false;
767 int64 intervalLength = 0;
768 while (startFrame < endFrame && !endOfInterval) {
769 intervalLength++;
770 startFrame++;
771 xEndFrame += playingDirection;
772 endOfInterval = (PlaylistFrameAtFrame(startFrame) != xEndFrame);
773 }
774 // order the interval bounds, if playing backwards
775 if (xStartFrame > xEndFrame) {
776 swap(xStartFrame, xEndFrame);
777 xStartFrame++;
778 xEndFrame++;
779 }
780 }
781
782
783 /*! The same as GetPlaylistFrameInterval() just for time instead of frame
784 intervals. Note, that /startTime/ and /endTime/ measure
785 performance times whereas /xStartTime/ and /xEndTime/ specifies an
786 Playlist time interval. In general it does not hold
787 xEndTime - xStartTime == endTime - startTime, even if playing (think
788 of a playing speed != 1.0). */
789 void
GetPlaylistTimeInterval(bigtime_t startTime,bigtime_t & endTime,bigtime_t & xStartTime,bigtime_t & xEndTime,float & playingSpeed) const790 PlaybackManager::GetPlaylistTimeInterval(bigtime_t startTime,
791 bigtime_t& endTime, bigtime_t& xStartTime, bigtime_t& xEndTime,
792 float& playingSpeed) const
793 {
794 // Get the frames that bound the given time interval. The end frame might
795 // be greater than necessary, but that doesn't harm.
796 int64 startFrame = FrameForTime(startTime);
797 int64 endFrame = FrameForTime(endTime) + 1;
798 #if SUPPORT_SPEED_CHANGES
799 SpeedInfo* info = _SpeedInfoForFrame(startFrame)->speed;
800 #endif
801 // Get the Playlist frame interval that belongs to the frame interval.
802 int64 xStartFrame;
803 int64 xEndFrame;
804 int32 playingDirection;
805 GetPlaylistFrameInterval(startFrame, endFrame, xStartFrame, xEndFrame,
806 playingDirection);
807 // Calculate the performance time interval end/length.
808 bigtime_t endTimeForFrame = TimeForFrame(endFrame);
809 endTime = min(endTime, endTimeForFrame);
810 bigtime_t intervalLength = endTime - startTime;
811
812 // Finally determine the time bounds for the Playlist interval (depending
813 // on the playing direction).
814 switch (playingDirection) {
815 // forward
816 case 1:
817 {
818 #if SUPPORT_SPEED_CHANGES
819 // TODO: The current method does not handle the times the same way.
820 // It may happen, that for the same performance time different
821 // Playlist times (within a frame) are returned when passing it
822 // one time as a start time and another time as an end time.
823 xStartTime = PlaylistTimeForFrame(xStartFrame)
824 + bigtime_t(double(startTime - TimeForFrame(startFrame))
825 * info->speed);
826 xEndTime = xStartTime
827 + bigtime_t((double)intervalLength * info->speed);
828 #else
829 xStartTime = PlaylistTimeForFrame(xStartFrame)
830 + startTime - TimeForFrame(startFrame);
831 xEndTime = xStartTime + intervalLength;
832 #endif
833 break;
834 }
835 // backward
836 case -1:
837 {
838 #if SUPPORT_SPEED_CHANGES
839 xEndTime = PlaylistTimeForFrame(xEndFrame)
840 - bigtime_t(double(startTime - TimeForFrame(startFrame))
841 * info->speed);
842 xStartTime = xEndTime
843 - bigtime_t((double)intervalLength * info->speed);
844 #else
845 xEndTime = PlaylistTimeForFrame(xEndFrame)
846 - startTime + TimeForFrame(startFrame);
847 xStartTime = xEndTime - intervalLength;
848 #endif
849 break;
850 }
851 // not playing
852 case 0:
853 default:
854 xStartTime = PlaylistTimeForFrame(xStartFrame);
855 xEndTime = xStartTime;
856 break;
857 }
858 #if SUPPORT_SPEED_CHANGES
859 playingSpeed = (float)playingDirection * info->speed;
860 #else
861 playingSpeed = (float)playingDirection;
862 #endif
863 }
864
865
866 /*! Returns the frame that is being performed at the supplied time.
867 It holds TimeForFrame(frame) <= time < TimeForFrame(frame + 1). */
868 int64
FrameForTime(bigtime_t time) const869 PlaybackManager::FrameForTime(bigtime_t time) const
870 {
871 //TRACE("PlaybackManager::FrameForTime(%lld)\n", time);
872 // In order to avoid problems caused by rounding errors, we check
873 // if for the resulting frame holds
874 // TimeForFrame(frame) <= time < TimeForFrame(frame + 1).
875 #if SUPPORT_SPEED_CHANGES
876 SpeedInfo* info = _SpeedInfoForTime(time);
877 if (!info) {
878 fprintf(stderr, "PlaybackManager::FrameForTime() - no SpeedInfo!\n");
879 return 0;
880 }
881 int64 frame = (int64)(((double)time - info->activation_time)
882 * (double)fFrameRate * info->speed / 1000000.0)
883 + info->activation_frame;
884
885 #else
886 int64 frame = (int64)((double)time * (double)fFrameRate / 1000000.0);
887 #endif
888 if (TimeForFrame(frame) > time)
889 frame--;
890 else if (TimeForFrame(frame + 1) <= time)
891 frame++;
892 //TRACE("PlaybackManager::FrameForTime() done: %lld\n", frame);
893 //printf("PlaybackManager::FrameForTime(%lld): %lld\n", time, frame);
894 return frame;
895 }
896
897
898 /*! Returns the time at which the supplied frame should be performed (started
899 to be performed). */
900 bigtime_t
TimeForFrame(int64 frame) const901 PlaybackManager::TimeForFrame(int64 frame) const
902 {
903 #if SUPPORT_SPEED_CHANGES
904 SpeedInfo* info = _SpeedInfoForFrame(frame);
905 if (!info) {
906 fprintf(stderr, "PlaybackManager::TimeForFrame() - no SpeedInfo!\n");
907 return 0;
908 }
909 return (bigtime_t)((double)(frame - info->activation_frame) * 1000000.0
910 / ((double)fFrameRate * info->speed))
911 + info->activation_time;
912 #else
913 return (bigtime_t)((double)frame * 1000000.0 / (double)fFrameRate);
914 #endif
915 }
916
917
918 /*! Returns the Playlist frame for an Playlist time.
919 It holds PlaylistTimeForFrame(frame) <= time <
920 PlaylistTimeForFrame(frame + 1). */
921 int64
PlaylistFrameForTime(bigtime_t time) const922 PlaybackManager::PlaylistFrameForTime(bigtime_t time) const
923 {
924 // In order to avoid problems caused by rounding errors, we check
925 // if for the resulting frame holds
926 // PlaylistTimeForFrame(frame) <= time < PlaylistTimeForFrame(frame + 1).
927 int64 frame = (int64)((double)time * (double)fFrameRate / 1000000.0);
928 if (TimeForFrame(frame) > time)
929 frame--;
930 else if (TimeForFrame(frame + 1) <= time)
931 frame++;
932 return frame;
933 }
934
935
936 //! Returns the Playlist start time for an Playlist frame.
937 bigtime_t
PlaylistTimeForFrame(int64 frame) const938 PlaybackManager::PlaylistTimeForFrame(int64 frame) const
939 {
940 return (bigtime_t)((double)frame * 1000000.0 / (double)fFrameRate);
941 }
942
943
944 //! To be called when done with all activities concerning audio before /time/.
945 void
SetCurrentAudioTime(bigtime_t time)946 PlaybackManager::SetCurrentAudioTime(bigtime_t time)
947 {
948 TRACE("PlaybackManager::SetCurrentAudioTime(%lld)\n", time);
949 bigtime_t lastFrameTime = _TimeForLastFrame();
950 fCurrentAudioTime = time;
951 bigtime_t newLastFrameTime = _TimeForLastFrame();
952 if (lastFrameTime != newLastFrameTime) {
953 if (fPerformanceTimeEvent == NULL) {
954 bigtime_t eventTime = RealTimeForTime(newLastFrameTime);
955 fPerformanceTimeEvent = new MessageEvent(eventTime, this);
956 EventQueue::Default().AddEvent(fPerformanceTimeEvent);
957 }
958 _CheckStopPlaying();
959 }
960 }
961
962
963 //! To be called when done with all activities concerning video before /frame/.
964 void
SetCurrentVideoFrame(int64 frame)965 PlaybackManager::SetCurrentVideoFrame(int64 frame)
966 {
967 SetCurrentVideoTime(TimeForFrame(frame));
968 }
969
970
971 //! To be called when done with all activities concerning video before /time/.
972 void
SetCurrentVideoTime(bigtime_t time)973 PlaybackManager::SetCurrentVideoTime(bigtime_t time)
974 {
975 TRACE("PlaybackManager::SetCurrentVideoTime(%lld)\n", time);
976 bigtime_t lastFrameTime = _TimeForLastFrame();
977 fCurrentVideoTime = time;
978 bigtime_t newLastFrameTime = _TimeForLastFrame();
979 if (lastFrameTime != newLastFrameTime) {
980 if (fPerformanceTimeEvent == NULL) {
981 bigtime_t eventTime = RealTimeForTime(newLastFrameTime);
982 fPerformanceTimeEvent = new MessageEvent(eventTime, this);
983 EventQueue::Default().AddEvent(fPerformanceTimeEvent);
984 }
985 _CheckStopPlaying();
986 }
987 }
988
989
990 //! To be called as soon as video frame /frame/ is being performed.
991 void
SetPerformanceFrame(int64 frame)992 PlaybackManager::SetPerformanceFrame(int64 frame)
993 {
994 SetPerformanceTime(TimeForFrame(frame));
995 }
996
997
998 /*! Similar to SetPerformanceFrame() just with a time instead of a frame
999 argument. */
1000 void
SetPerformanceTime(bigtime_t time)1001 PlaybackManager::SetPerformanceTime(bigtime_t time)
1002 {
1003 int64 oldCurrentFrame = CurrentFrame();
1004 fPerformanceTime = time;
1005 _UpdateStates();
1006 _UpdateSpeedInfos();
1007 int64 currentFrame = CurrentFrame();
1008
1009 //printf("PlaybackManager::SetPerformanceTime(%lld): %ld -> %ld\n",
1010 // time, oldCurrentFrame, currentFrame);
1011
1012 if (currentFrame != oldCurrentFrame)
1013 NotifyCurrentFrameChanged(currentFrame);
1014 }
1015
1016
1017 // #pragma mark - Listeners
1018
1019
1020 void
AddListener(PlaybackListener * listener)1021 PlaybackManager::AddListener(PlaybackListener* listener)
1022 {
1023 if (!listener)
1024 return;
1025
1026 if (!Lock())
1027 return;
1028
1029 if (!fListeners.HasItem(listener) && fListeners.AddItem(listener)) {
1030 // bring listener up2date, if we have been initialized
1031 if (_LastState()) {
1032 listener->PlayModeChanged(PlayMode());
1033 listener->LoopModeChanged(LoopMode());
1034 listener->LoopingEnabledChanged(IsLoopingEnabled());
1035 listener->VideoBoundsChanged(VideoBounds());
1036 listener->FramesPerSecondChanged(FramesPerSecond());
1037 listener->SpeedChanged(Speed());
1038 listener->CurrentFrameChanged(CurrentFrame());
1039 }
1040 }
1041
1042 Unlock();
1043 }
1044
1045
1046 void
RemoveListener(PlaybackListener * listener)1047 PlaybackManager::RemoveListener(PlaybackListener* listener)
1048 {
1049 if (listener && Lock()) {
1050 fListeners.RemoveItem(listener);
1051 Unlock();
1052 }
1053 }
1054
1055
1056 void
NotifyPlayModeChanged(int32 mode) const1057 PlaybackManager::NotifyPlayModeChanged(int32 mode) const
1058 {
1059 for (int32 i = 0;
1060 PlaybackListener* listener = (PlaybackListener*)fListeners.ItemAt(i);
1061 i++) {
1062 listener->PlayModeChanged(mode);
1063 }
1064 }
1065
1066
1067 void
NotifyLoopModeChanged(int32 mode) const1068 PlaybackManager::NotifyLoopModeChanged(int32 mode) const
1069 {
1070 for (int32 i = 0;
1071 PlaybackListener* listener = (PlaybackListener*)fListeners.ItemAt(i);
1072 i++) {
1073 listener->LoopModeChanged(mode);
1074 }
1075 }
1076
1077
1078 void
NotifyLoopingEnabledChanged(bool enabled) const1079 PlaybackManager::NotifyLoopingEnabledChanged(bool enabled) const
1080 {
1081 for (int32 i = 0;
1082 PlaybackListener* listener = (PlaybackListener*)fListeners.ItemAt(i);
1083 i++) {
1084 listener->LoopingEnabledChanged(enabled);
1085 }
1086 }
1087
1088
1089 void
NotifyVideoBoundsChanged(BRect bounds) const1090 PlaybackManager::NotifyVideoBoundsChanged(BRect bounds) const
1091 {
1092 for (int32 i = 0;
1093 PlaybackListener* listener = (PlaybackListener*)fListeners.ItemAt(i);
1094 i++) {
1095 listener->VideoBoundsChanged(bounds);
1096 }
1097 }
1098
1099
1100 void
NotifyFPSChanged(float fps) const1101 PlaybackManager::NotifyFPSChanged(float fps) const
1102 {
1103 for (int32 i = 0;
1104 PlaybackListener* listener = (PlaybackListener*)fListeners.ItemAt(i);
1105 i++) {
1106 listener->FramesPerSecondChanged(fps);
1107 }
1108 }
1109
1110
1111 void
NotifyCurrentFrameChanged(int64 frame) const1112 PlaybackManager::NotifyCurrentFrameChanged(int64 frame) const
1113 {
1114 for (int32 i = 0;
1115 PlaybackListener* listener = (PlaybackListener*)fListeners.ItemAt(i);
1116 i++) {
1117 listener->CurrentFrameChanged(frame);
1118 }
1119 }
1120
1121
1122 void
NotifySpeedChanged(float speed) const1123 PlaybackManager::NotifySpeedChanged(float speed) const
1124 {
1125 for (int32 i = 0;
1126 PlaybackListener* listener = (PlaybackListener*)fListeners.ItemAt(i);
1127 i++) {
1128 listener->SpeedChanged(speed);
1129 }
1130 }
1131
1132
1133 void
NotifyFrameDropped() const1134 PlaybackManager::NotifyFrameDropped() const
1135 {
1136 for (int32 i = 0;
1137 PlaybackListener* listener = (PlaybackListener*)fListeners.ItemAt(i);
1138 i++) {
1139 listener->FrameDropped();
1140 }
1141 }
1142
1143
1144 void
NotifyStopFrameReached() const1145 PlaybackManager::NotifyStopFrameReached() const
1146 {
1147 // not currently implemented in PlaybackListener interface
1148 }
1149
1150
1151 void
NotifySeekHandled(int64 frame) const1152 PlaybackManager::NotifySeekHandled(int64 frame) const
1153 {
1154 // not currently implemented in PlaybackListener interface
1155 }
1156
1157
1158 void
PrintState(PlayingState * state)1159 PlaybackManager::PrintState(PlayingState* state)
1160 {
1161 TRACE("state: activation frame: %lld, current frame: %lld, "
1162 "start frame: %lld, end frame: %lld, frame count: %lld, "
1163 "first visible: %lld, last visible: %lld, selection (...), "
1164 "play mode: %ld, loop mode: %ld\n",
1165 state->activation_frame,
1166 state->current_frame,
1167 state->start_frame,
1168 state->end_frame,
1169 state->frame_count,
1170 state->first_visible_frame,
1171 state->last_visible_frame,
1172 // state->selection,
1173 state->play_mode,
1174 state->loop_mode);
1175 }
1176
1177
1178 void
PrintStateAtFrame(int64 frame)1179 PlaybackManager::PrintStateAtFrame(int64 frame)
1180 {
1181 TRACE("frame %lld: ", frame);
1182 PrintState(_StateAtFrame(frame));
1183 }
1184
1185
1186 // #pragma mark -
1187
1188
1189 /*! Appends the supplied state to the list of states. If the state would
1190 become active at the same time as _LastState() the latter is removed
1191 and deleted. However, the activation time for the new state is adjusted,
1192 so that it is >= that of the last state and >= the current audio and
1193 video time. If the additional parameter /adjustCurrentFrame/ is true,
1194 the new state's current frame is tried to be set to the frame that is
1195 reached at the time the state will become active. In every case
1196 it is ensured that the current frame lies within the playing range
1197 (if playing). */
1198 void
_PushState(PlayingState * state,bool adjustCurrentFrame)1199 PlaybackManager::_PushState(PlayingState* state, bool adjustCurrentFrame)
1200 {
1201 // if (!_LastState())
1202 // debugger("PlaybackManager::_PushState() used before Init()\n");
1203
1204 TRACE("PlaybackManager::_PushState()\n");
1205 if (state == NULL)
1206 return;
1207
1208 // unset fStopPlayingFrame
1209 int64 oldStopPlayingFrame = fStopPlayingFrame;
1210 fStopPlayingFrame = -1;
1211 // get last state
1212 PlayingState* lastState = _LastState();
1213 int64 activationFrame = max(max(state->activation_frame,
1214 lastState->activation_frame),
1215 NextFrame());
1216 int64 currentFrame = 0;
1217 // remember the current frame, if necessary
1218 if (adjustCurrentFrame) {
1219 currentFrame = PlaylistFrameAtFrame(activationFrame);
1220 if (currentFrame == CurrentFrame()) {
1221 // Seems to be paused, force using the next frame
1222 currentFrame++;
1223 }
1224 }
1225 // Check whether the last state has already become active
1226 // (NOTE: We may want to keep the last state, if it is not active,
1227 // but then the new state should become active after the last one.
1228 // Thus we had to replace `NextFrame()' with `activationFrame'.)
1229 TRACE(" state activation frame: %lld, last state activation frame: %lld, "
1230 "NextFrame(): %lld, currentFrame: %lld, next currentFrame: %lld\n",
1231 state->activation_frame, lastState->activation_frame, NextFrame(),
1232 CurrentFrame(), currentFrame);
1233 if (lastState->activation_frame >= NextFrame()) {
1234 // it isn't -- remove it
1235 fStates.RemoveItem(fStates.CountItems() - 1);
1236 TRACE("deleting last \n");
1237 PrintState(lastState);
1238 _NotifySeekHandledIfNecessary(lastState);
1239 delete lastState;
1240 } else {
1241 // it is -- keep it
1242 }
1243 // adjust the new state's current frame and activation frame
1244 if (adjustCurrentFrame)
1245 state->current_frame = currentFrame;
1246 int32 playingDirection = _PlayingDirectionFor(state);
1247 if (playingDirection != 0) {
1248 state->current_frame
1249 = _NextFrameInRange(state, state->current_frame);
1250 } else {
1251 // If not playing, we check at least, if the current frame lies
1252 // within the interval [0, max_frame_count).
1253 if (state->current_frame >= state->max_frame_count)
1254 state->current_frame = state->max_frame_count - 1;
1255 if (state->current_frame < 0)
1256 state->current_frame = 0;
1257 }
1258 state->range_index = _RangeFrameForFrame(state, state->current_frame);
1259 state->activation_frame = activationFrame;
1260 fStates.AddItem(state);
1261 PrintState(state);
1262 TRACE("_PushState: state count: %ld\n", fStates.CountItems());
1263 #if SUPPORT_SPEED_CHANGES
1264 // push a new speed info
1265 SpeedInfo* speedInfo = new SpeedInfo(*_LastSpeedInfo());
1266 if (playingDirection == 0)
1267 speedInfo->speed = 1.0;
1268 else
1269 speedInfo->speed = speedInfo->set_speed;
1270 speedInfo->activation_frame = state->activation_frame;
1271 _PushSpeedInfo(speedInfo);
1272 #endif
1273 // If the new state is a playing state and looping is turned off,
1274 // determine when playing shall stop.
1275 if (playingDirection != 0 && !state->looping_enabled) {
1276 int64 startFrame, endFrame, frameCount;
1277 _GetPlayingBoundsFor(state, startFrame, endFrame, frameCount);
1278 if (playingDirection == -1)
1279 swap(startFrame, endFrame);
1280 // If we shall stop at the frame we start, set the current frame
1281 // to the beginning of the range.
1282 // We have to take care, since this state may equal the one
1283 // before (or probably differs in just one (unimportant)
1284 // parameter). This happens for instance, if the user changes the
1285 // data or start/end frame... while playing. In this case setting
1286 // the current frame to the start frame is unwanted. Therefore
1287 // we check whether the previous state was intended to stop
1288 // at the activation frame of this state.
1289 if (oldStopPlayingFrame != state->activation_frame
1290 && state->current_frame == endFrame && frameCount > 1) {
1291 state->current_frame = startFrame;
1292 state->range_index
1293 = _RangeFrameForFrame(state, state->current_frame);
1294 }
1295 if (playingDirection == 1) { // forward
1296 fStopPlayingFrame = state->activation_frame
1297 + frameCount - state->range_index - 1;
1298 } else { // backwards
1299 fStopPlayingFrame = state->activation_frame
1300 + state->range_index;
1301 }
1302 _CheckStopPlaying();
1303 }
1304 TRACE("PlaybackManager::_PushState() done\n");
1305 }
1306
1307
1308 /*! Removes and deletes all states that are obsolete, that is which stopped
1309 being active at or before the current audio and video time. */
1310 void
_UpdateStates()1311 PlaybackManager::_UpdateStates()
1312 {
1313 // int32 firstActive = min(_IndexForTime(fCurrentAudioTime),
1314 // _IndexForTime(fCurrentVideoTime));
1315 // Performance time should always be the least one.
1316 int32 firstActive = _IndexForTime(fPerformanceTime);
1317 //TRACE("firstActive: %ld, numStates: %ld\n", firstActive, fStates.CountItems());
1318 for (int32 i = 0; i < firstActive; i++) {
1319 PlayingState* state = _StateAt(i);
1320 _NotifySeekHandledIfNecessary(state);
1321 delete state;
1322 }
1323 if (firstActive > 0)
1324 {
1325 fStates.RemoveItems(0, firstActive);
1326 TRACE("_UpdateStates: states removed: %ld, state count: %ld\n",
1327 firstActive, fStates.CountItems());
1328 }
1329 _NotifySeekHandledIfNecessary(_StateAt(0));
1330 }
1331
1332
1333 /*! Returns the index of the state, that is active at frame /frame/.
1334 The index of the first frame (0) is returned, if /frame/ is even less
1335 than the frame at which this state becomes active. */
1336 int32
_IndexForFrame(int64 frame) const1337 PlaybackManager::_IndexForFrame(int64 frame) const
1338 {
1339 int32 index = 0;
1340 PlayingState* state;
1341 while (((state = _StateAt(index + 1))) && state->activation_frame <= frame)
1342 index++;
1343 return index;
1344 }
1345
1346 /*! Returns the index of the state, that is active at time /time/.
1347 The index of the first frame (0) is returned, if /time/ is even less
1348 than the time at which this state becomes active. */
1349 int32
_IndexForTime(bigtime_t time) const1350 PlaybackManager::_IndexForTime(bigtime_t time) const
1351 {
1352 return _IndexForFrame(FrameForTime(time));
1353 }
1354
1355
1356 //! Returns the state that reflects the most recent changes.
1357 PlaybackManager::PlayingState*
_LastState() const1358 PlaybackManager::_LastState() const
1359 {
1360 return _StateAt(fStates.CountItems() - 1);
1361 }
1362
1363
1364 PlaybackManager::PlayingState*
_StateAt(int32 index) const1365 PlaybackManager::_StateAt(int32 index) const
1366 {
1367 return (PlayingState*)fStates.ItemAt(index);
1368 }
1369
1370
1371 PlaybackManager::PlayingState*
_StateAtFrame(int64 frame) const1372 PlaybackManager::_StateAtFrame(int64 frame) const
1373 {
1374 return _StateAt(_IndexForFrame(frame));
1375 }
1376
1377
1378 PlaybackManager::PlayingState*
_StateAtTime(bigtime_t time) const1379 PlaybackManager::_StateAtTime(bigtime_t time) const
1380 {
1381 return _StateAt(_IndexForTime(time));
1382 }
1383
1384
1385 int32
_PlayingDirectionFor(int32 playingMode)1386 PlaybackManager::_PlayingDirectionFor(int32 playingMode)
1387 {
1388 int32 direction = 0;
1389 switch (playingMode) {
1390 case MODE_PLAYING_FORWARD:
1391 direction = 1;
1392 break;
1393 case MODE_PLAYING_BACKWARD:
1394 direction = -1;
1395 break;
1396 case MODE_PLAYING_PAUSED_FORWARD:
1397 case MODE_PLAYING_PAUSED_BACKWARD:
1398 break;
1399 }
1400 return direction;
1401 }
1402
1403
1404 int32
_PlayingDirectionFor(PlayingState * state)1405 PlaybackManager::_PlayingDirectionFor(PlayingState* state)
1406 {
1407 return _PlayingDirectionFor(state->play_mode);
1408 }
1409
1410
1411 /*! Returns the Playlist frame range that bounds the playing range of a given
1412 state.
1413 \a startFrame is the lower and \a endFrame the upper bound of the range,
1414 and \a frameCount the number of frames in the range; it is guaranteed to
1415 be >= 1, even for an empty selection. */
1416 void
_GetPlayingBoundsFor(PlayingState * state,int64 & startFrame,int64 & endFrame,int64 & frameCount)1417 PlaybackManager::_GetPlayingBoundsFor(PlayingState* state, int64& startFrame,
1418 int64& endFrame, int64& frameCount)
1419 {
1420 switch (state->loop_mode) {
1421 case LOOPING_ALL:
1422 startFrame = 0;
1423 endFrame = max(startFrame, state->frame_count - 1);
1424 frameCount = endFrame - startFrame + 1;
1425 break;
1426 case LOOPING_RANGE:
1427 startFrame = state->start_frame;
1428 endFrame = state->end_frame;
1429 frameCount = endFrame - startFrame + 1;
1430 break;
1431 // case LOOPING_SELECTION:
1432 // if (!state->selection.IsEmpty()) {
1433 // startFrame = state->selection.FirstIndex();
1434 // endFrame = state->selection.LastIndex();
1435 // frameCount = state->selection.CountIndices();
1436 //TRACE(" LOOPING_SELECTION: %lld - %lld (%lld)\n", startFrame, endFrame,
1437 //frameCount);
1438 // } else {
1439 // startFrame = state->current_frame;
1440 // endFrame = state->current_frame;
1441 // frameCount = 1;
1442 // }
1443 // break;
1444 case LOOPING_VISIBLE:
1445 startFrame = state->first_visible_frame;
1446 endFrame = state->last_visible_frame;
1447 frameCount = endFrame - startFrame + 1;
1448 break;
1449 }
1450 }
1451
1452
1453 /*! Returns the frame at which playing would start for a given playing
1454 state. If the playing mode for the supplied state specifies a stopped
1455 or undefined mode, the result is the state's current frame. */
1456 int64
_PlayingStartFrameFor(PlayingState * state)1457 PlaybackManager::_PlayingStartFrameFor(PlayingState* state)
1458 {
1459 int64 startFrame, endFrame, frameCount, frame = 0;
1460 _GetPlayingBoundsFor(state, startFrame, endFrame, frameCount);
1461 switch (_PlayingDirectionFor(state)) {
1462 case -1:
1463 frame = endFrame;
1464 break;
1465 case 1:
1466 frame = startFrame;
1467 break;
1468 default:
1469 frame = state->current_frame;
1470 break;
1471 }
1472 return frame;
1473 }
1474
1475
1476 /*! Returns the frame at which playing would end for a given playing
1477 state. If the playing mode for the supplied state specifies a stopped
1478 or undefined mode, the result is the state's current frame. */
1479 int64
_PlayingEndFrameFor(PlayingState * state)1480 PlaybackManager::_PlayingEndFrameFor(PlayingState* state)
1481 {
1482 int64 startFrame, endFrame, frameCount, frame = 0;
1483 _GetPlayingBoundsFor(state, startFrame, endFrame, frameCount);
1484 switch (_PlayingDirectionFor(state)) {
1485 case -1:
1486 frame = startFrame;
1487 break;
1488 case 1:
1489 frame = endFrame;
1490 break;
1491 default:
1492 frame = state->current_frame;
1493 break;
1494 }
1495 return frame;
1496 }
1497
1498
1499 /*! Returns the index that the supplied frame has within a playing range.
1500 If the state specifies a not-playing mode, 0 is returned. The supplied
1501 frame has to lie within the bounds of the playing range, but it doesn't
1502 need to be contained, e.g. if the range is not contiguous. In this case
1503 the index of the next frame within the range (in playing direction) is
1504 returned. */
1505 int64
_RangeFrameForFrame(PlayingState * state,int64 frame)1506 PlaybackManager::_RangeFrameForFrame(PlayingState* state, int64 frame)
1507 {
1508 TRACE("PlaybackManager::_RangeFrameForFrame(%lld)\n", frame);
1509 int64 startFrame, endFrame, frameCount;
1510 int64 index = 0;
1511 _GetPlayingBoundsFor(state, startFrame, endFrame, frameCount);
1512 TRACE(" start frame: %lld, end frame: %lld, frame count: %lld\n",
1513 startFrame, endFrame, frameCount);
1514 switch (state->loop_mode) {
1515 case LOOPING_ALL:
1516 case LOOPING_RANGE:
1517 case LOOPING_VISIBLE:
1518 index = frame - startFrame;
1519 break;
1520 }
1521 TRACE("PlaybackManager::_RangeFrameForFrame() done: %lld\n", index);
1522 return index;
1523 }
1524
1525
1526 /*! Returns the Playlist frame for a playing range index. /index/ doesn't need
1527 to be in the playing range -- it is mapped into. */
1528 int64
_FrameForRangeFrame(PlayingState * state,int64 index)1529 PlaybackManager::_FrameForRangeFrame(PlayingState* state, int64 index)
1530 {
1531 TRACE("PlaybackManager::_FrameForRangeFrame(%lld)\n", index);
1532 int64 startFrame, endFrame, frameCount;
1533 _GetPlayingBoundsFor(state, startFrame, endFrame, frameCount);
1534 TRACE(" frame range: %lld - %lld, count: %lld\n", startFrame, endFrame,
1535 frameCount);
1536 // map the index into the index interval of the playing range
1537 if (frameCount > 1)
1538 index = (index % frameCount + frameCount) % frameCount;
1539
1540 // get the frame for the index
1541 int64 frame = startFrame;
1542 switch (state->loop_mode) {
1543 case LOOPING_ALL:
1544 case LOOPING_RANGE:
1545 case LOOPING_VISIBLE:
1546 frame = startFrame + index;
1547 break;
1548 }
1549 TRACE("PlaybackManager::_FrameForRangeFrame() done: %" PRId64 "\n", frame);
1550 return frame;
1551 }
1552
1553
1554 /*! Given an arbitrary Playlist frame this function returns the next frame within
1555 the playing range for the supplied playing state. */
1556 int64
_NextFrameInRange(PlayingState * state,int64 frame)1557 PlaybackManager::_NextFrameInRange(PlayingState* state, int64 frame)
1558 {
1559 int64 newFrame = frame;
1560 int64 startFrame, endFrame, frameCount;
1561 _GetPlayingBoundsFor(state, startFrame, endFrame, frameCount);
1562 if (frame < startFrame || frame > endFrame)
1563 newFrame = _PlayingStartFrameFor(state);
1564 else {
1565 int64 index = _RangeFrameForFrame(state, frame);
1566 newFrame = _FrameForRangeFrame(state, index);
1567 if (newFrame > frame && _PlayingDirectionFor(state) == -1)
1568 newFrame = _FrameForRangeFrame(state, index - 1);
1569 }
1570 return newFrame;
1571 }
1572
1573
1574 void
_PushSpeedInfo(SpeedInfo * info)1575 PlaybackManager::_PushSpeedInfo(SpeedInfo* info)
1576 {
1577 #if SUPPORT_SPEED_CHANGES
1578 if (info == NULL)
1579 return;
1580 // check the last state
1581 if (SpeedInfo* lastSpeed = _LastSpeedInfo()) {
1582 // set the activation time
1583 info->activation_time = TimeForFrame(info->activation_frame);
1584 // Remove the last state, if it won't be activated.
1585 if (lastSpeed->activation_frame == info->activation_frame) {
1586 //fprintf(stderr, " replacing last speed info\n");
1587 fSpeeds.RemoveItem(lastSpeed);
1588 delete lastSpeed;
1589 }
1590 }
1591 fSpeeds.AddItem(info);
1592 //fprintf(stderr, " speed info pushed: activation frame: %lld, "
1593 //"activation time: %lld, speed: %f\n", info->activation_frame,
1594 //info->activation_time, info->speed);
1595 // ...
1596 #endif
1597 }
1598
1599
1600 PlaybackManager::SpeedInfo*
_LastSpeedInfo() const1601 PlaybackManager::_LastSpeedInfo() const
1602 {
1603 #if SUPPORT_SPEED_CHANGES
1604 return (SpeedInfo*)fSpeeds.ItemAt(fSpeeds.CountItems() - 1);
1605 #else
1606 return NULL;
1607 #endif
1608 }
1609
1610
1611 PlaybackManager::SpeedInfo*
_SpeedInfoAt(int32 index) const1612 PlaybackManager::_SpeedInfoAt(int32 index) const
1613 {
1614 #if SUPPORT_SPEED_CHANGES
1615 return (SpeedInfo*)fSpeeds.ItemAt(index);
1616 #else
1617 return NULL;
1618 #endif
1619 }
1620
1621
1622 int32
_SpeedInfoIndexForFrame(int64 frame) const1623 PlaybackManager::_SpeedInfoIndexForFrame(int64 frame) const
1624 {
1625 int32 index = 0;
1626 #if SUPPORT_SPEED_CHANGES
1627 SpeedInfo* info;
1628 while (((info = _SpeedInfoAt(index + 1)))
1629 && info->activation_frame <= frame) {
1630 index++;
1631 }
1632 //fprintf(stderr, "PlaybackManager::_SpeedInfoIndexForFrame(%lld): %ld\n",
1633 //frame, index);
1634 #endif
1635 return index;
1636 }
1637
1638
1639 int32
_SpeedInfoIndexForTime(bigtime_t time) const1640 PlaybackManager::_SpeedInfoIndexForTime(bigtime_t time) const
1641 {
1642 int32 index = 0;
1643 #if SUPPORT_SPEED_CHANGES
1644 SpeedInfo* info;
1645 while (((info = _SpeedInfoAt(index + 1)))
1646 && info->activation_time <= time) {
1647 index++;
1648 }
1649 //fprintf(stderr, "PlaybackManager::_SpeedInfoIndexForTime(%lld): %ld\n",
1650 //time, index);
1651 #endif
1652 return index;
1653 }
1654
1655
1656 PlaybackManager::SpeedInfo*
_SpeedInfoForFrame(int64 frame) const1657 PlaybackManager::_SpeedInfoForFrame(int64 frame) const
1658 {
1659 return _SpeedInfoAt(_SpeedInfoIndexForFrame(frame));
1660 }
1661
1662
1663 PlaybackManager::SpeedInfo*
_SpeedInfoForTime(bigtime_t time) const1664 PlaybackManager::_SpeedInfoForTime(bigtime_t time) const
1665 {
1666 return _SpeedInfoAt(_SpeedInfoIndexForTime(time));
1667 }
1668
1669
1670 void
_UpdateSpeedInfos()1671 PlaybackManager::_UpdateSpeedInfos()
1672 {
1673 #if SUPPORT_SPEED_CHANGES
1674 int32 firstActive = _SpeedInfoIndexForTime(fPerformanceTime);
1675 for (int32 i = 0; i < firstActive; i++)
1676 delete _SpeedInfoAt(i);
1677 if (firstActive > 0)
1678 fSpeeds.RemoveItems(0, firstActive);
1679 //fprintf(stderr, " speed infos 0 - %ld removed\n", firstActive);
1680 #endif
1681 }
1682
1683
1684 /*! Returns the end time for the last video frame that the video and the
1685 audio producer both have completely processed. */
1686 bigtime_t
_TimeForLastFrame() const1687 PlaybackManager::_TimeForLastFrame() const
1688 {
1689 if (fNoAudio)
1690 return TimeForFrame(FrameForTime(fCurrentVideoTime));
1691
1692 return TimeForFrame(FrameForTime(min((bigtime_t)fCurrentAudioTime,
1693 (bigtime_t)fCurrentVideoTime)));
1694 }
1695
1696
1697 /*! Returns the start time for the first video frame for which
1698 neither the video nor the audio producer have fetched data. */
1699 bigtime_t
_TimeForNextFrame() const1700 PlaybackManager::_TimeForNextFrame() const
1701 {
1702 return TimeForFrame(NextFrame());
1703 }
1704
1705
1706 void
_CheckStopPlaying()1707 PlaybackManager::_CheckStopPlaying()
1708 {
1709 //printf("_CheckStopPlaying() - %lld, next: %lld\n", fStopPlayingFrame, NextFrame());
1710 if (fStopPlayingFrame > 0 && fStopPlayingFrame <= NextFrame()) {
1711 StopPlaying();
1712 NotifyStopFrameReached();
1713 }
1714 }
1715
1716
1717 void
_NotifySeekHandledIfNecessary(PlayingState * state)1718 PlaybackManager::_NotifySeekHandledIfNecessary(PlayingState* state)
1719 {
1720 if (state->is_seek_request) {
1721 state->is_seek_request = false;
1722 NotifySeekHandled(state->current_frame);
1723 }
1724 }
1725