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