vfs: check userland buffers before reading them.
[haiku.git] / src / apps / mediaplayer / media_node_framework / PlaybackManager.cpp
blobe9690301a6efdc8ebc542a6932164ff9c99eafd4
1 // PlaybackManager.cpp
4 #include <algorithm>
5 #include <stdio.h>
7 #include <Message.h>
8 #include <OS.h>
9 #include <Window.h>
11 #include "EventQueue.h"
12 #include "MessageEvent.h"
13 #include "PlaybackListener.h"
15 #include "PlaybackManager.h"
18 using namespace std;
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
31 void
32 tdebug(const char* str)
34 TRACE("[%lx, %lld] ", find_thread(NULL), system_time());
35 TRACE(str);
39 #define SUPPORT_SPEED_CHANGES 0
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
57 PlayingState()
61 PlayingState(const PlayingState& other)
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)
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
89 #endif
92 // #pragma mark - PlaybackManager
95 PlaybackManager::PlaybackManager()
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)
109 Run();
113 PlaybackManager::~PlaybackManager()
115 Cleanup();
119 void
120 PlaybackManager::Init(float frameRate, bool initPerformanceTimes,
121 int32 loopingMode, bool loopingEnabled, float playbackSpeed,
122 int32 playMode, int32 currentFrame)
124 // cleanup first
125 Cleanup();
127 // set the new frame rate
128 fFrameRate = frameRate;
129 if (initPerformanceTimes) {
130 fCurrentAudioTime = 0;
131 fCurrentVideoTime = 0;
132 fPerformanceTime = 0;
134 fStopPlayingFrame = -1;
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
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;
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);
163 TRACE("initial state pushed: state count: %ld\n", fStates.CountItems());
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);
177 void
178 PlaybackManager::Cleanup()
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();
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
197 void
198 PlaybackManager::MessageReceived(BMessage* message)
200 switch (message->what) {
201 case MSG_EVENT:
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;
211 bigtime_t eventTime;
212 message->FindInt64("time", &eventTime);
213 // bigtime_t now = system_time();
214 fPerformanceTimeEvent = NULL;
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;
223 case MSG_PLAYBACK_FORCE_UPDATE:
225 int64 frame;
226 if (message->FindInt64("frame", &frame) < B_OK)
227 frame = CurrentFrame();
228 SetCurrentFrame(frame);
229 break;
232 case MSG_PLAYBACK_SET_RANGE:
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);
245 break;
248 case MSG_PLAYBACK_SET_VISIBLE:
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);
261 break;
264 case MSG_PLAYBACK_SET_LOOP_MODE:
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);
273 break;
276 // other messages
277 default:
278 BLooper::MessageReceived(message);
279 break;
283 // #pragma mark - playback control
286 void
287 PlaybackManager::StartPlaying(bool atBeginning)
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);
298 void
299 PlaybackManager::StopPlaying()
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);
310 void
311 PlaybackManager::TogglePlaying(bool atBeginning)
313 // playmodes (paused <-> playing) are the negative of each other
314 SetPlayMode(-PlayMode(), !atBeginning);
318 void
319 PlaybackManager::PausePlaying()
321 if (PlayMode() > 0)
322 TogglePlaying();
326 bool
327 PlaybackManager::IsPlaying() const
329 return (PlayMode() > 0);
333 int32
334 PlaybackManager::PlayMode() const
336 if (!_LastState())
337 return MODE_PLAYING_PAUSED_FORWARD;
338 return _LastState()->play_mode;
342 int32
343 PlaybackManager::LoopMode() const
345 if (!_LastState())
346 return LOOPING_ALL;
347 return _LastState()->loop_mode;
351 bool
352 PlaybackManager::IsLoopingEnabled() const
354 if (!_LastState())
355 return true;
356 return _LastState()->looping_enabled;
360 int64
361 PlaybackManager::CurrentFrame() const
363 return PlaylistFrameAtFrame(FrameForTime(fPerformanceTime));
367 float
368 PlaybackManager::Speed() const
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
380 void
381 PlaybackManager::SetFramesPerSecond(float framesPerSecond)
383 if (framesPerSecond != fFrameRate) {
384 fFrameRate = framesPerSecond;
385 NotifyFPSChanged(fFrameRate);
390 float
391 PlaybackManager::FramesPerSecond() const
393 return fFrameRate;
397 void
398 PlaybackManager::FrameDropped() const
400 NotifyFrameDropped();
404 void
405 PlaybackManager::DurationChanged()
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;
415 _PushState(state, true);
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
423 PlaybackManager::SetCurrentFrame(int64 frame)
425 if (CurrentFrame() == frame) {
426 NotifySeekHandled(frame);
427 return;
429 PlayingState* newState = new PlayingState(*_LastState());
430 newState->current_frame = frame;
431 newState->is_seek_request = true;
432 _PushState(newState, false);
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
445 PlaybackManager::SetPlayMode(int32 mode, bool continuePlaying)
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);
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
468 PlaybackManager::SetLoopMode(int32 mode, bool continuePlaying)
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);
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
490 PlaybackManager::SetLoopingEnabled(bool enabled, bool continuePlaying)
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);
503 void
504 PlaybackManager::SetSpeed(float speed)
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);
518 #endif
522 // #pragma mark -
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
529 PlaybackManager::NextFrame() const
531 if (fNoAudio)
532 return FrameForTime(fCurrentVideoTime - 1) + 1;
534 return FrameForTime(max((bigtime_t)fCurrentAudioTime,
535 (bigtime_t)fCurrentVideoTime) - 1) + 1;
539 //! Returns the Playlist frame for NextFrame().
540 int64
541 PlaybackManager::NextPlaylistFrame() const
543 return PlaylistFrameAtFrame(NextFrame());
547 int64
548 PlaybackManager::FirstPlaybackRangeFrame()
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;
560 case LOOPING_ALL:
561 default:
562 return 0;
567 int64
568 PlaybackManager::LastPlaybackRangeFrame()
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;
580 case LOOPING_ALL:
581 default:
582 return state->frame_count - 1;
587 // #pragma mark -
590 int64
591 PlaybackManager::StartFrameAtFrame(int64 frame)
593 return _StateAtFrame(frame)->start_frame;
597 int64
598 PlaybackManager::StartFrameAtTime(bigtime_t time)
600 return _StateAtTime(time)->start_frame;
604 int64
605 PlaybackManager::EndFrameAtFrame(int64 frame)
607 return _StateAtTime(frame)->end_frame;
611 int64
612 PlaybackManager::EndFrameAtTime(bigtime_t time)
614 return _StateAtTime(time)->end_frame;
618 int64
619 PlaybackManager::FrameCountAtFrame(int64 frame)
621 return _StateAtTime(frame)->frame_count;
625 int64
626 PlaybackManager::FrameCountAtTime(bigtime_t time)
628 return _StateAtTime(time)->frame_count;
632 int32
633 PlaybackManager::PlayModeAtFrame(int64 frame)
635 return _StateAtTime(frame)->play_mode;
639 int32
640 PlaybackManager::PlayModeAtTime(bigtime_t time)
642 return _StateAtTime(time)->play_mode;
646 int32
647 PlaybackManager::LoopModeAtFrame(int64 frame)
649 return _StateAtTime(frame)->loop_mode;
653 int32
654 PlaybackManager::LoopModeAtTime(bigtime_t time)
656 return _StateAtTime(time)->loop_mode;
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
667 PlaybackManager::PlaylistFrameAtFrame(int64 frame, int32& playingDirection,
668 bool& newState) const
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);
685 //TRACE("PlaybackManager::PlaylistFrameAtFrame() done: %lld\n", result);
686 //printf("PlaybackManager::PlaylistFrameAtFrame(%lld): %lld, direction: %ld\n",
687 // frame, result, playingDirection);
688 return result;
692 int64
693 PlaybackManager::PlaylistFrameAtFrame(int64 frame, int32& playingDirection) const
695 bool newState;
696 return PlaylistFrameAtFrame(frame, playingDirection, newState);
700 int64
701 PlaybackManager::PlaylistFrameAtFrame(int64 frame) const
703 bool newState;
704 int32 playingDirection;
705 return PlaylistFrameAtFrame(frame, playingDirection, newState);
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
713 PlaybackManager::NextChangeFrame(int64 startFrame, int64 endFrame) const
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;
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
732 PlaybackManager::NextChangeTime(bigtime_t startTime, bigtime_t endTime) const
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;
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
755 PlaybackManager::GetPlaylistFrameInterval(int64 startFrame, int64& endFrame,
756 int64& xStartFrame, int64& xEndFrame, int32& playingDirection) const
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);
774 // order the interval bounds, if playing backwards
775 if (xStartFrame > xEndFrame) {
776 swap(xStartFrame, xEndFrame);
777 xStartFrame++;
778 xEndFrame++;
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
790 PlaybackManager::GetPlaylistTimeInterval(bigtime_t startTime,
791 bigtime_t& endTime, bigtime_t& xStartTime, bigtime_t& xEndTime,
792 float& playingSpeed) const
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;
812 // Finally determine the time bounds for the Playlist interval (depending
813 // on the playing direction).
814 switch (playingDirection) {
815 // forward
816 case 1:
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;
835 // backward
836 case -1:
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;
851 // not playing
852 case 0:
853 default:
854 xStartTime = PlaylistTimeForFrame(xStartFrame);
855 xEndTime = xStartTime;
856 break;
858 #if SUPPORT_SPEED_CHANGES
859 playingSpeed = (float)playingDirection * info->speed;
860 #else
861 playingSpeed = (float)playingDirection;
862 #endif
866 /*! Returns the frame that is being performed at the supplied time.
867 It holds TimeForFrame(frame) <= time < TimeForFrame(frame + 1). */
868 int64
869 PlaybackManager::FrameForTime(bigtime_t time) const
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;
881 int64 frame = (int64)(((double)time - info->activation_time)
882 * (double)fFrameRate * info->speed / 1000000.0)
883 + info->activation_frame;
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;
898 /*! Returns the time at which the supplied frame should be performed (started
899 to be performed). */
900 bigtime_t
901 PlaybackManager::TimeForFrame(int64 frame) const
903 #if SUPPORT_SPEED_CHANGES
904 SpeedInfo* info = _SpeedInfoForFrame(frame);
905 if (!info) {
906 fprintf(stderr, "PlaybackManager::TimeForFrame() - no SpeedInfo!\n");
907 return 0;
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
918 /*! Returns the Playlist frame for an Playlist time.
919 It holds PlaylistTimeForFrame(frame) <= time <
920 PlaylistTimeForFrame(frame + 1). */
921 int64
922 PlaybackManager::PlaylistFrameForTime(bigtime_t time) const
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;
936 //! Returns the Playlist start time for an Playlist frame.
937 bigtime_t
938 PlaybackManager::PlaylistTimeForFrame(int64 frame) const
940 return (bigtime_t)((double)frame * 1000000.0 / (double)fFrameRate);
944 //! To be called when done with all activities concerning audio before /time/.
945 void
946 PlaybackManager::SetCurrentAudioTime(bigtime_t time)
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);
958 _CheckStopPlaying();
963 //! To be called when done with all activities concerning video before /frame/.
964 void
965 PlaybackManager::SetCurrentVideoFrame(int64 frame)
967 SetCurrentVideoTime(TimeForFrame(frame));
971 //! To be called when done with all activities concerning video before /time/.
972 void
973 PlaybackManager::SetCurrentVideoTime(bigtime_t time)
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);
985 _CheckStopPlaying();
990 //! To be called as soon as video frame /frame/ is being performed.
991 void
992 PlaybackManager::SetPerformanceFrame(int64 frame)
994 SetPerformanceTime(TimeForFrame(frame));
998 /*! Similar to SetPerformanceFrame() just with a time instead of a frame
999 argument. */
1000 void
1001 PlaybackManager::SetPerformanceTime(bigtime_t time)
1003 int64 oldCurrentFrame = CurrentFrame();
1004 fPerformanceTime = time;
1005 _UpdateStates();
1006 _UpdateSpeedInfos();
1007 int64 currentFrame = CurrentFrame();
1009 //printf("PlaybackManager::SetPerformanceTime(%lld): %ld -> %ld\n",
1010 // time, oldCurrentFrame, currentFrame);
1012 if (currentFrame != oldCurrentFrame)
1013 NotifyCurrentFrameChanged(currentFrame);
1017 // #pragma mark - Listeners
1020 void
1021 PlaybackManager::AddListener(PlaybackListener* listener)
1023 if (!listener)
1024 return;
1026 if (!Lock())
1027 return;
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());
1042 Unlock();
1046 void
1047 PlaybackManager::RemoveListener(PlaybackListener* listener)
1049 if (listener && Lock()) {
1050 fListeners.RemoveItem(listener);
1051 Unlock();
1056 void
1057 PlaybackManager::NotifyPlayModeChanged(int32 mode) const
1059 for (int32 i = 0;
1060 PlaybackListener* listener = (PlaybackListener*)fListeners.ItemAt(i);
1061 i++) {
1062 listener->PlayModeChanged(mode);
1067 void
1068 PlaybackManager::NotifyLoopModeChanged(int32 mode) const
1070 for (int32 i = 0;
1071 PlaybackListener* listener = (PlaybackListener*)fListeners.ItemAt(i);
1072 i++) {
1073 listener->LoopModeChanged(mode);
1078 void
1079 PlaybackManager::NotifyLoopingEnabledChanged(bool enabled) const
1081 for (int32 i = 0;
1082 PlaybackListener* listener = (PlaybackListener*)fListeners.ItemAt(i);
1083 i++) {
1084 listener->LoopingEnabledChanged(enabled);
1089 void
1090 PlaybackManager::NotifyVideoBoundsChanged(BRect bounds) const
1092 for (int32 i = 0;
1093 PlaybackListener* listener = (PlaybackListener*)fListeners.ItemAt(i);
1094 i++) {
1095 listener->VideoBoundsChanged(bounds);
1100 void
1101 PlaybackManager::NotifyFPSChanged(float fps) const
1103 for (int32 i = 0;
1104 PlaybackListener* listener = (PlaybackListener*)fListeners.ItemAt(i);
1105 i++) {
1106 listener->FramesPerSecondChanged(fps);
1111 void
1112 PlaybackManager::NotifyCurrentFrameChanged(int64 frame) const
1114 for (int32 i = 0;
1115 PlaybackListener* listener = (PlaybackListener*)fListeners.ItemAt(i);
1116 i++) {
1117 listener->CurrentFrameChanged(frame);
1122 void
1123 PlaybackManager::NotifySpeedChanged(float speed) const
1125 for (int32 i = 0;
1126 PlaybackListener* listener = (PlaybackListener*)fListeners.ItemAt(i);
1127 i++) {
1128 listener->SpeedChanged(speed);
1133 void
1134 PlaybackManager::NotifyFrameDropped() const
1136 for (int32 i = 0;
1137 PlaybackListener* listener = (PlaybackListener*)fListeners.ItemAt(i);
1138 i++) {
1139 listener->FrameDropped();
1144 void
1145 PlaybackManager::NotifyStopFrameReached() const
1147 // not currently implemented in PlaybackListener interface
1151 void
1152 PlaybackManager::NotifySeekHandled(int64 frame) const
1154 // not currently implemented in PlaybackListener interface
1158 void
1159 PlaybackManager::PrintState(PlayingState* state)
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);
1178 void
1179 PlaybackManager::PrintStateAtFrame(int64 frame)
1181 TRACE("frame %lld: ", frame);
1182 PrintState(_StateAtFrame(frame));
1186 // #pragma mark -
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
1199 PlaybackManager::_PushState(PlayingState* state, bool adjustCurrentFrame)
1201 // if (!_LastState())
1202 // debugger("PlaybackManager::_PushState() used before Init()\n");
1204 TRACE("PlaybackManager::_PushState()\n");
1205 if (state == NULL)
1206 return;
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++;
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
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;
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);
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;
1302 _CheckStopPlaying();
1304 TRACE("PlaybackManager::_PushState() done\n");
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
1311 PlaybackManager::_UpdateStates()
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;
1323 if (firstActive > 0)
1325 fStates.RemoveItems(0, firstActive);
1326 TRACE("_UpdateStates: states removed: %ld, state count: %ld\n",
1327 firstActive, fStates.CountItems());
1329 _NotifySeekHandledIfNecessary(_StateAt(0));
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
1337 PlaybackManager::_IndexForFrame(int64 frame) const
1339 int32 index = 0;
1340 PlayingState* state;
1341 while (((state = _StateAt(index + 1))) && state->activation_frame <= frame)
1342 index++;
1343 return index;
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
1350 PlaybackManager::_IndexForTime(bigtime_t time) const
1352 return _IndexForFrame(FrameForTime(time));
1356 //! Returns the state that reflects the most recent changes.
1357 PlaybackManager::PlayingState*
1358 PlaybackManager::_LastState() const
1360 return _StateAt(fStates.CountItems() - 1);
1364 PlaybackManager::PlayingState*
1365 PlaybackManager::_StateAt(int32 index) const
1367 return (PlayingState*)fStates.ItemAt(index);
1371 PlaybackManager::PlayingState*
1372 PlaybackManager::_StateAtFrame(int64 frame) const
1374 return _StateAt(_IndexForFrame(frame));
1378 PlaybackManager::PlayingState*
1379 PlaybackManager::_StateAtTime(bigtime_t time) const
1381 return _StateAt(_IndexForTime(time));
1385 int32
1386 PlaybackManager::_PlayingDirectionFor(int32 playingMode)
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;
1400 return direction;
1404 int32
1405 PlaybackManager::_PlayingDirectionFor(PlayingState* state)
1407 return _PlayingDirectionFor(state->play_mode);
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
1417 PlaybackManager::_GetPlayingBoundsFor(PlayingState* state, int64& startFrame,
1418 int64& endFrame, int64& frameCount)
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;
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
1457 PlaybackManager::_PlayingStartFrameFor(PlayingState* state)
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;
1472 return frame;
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
1480 PlaybackManager::_PlayingEndFrameFor(PlayingState* state)
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;
1495 return frame;
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
1506 PlaybackManager::_RangeFrameForFrame(PlayingState* state, int64 frame)
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;
1521 TRACE("PlaybackManager::_RangeFrameForFrame() done: %lld\n", index);
1522 return index;
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
1529 PlaybackManager::_FrameForRangeFrame(PlayingState* state, int64 index)
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;
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;
1549 TRACE("PlaybackManager::_FrameForRangeFrame() done: %ld\n", frame);
1550 return frame;
1554 /*! Given an arbitrary Playlist frame this function returns the next frame within
1555 the playing range for the supplied playing state. */
1556 int64
1557 PlaybackManager::_NextFrameInRange(PlayingState* state, int64 frame)
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);
1570 return newFrame;
1574 void
1575 PlaybackManager::_PushSpeedInfo(SpeedInfo* info)
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;
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
1600 PlaybackManager::SpeedInfo*
1601 PlaybackManager::_LastSpeedInfo() const
1603 #if SUPPORT_SPEED_CHANGES
1604 return (SpeedInfo*)fSpeeds.ItemAt(fSpeeds.CountItems() - 1);
1605 #else
1606 return NULL;
1607 #endif
1611 PlaybackManager::SpeedInfo*
1612 PlaybackManager::_SpeedInfoAt(int32 index) const
1614 #if SUPPORT_SPEED_CHANGES
1615 return (SpeedInfo*)fSpeeds.ItemAt(index);
1616 #else
1617 return NULL;
1618 #endif
1622 int32
1623 PlaybackManager::_SpeedInfoIndexForFrame(int64 frame) const
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++;
1632 //fprintf(stderr, "PlaybackManager::_SpeedInfoIndexForFrame(%lld): %ld\n",
1633 //frame, index);
1634 #endif
1635 return index;
1639 int32
1640 PlaybackManager::_SpeedInfoIndexForTime(bigtime_t time) const
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++;
1649 //fprintf(stderr, "PlaybackManager::_SpeedInfoIndexForTime(%lld): %ld\n",
1650 //time, index);
1651 #endif
1652 return index;
1656 PlaybackManager::SpeedInfo*
1657 PlaybackManager::_SpeedInfoForFrame(int64 frame) const
1659 return _SpeedInfoAt(_SpeedInfoIndexForFrame(frame));
1663 PlaybackManager::SpeedInfo*
1664 PlaybackManager::_SpeedInfoForTime(bigtime_t time) const
1666 return _SpeedInfoAt(_SpeedInfoIndexForTime(time));
1670 void
1671 PlaybackManager::_UpdateSpeedInfos()
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
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
1687 PlaybackManager::_TimeForLastFrame() const
1689 if (fNoAudio)
1690 return TimeForFrame(FrameForTime(fCurrentVideoTime));
1692 return TimeForFrame(FrameForTime(min((bigtime_t)fCurrentAudioTime,
1693 (bigtime_t)fCurrentVideoTime)));
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
1700 PlaybackManager::_TimeForNextFrame() const
1702 return TimeForFrame(NextFrame());
1706 void
1707 PlaybackManager::_CheckStopPlaying()
1709 //printf("_CheckStopPlaying() - %lld, next: %lld\n", fStopPlayingFrame, NextFrame());
1710 if (fStopPlayingFrame > 0 && fStopPlayingFrame <= NextFrame()) {
1711 StopPlaying();
1712 NotifyStopFrameReached();
1717 void
1718 PlaybackManager::_NotifySeekHandledIfNecessary(PlayingState* state)
1720 if (state->is_seek_request) {
1721 state->is_seek_request = false;
1722 NotifySeekHandled(state->current_frame);