11 #include "EventQueue.h"
12 #include "MessageEvent.h"
13 #include "PlaybackListener.h"
15 #include "PlaybackManager.h"
21 //#define TRACE_NODE_MANAGER
22 #ifdef TRACE_NODE_MANAGER
23 # define TRACE(x...) printf(x)
24 # define ERROR(x...) fprintf(stderr, x)
27 # define ERROR(x...) fprintf(stderr, x)
32 tdebug(const char* str
)
34 TRACE("[%lx, %lld] ", find_thread(NULL
), system_time());
39 #define SUPPORT_SPEED_CHANGES 0
42 struct PlaybackManager::PlayingState
{
46 int64 first_visible_frame
;
47 int64 last_visible_frame
;
48 int64 max_frame_count
;
53 int64 current_frame
; // Playlist frame
54 int64 range_index
; // playing range index of current_frame
55 int64 activation_frame
; // absolute video frame
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
92 // #pragma mark - PlaybackManager
95 PlaybackManager::PlaybackManager()
97 BLooper("playback manager"),
100 fCurrentAudioTime(0),
101 fCurrentVideoTime(0),
103 fPerformanceTimeEvent(NULL
),
105 fStopPlayingFrame(-1),
113 PlaybackManager::~PlaybackManager()
120 PlaybackManager::Init(float frameRate
, bool initPerformanceTimes
,
121 int32 loopingMode
, bool loopingEnabled
, float playbackSpeed
,
122 int32 playMode
, int32 currentFrame
)
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
);
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
);
178 PlaybackManager::Cleanup()
180 if (EventQueue::Default().RemoveEvent(fPerformanceTimeEvent
))
181 delete fPerformanceTimeEvent
;
182 fPerformanceTimeEvent
= NULL
;
184 for (int32 i
= 0; PlayingState
* state
= _StateAt(i
); i
++)
188 #if SUPPORT_SPEED_CHANGES
189 // delete speed infos
190 for (int32 i
= 0; SpeedInfo
* speed
= _SpeedInfoAt(i
); i
++)
198 PlaybackManager::MessageReceived(BMessage
* message
)
200 switch (message
->what
) {
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.
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);
223 case MSG_PLAYBACK_FORCE_UPDATE
:
226 if (message
->FindInt64("frame", &frame
) < B_OK
)
227 frame
= CurrentFrame();
228 SetCurrentFrame(frame
);
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);
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);
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);
278 BLooper::MessageReceived(message
);
283 // #pragma mark - playback control
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
);
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);
311 PlaybackManager::TogglePlaying(bool atBeginning
)
313 // playmodes (paused <-> playing) are the negative of each other
314 SetPlayMode(-PlayMode(), !atBeginning
);
319 PlaybackManager::PausePlaying()
327 PlaybackManager::IsPlaying() const
329 return (PlayMode() > 0);
334 PlaybackManager::PlayMode() const
337 return MODE_PLAYING_PAUSED_FORWARD
;
338 return _LastState()->play_mode
;
343 PlaybackManager::LoopMode() const
347 return _LastState()->loop_mode
;
352 PlaybackManager::IsLoopingEnabled() const
356 return _LastState()->looping_enabled
;
361 PlaybackManager::CurrentFrame() const
363 return PlaylistFrameAtFrame(FrameForTime(fPerformanceTime
));
368 PlaybackManager::Speed() const
370 #if SUPPORT_SPEED_CHANGES
373 return _LastSpeedInfo()->set_speed
;
381 PlaybackManager::SetFramesPerSecond(float framesPerSecond
)
383 if (framesPerSecond
!= fFrameRate
) {
384 fFrameRate
= framesPerSecond
;
385 NotifyFPSChanged(fFrameRate
);
391 PlaybackManager::FramesPerSecond() const
398 PlaybackManager::FrameDropped() const
400 NotifyFrameDropped();
405 PlaybackManager::DurationChanged()
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. */
423 PlaybackManager::SetCurrentFrame(int64 frame
)
425 if (CurrentFrame() == frame
) {
426 NotifySeekHandled(frame
);
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). */
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
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). */
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
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). */
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
496 if (!continuePlaying
&& !(_PlayingDirectionFor(newState
) == 0))
497 newState
->current_frame
= _PlayingStartFrameFor(newState
);
498 _PushState(newState
, continuePlaying
);
499 NotifyLoopingEnabledChanged(enabled
);
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
;
516 _PushSpeedInfo(info
);
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
529 PlaybackManager::NextFrame() const
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().
541 PlaybackManager::NextPlaylistFrame() const
543 return PlaylistFrameAtFrame(NextFrame());
548 PlaybackManager::FirstPlaybackRangeFrame()
550 PlayingState
* state
= _StateAtFrame(CurrentFrame());
551 switch (state
->loop_mode
) {
553 return state
->start_frame
;
554 case LOOPING_SELECTION
:
557 case LOOPING_VISIBLE
:
558 return state
->first_visible_frame
;
568 PlaybackManager::LastPlaybackRangeFrame()
570 PlayingState
* state
= _StateAtFrame(CurrentFrame());
571 switch (state
->loop_mode
) {
573 return state
->end_frame
;
574 case LOOPING_SELECTION
:
576 return state
->frame_count
- 1;
577 case LOOPING_VISIBLE
:
578 return state
->last_visible_frame
;
582 return state
->frame_count
- 1;
591 PlaybackManager::StartFrameAtFrame(int64 frame
)
593 return _StateAtFrame(frame
)->start_frame
;
598 PlaybackManager::StartFrameAtTime(bigtime_t time
)
600 return _StateAtTime(time
)->start_frame
;
605 PlaybackManager::EndFrameAtFrame(int64 frame
)
607 return _StateAtTime(frame
)->end_frame
;
612 PlaybackManager::EndFrameAtTime(bigtime_t time
)
614 return _StateAtTime(time
)->end_frame
;
619 PlaybackManager::FrameCountAtFrame(int64 frame
)
621 return _StateAtTime(frame
)->frame_count
;
626 PlaybackManager::FrameCountAtTime(bigtime_t time
)
628 return _StateAtTime(time
)->frame_count
;
633 PlaybackManager::PlayModeAtFrame(int64 frame
)
635 return _StateAtTime(frame
)->play_mode
;
640 PlaybackManager::PlayModeAtTime(bigtime_t time
)
642 return _StateAtTime(time
)->play_mode
;
647 PlaybackManager::LoopModeAtFrame(int64 frame
)
649 return _StateAtTime(frame
)->loop_mode
;
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. */
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);
693 PlaybackManager::PlaylistFrameAtFrame(int64 frame
, int32
& playingDirection
) const
696 return PlaylistFrameAtFrame(frame
, playingDirection
, newState
);
701 PlaybackManager::PlaylistFrameAtFrame(int64 frame
) const
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
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
;
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. */
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
);
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. */
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
) {
771 xEndFrame
+= playingDirection
;
772 endOfInterval
= (PlaylistFrameAtFrame(startFrame
) != xEndFrame
);
774 // order the interval bounds, if playing backwards
775 if (xStartFrame
> xEndFrame
) {
776 swap(xStartFrame
, 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). */
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
;
801 // Get the Playlist frame interval that belongs to the frame interval.
804 int32 playingDirection
;
805 GetPlaylistFrameInterval(startFrame
, endFrame
, xStartFrame
, xEndFrame
,
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
) {
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
))
826 xEndTime
= xStartTime
827 + bigtime_t((double)intervalLength
* info
->speed
);
829 xStartTime
= PlaylistTimeForFrame(xStartFrame
)
830 + startTime
- TimeForFrame(startFrame
);
831 xEndTime
= xStartTime
+ intervalLength
;
838 #if SUPPORT_SPEED_CHANGES
839 xEndTime
= PlaylistTimeForFrame(xEndFrame
)
840 - bigtime_t(double(startTime
- TimeForFrame(startFrame
))
842 xStartTime
= xEndTime
843 - bigtime_t((double)intervalLength
* info
->speed
);
845 xEndTime
= PlaylistTimeForFrame(xEndFrame
)
846 - startTime
+ TimeForFrame(startFrame
);
847 xStartTime
= xEndTime
- intervalLength
;
854 xStartTime
= PlaylistTimeForFrame(xStartFrame
);
855 xEndTime
= xStartTime
;
858 #if SUPPORT_SPEED_CHANGES
859 playingSpeed
= (float)playingDirection
* info
->speed
;
861 playingSpeed
= (float)playingDirection
;
866 /*! Returns the frame that is being performed at the supplied time.
867 It holds TimeForFrame(frame) <= time < TimeForFrame(frame + 1). */
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
);
878 fprintf(stderr
, "PlaybackManager::FrameForTime() - no SpeedInfo!\n");
881 int64 frame
= (int64
)(((double)time
- info
->activation_time
)
882 * (double)fFrameRate
* info
->speed
/ 1000000.0)
883 + info
->activation_frame
;
886 int64 frame
= (int64
)((double)time
* (double)fFrameRate
/ 1000000.0);
888 if (TimeForFrame(frame
) > time
)
890 else if (TimeForFrame(frame
+ 1) <= time
)
892 //TRACE("PlaybackManager::FrameForTime() done: %lld\n", frame);
893 //printf("PlaybackManager::FrameForTime(%lld): %lld\n", time, frame);
898 /*! Returns the time at which the supplied frame should be performed (started
901 PlaybackManager::TimeForFrame(int64 frame
) const
903 #if SUPPORT_SPEED_CHANGES
904 SpeedInfo
* info
= _SpeedInfoForFrame(frame
);
906 fprintf(stderr
, "PlaybackManager::TimeForFrame() - no SpeedInfo!\n");
909 return (bigtime_t
)((double)(frame
- info
->activation_frame
) * 1000000.0
910 / ((double)fFrameRate
* info
->speed
))
911 + info
->activation_time
;
913 return (bigtime_t
)((double)frame
* 1000000.0 / (double)fFrameRate
);
918 /*! Returns the Playlist frame for an Playlist time.
919 It holds PlaylistTimeForFrame(frame) <= time <
920 PlaylistTimeForFrame(frame + 1). */
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
)
930 else if (TimeForFrame(frame
+ 1) <= time
)
936 //! Returns the Playlist start time for an Playlist frame.
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/.
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
);
963 //! To be called when done with all activities concerning video before /frame/.
965 PlaybackManager::SetCurrentVideoFrame(int64 frame
)
967 SetCurrentVideoTime(TimeForFrame(frame
));
971 //! To be called when done with all activities concerning video before /time/.
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
);
990 //! To be called as soon as video frame /frame/ is being performed.
992 PlaybackManager::SetPerformanceFrame(int64 frame
)
994 SetPerformanceTime(TimeForFrame(frame
));
998 /*! Similar to SetPerformanceFrame() just with a time instead of a frame
1001 PlaybackManager::SetPerformanceTime(bigtime_t time
)
1003 int64 oldCurrentFrame
= CurrentFrame();
1004 fPerformanceTime
= time
;
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
1021 PlaybackManager::AddListener(PlaybackListener
* listener
)
1029 if (!fListeners
.HasItem(listener
) && fListeners
.AddItem(listener
)) {
1030 // bring listener up2date, if we have been initialized
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());
1047 PlaybackManager::RemoveListener(PlaybackListener
* listener
)
1049 if (listener
&& Lock()) {
1050 fListeners
.RemoveItem(listener
);
1057 PlaybackManager::NotifyPlayModeChanged(int32 mode
) const
1060 PlaybackListener
* listener
= (PlaybackListener
*)fListeners
.ItemAt(i
);
1062 listener
->PlayModeChanged(mode
);
1068 PlaybackManager::NotifyLoopModeChanged(int32 mode
) const
1071 PlaybackListener
* listener
= (PlaybackListener
*)fListeners
.ItemAt(i
);
1073 listener
->LoopModeChanged(mode
);
1079 PlaybackManager::NotifyLoopingEnabledChanged(bool enabled
) const
1082 PlaybackListener
* listener
= (PlaybackListener
*)fListeners
.ItemAt(i
);
1084 listener
->LoopingEnabledChanged(enabled
);
1090 PlaybackManager::NotifyVideoBoundsChanged(BRect bounds
) const
1093 PlaybackListener
* listener
= (PlaybackListener
*)fListeners
.ItemAt(i
);
1095 listener
->VideoBoundsChanged(bounds
);
1101 PlaybackManager::NotifyFPSChanged(float fps
) const
1104 PlaybackListener
* listener
= (PlaybackListener
*)fListeners
.ItemAt(i
);
1106 listener
->FramesPerSecondChanged(fps
);
1112 PlaybackManager::NotifyCurrentFrameChanged(int64 frame
) const
1115 PlaybackListener
* listener
= (PlaybackListener
*)fListeners
.ItemAt(i
);
1117 listener
->CurrentFrameChanged(frame
);
1123 PlaybackManager::NotifySpeedChanged(float speed
) const
1126 PlaybackListener
* listener
= (PlaybackListener
*)fListeners
.ItemAt(i
);
1128 listener
->SpeedChanged(speed
);
1134 PlaybackManager::NotifyFrameDropped() const
1137 PlaybackListener
* listener
= (PlaybackListener
*)fListeners
.ItemAt(i
);
1139 listener
->FrameDropped();
1145 PlaybackManager::NotifyStopFrameReached() const
1147 // not currently implemented in PlaybackListener interface
1152 PlaybackManager::NotifySeekHandled(int64 frame
) const
1154 // not currently implemented in PlaybackListener interface
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
,
1170 state
->first_visible_frame
,
1171 state
->last_visible_frame
,
1172 // state->selection,
1179 PlaybackManager::PrintStateAtFrame(int64 frame
)
1181 TRACE("frame %lld: ", frame
);
1182 PrintState(_StateAtFrame(frame
));
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
1199 PlaybackManager::_PushState(PlayingState
* state
, bool adjustCurrentFrame
)
1201 // if (!_LastState())
1202 // debugger("PlaybackManager::_PushState() used before Init()\n");
1204 TRACE("PlaybackManager::_PushState()\n");
1208 // unset fStopPlayingFrame
1209 int64 oldStopPlayingFrame
= fStopPlayingFrame
;
1210 fStopPlayingFrame
= -1;
1212 PlayingState
* lastState
= _LastState();
1213 int64 activationFrame
= max(max(state
->activation_frame
,
1214 lastState
->activation_frame
),
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
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
);
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
);
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
);
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;
1269 speedInfo
->speed
= speedInfo
->set_speed
;
1270 speedInfo
->activation_frame
= state
->activation_frame
;
1271 _PushSpeedInfo(speedInfo
);
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
;
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. */
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
);
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. */
1337 PlaybackManager::_IndexForFrame(int64 frame
) const
1340 PlayingState
* state
;
1341 while (((state
= _StateAt(index
+ 1))) && state
->activation_frame
<= frame
)
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. */
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
));
1386 PlaybackManager::_PlayingDirectionFor(int32 playingMode
)
1388 int32 direction
= 0;
1389 switch (playingMode
) {
1390 case MODE_PLAYING_FORWARD
:
1393 case MODE_PLAYING_BACKWARD
:
1396 case MODE_PLAYING_PAUSED_FORWARD
:
1397 case MODE_PLAYING_PAUSED_BACKWARD
:
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
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. */
1417 PlaybackManager::_GetPlayingBoundsFor(PlayingState
* state
, int64
& startFrame
,
1418 int64
& endFrame
, int64
& frameCount
)
1420 switch (state
->loop_mode
) {
1423 endFrame
= max(startFrame
, state
->frame_count
- 1);
1424 frameCount
= endFrame
- startFrame
+ 1;
1427 startFrame
= state
->start_frame
;
1428 endFrame
= state
->end_frame
;
1429 frameCount
= endFrame
- startFrame
+ 1;
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,
1439 // startFrame = state->current_frame;
1440 // endFrame = state->current_frame;
1444 case LOOPING_VISIBLE
:
1445 startFrame
= state
->first_visible_frame
;
1446 endFrame
= state
->last_visible_frame
;
1447 frameCount
= endFrame
- startFrame
+ 1;
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. */
1457 PlaybackManager::_PlayingStartFrameFor(PlayingState
* state
)
1459 int64 startFrame
, endFrame
, frameCount
, frame
= 0;
1460 _GetPlayingBoundsFor(state
, startFrame
, endFrame
, frameCount
);
1461 switch (_PlayingDirectionFor(state
)) {
1469 frame
= state
->current_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. */
1480 PlaybackManager::_PlayingEndFrameFor(PlayingState
* state
)
1482 int64 startFrame
, endFrame
, frameCount
, frame
= 0;
1483 _GetPlayingBoundsFor(state
, startFrame
, endFrame
, frameCount
);
1484 switch (_PlayingDirectionFor(state
)) {
1492 frame
= state
->current_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
1506 PlaybackManager::_RangeFrameForFrame(PlayingState
* state
, int64 frame
)
1508 TRACE("PlaybackManager::_RangeFrameForFrame(%lld)\n", frame
);
1509 int64 startFrame
, endFrame
, frameCount
;
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
) {
1517 case LOOPING_VISIBLE
:
1518 index
= frame
- startFrame
;
1521 TRACE("PlaybackManager::_RangeFrameForFrame() done: %lld\n", 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. */
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
,
1536 // map the index into the index interval of the playing range
1538 index
= (index
% frameCount
+ frameCount
) % frameCount
;
1540 // get the frame for the index
1541 int64 frame
= startFrame
;
1542 switch (state
->loop_mode
) {
1545 case LOOPING_VISIBLE
:
1546 frame
= startFrame
+ index
;
1549 TRACE("PlaybackManager::_FrameForRangeFrame() done: %ld\n", frame
);
1554 /*! Given an arbitrary Playlist frame this function returns the next frame within
1555 the playing range for the supplied playing state. */
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
);
1565 int64 index
= _RangeFrameForFrame(state
, frame
);
1566 newFrame
= _FrameForRangeFrame(state
, index
);
1567 if (newFrame
> frame
&& _PlayingDirectionFor(state
) == -1)
1568 newFrame
= _FrameForRangeFrame(state
, index
- 1);
1575 PlaybackManager::_PushSpeedInfo(SpeedInfo
* info
)
1577 #if SUPPORT_SPEED_CHANGES
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
);
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);
1600 PlaybackManager::SpeedInfo
*
1601 PlaybackManager::_LastSpeedInfo() const
1603 #if SUPPORT_SPEED_CHANGES
1604 return (SpeedInfo
*)fSpeeds
.ItemAt(fSpeeds
.CountItems() - 1);
1611 PlaybackManager::SpeedInfo
*
1612 PlaybackManager::_SpeedInfoAt(int32 index
) const
1614 #if SUPPORT_SPEED_CHANGES
1615 return (SpeedInfo
*)fSpeeds
.ItemAt(index
);
1623 PlaybackManager::_SpeedInfoIndexForFrame(int64 frame
) const
1626 #if SUPPORT_SPEED_CHANGES
1628 while (((info
= _SpeedInfoAt(index
+ 1)))
1629 && info
->activation_frame
<= frame
) {
1632 //fprintf(stderr, "PlaybackManager::_SpeedInfoIndexForFrame(%lld): %ld\n",
1640 PlaybackManager::_SpeedInfoIndexForTime(bigtime_t time
) const
1643 #if SUPPORT_SPEED_CHANGES
1645 while (((info
= _SpeedInfoAt(index
+ 1)))
1646 && info
->activation_time
<= time
) {
1649 //fprintf(stderr, "PlaybackManager::_SpeedInfoIndexForTime(%lld): %ld\n",
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
));
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);
1684 /*! Returns the end time for the last video frame that the video and the
1685 audio producer both have completely processed. */
1687 PlaybackManager::_TimeForLastFrame() const
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. */
1700 PlaybackManager::_TimeForNextFrame() const
1702 return TimeForFrame(NextFrame());
1707 PlaybackManager::_CheckStopPlaying()
1709 //printf("_CheckStopPlaying() - %lld, next: %lld\n", fStopPlayingFrame, NextFrame());
1710 if (fStopPlayingFrame
> 0 && fStopPlayingFrame
<= NextFrame()) {
1712 NotifyStopFrameReached();
1718 PlaybackManager::_NotifySeekHandledIfNecessary(PlayingState
* state
)
1720 if (state
->is_seek_request
) {
1721 state
->is_seek_request
= false;
1722 NotifySeekHandled(state
->current_frame
);