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