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