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