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