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