Author: stippi Date: 2010-09-09 23:30:36 +0200 (Thu, 09 Sep 2010) New Revision: 38594 Changeset: http://dev.haiku-os.org/changeset/38594 Ticket: http://dev.haiku-os.org/ticket/2495 Modified: haiku/trunk/src/apps/mediaplayer/Controller.cpp haiku/trunk/src/apps/mediaplayer/Controller.h haiku/trunk/src/apps/mediaplayer/ControllerObserver.cpp haiku/trunk/src/apps/mediaplayer/ControllerObserver.h haiku/trunk/src/apps/mediaplayer/MainWin.cpp haiku/trunk/src/apps/mediaplayer/MainWin.h haiku/trunk/src/apps/mediaplayer/media_node_framework/NodeManager.cpp haiku/trunk/src/apps/mediaplayer/media_node_framework/PlaybackManager.cpp haiku/trunk/src/apps/mediaplayer/media_node_framework/PlaybackManager.h Log: PlaybackManager: * Make sure that the messages which trigger a performance time update a) don't pever pile up and b) that we don't still receive an event after reinitialization (would not have been a problem, at one point I thought it was). * Don't compile in support for changing the playback speed for the moment. * Better support for notifying the reaching of a seek frame, In _UpdateStates(), the wrong state (most often out of bounds) was checked to be a seek request state. Check if a seek request was reached in all other cases where states are removed. Controller: * Simple but important simplification of the problem that seeked frames are reached asynchronously and with a latency: In TimePosition() simply report the seeked frame, if there are still pending seek requests. This allows a consistent view from the outside, i.e. after calling SetTimePosition(), TimePosition() will not return something different. * Use a more robust way to track pending seek requests. A new request may have been issued while not having reached the previous one yet. * Implement a notification for reaching the seek frame, but I didn't need it after all, may come in handy later... MainWin: * Change the cursor left/right keys to support winding. Cursor up/down change the volume, Cmd-up/down skips to the previous/next playlist item, left/right do the winding now, as requested in ticket #2495. Modified: haiku/trunk/src/apps/mediaplayer/Controller.cpp =================================================================== --- haiku/trunk/src/apps/mediaplayer/Controller.cpp 2010-09-09 19:55:09 UTC (rev 38593) +++ haiku/trunk/src/apps/mediaplayer/Controller.cpp 2010-09-09 21:30:36 UTC (rev 38594) @@ -77,6 +77,7 @@ void Controller::Listener::AudioStatsChanged() {} void Controller::Listener::PlaybackStateChanged(uint32) {} void Controller::Listener::PositionChanged(float) {} +void Controller::Listener::SeekHandled(int64 seekFrame) {} void Controller::Listener::VolumeChanged(float) {} void Controller::Listener::MutedChanged(bool) {} @@ -108,11 +109,13 @@ fAudioTrackList(4), fVideoTrackList(2), - fPosition(0), + fCurrentFrame(0), fDuration(0), fVideoFrameRate(25.0), - fSeekRequested(false), + fPendingSeekRequests(0), + fSeekFrame(-1), + fGlobalSettingsListener(this), fListeners(4) @@ -167,12 +170,7 @@ int64 Controller::Duration() { - // This should really be total frames (video frames at that) - // TODO: It is not so nice that the MediaPlayer still measures - // in video frames if only playing audio. Here for example, it will - // return a duration of 0 if the audio clip happens to be shorter than - // one video frame at 25 fps. - return (int64)((double)fDuration * fVideoFrameRate / 1000000.0); + return _FrameDuration(); } @@ -258,11 +256,12 @@ fVideoTrackSupplier = NULL; fAudioTrackSupplier = NULL; + fCurrentFrame = 0; fDuration = 0; fVideoFrameRate = 25.0; + fPendingSeekRequests = 0; fSeekFrame = -1; - fSeekRequested = false; if (fItem.Get() == NULL) return B_BAD_VALUE; @@ -641,7 +640,7 @@ { BAutolock _(this); - return fPosition; + return _TimePosition(); } @@ -649,8 +648,7 @@ Controller::SetVolume(float value) { // printf("Controller::SetVolume %.4f\n", value); - if (!Lock()) - return; + BAutolock _(this); value = max_c(0.0, min_c(2.0, value)); @@ -663,8 +661,6 @@ _NotifyVolumeChanged(fVolume); } - - Unlock(); } void @@ -684,8 +680,7 @@ void Controller::ToggleMute() { - if (!Lock()) - return; + BAutolock _(this); fMuted = !fMuted; @@ -695,8 +690,6 @@ fAudioSupplier->SetVolume(fVolume); _NotifyMutedChanged(fMuted); - - Unlock(); } @@ -709,40 +702,50 @@ } -void +int64 Controller::SetPosition(float value) { BAutolock _(this); - SetFramePosition(Duration() * value); + return SetFramePosition(_FrameDuration() * value); } -void -Controller::SetFramePosition(int32 value) +int64 +Controller::SetFramePosition(int64 value) { BAutolock _(this); - int64 seekFrame = max_c(0, min_c(Duration(), value)); - int64 currentFrame = CurrentFrame(); + fPendingSeekRequests++; + fSeekFrame = max_c(0, min_c(_FrameDuration(), value)); + // Snap to video keyframe, since that will be the fastest // to display and seeking will feel more snappy. if (Duration() > 240 && fVideoTrackSupplier != NULL) - fVideoTrackSupplier->FindKeyFrameForFrame(&seekFrame); - if (seekFrame != currentFrame) { - fSeekFrame = seekFrame; - fSeekRequested = true; - SetCurrentFrame(seekFrame); - } + fVideoTrackSupplier->FindKeyFrameForFrame(&fSeekFrame); + + int64 currentFrame = CurrentFrame(); +//printf("SetFramePosition(%lld) -> %lld (current: %lld, duration: %lld) " +//"(video: %p)\n", value, fSeekFrame, currentFrame, _FrameDuration(), +//fVideoTrackSupplier); + if (fSeekFrame != currentFrame) { + int64 seekFrame = fSeekFrame; + SetCurrentFrame(fSeekFrame); + // May trigger the notification and reset fSeekFrame, + // if next current frame == seek frame. + return seekFrame; + } else + NotifySeekHandled(fSeekFrame); + return currentFrame; } -void +int64 Controller::SetTimePosition(bigtime_t value) { BAutolock _(this); - SetPosition((float)value / TimeDuration()); + return SetPosition((float)value / TimeDuration()); } @@ -924,6 +927,39 @@ } +bigtime_t +Controller::_TimePosition() const +{ + if (fDuration == 0) + return 0; + + // Check if we are still waiting to reach the seekframe, + // pass the last pending seek frame back to the caller, so + // that the view of the current frame/time from the outside + // does not depend on the internal latency to reach requested + // frames asynchronously. + int64 frame; + if (fPendingSeekRequests > 0) + frame = fSeekFrame; + else + frame = fCurrentFrame; + + return frame * fDuration / _FrameDuration(); +} + + +int64 +Controller::_FrameDuration() const +{ + // This should really be total frames (video frames at that) + // TODO: It is not so nice that the MediaPlayer still measures + // in video frames if only playing audio. Here for example, it will + // return a duration of 0 if the audio clip happens to be shorter than + // one video frame at 25 fps. + return (int64)((double)fDuration * fVideoFrameRate / 1000000.0); +} + + // #pragma mark - Notifications @@ -1024,6 +1060,18 @@ void +Controller::_NotifySeekHandled(int64 seekFrame) const +{ + BList listeners(fListeners); + int32 count = listeners.CountItems(); + for (int32 i = 0; i < count; i++) { + Listener* listener = (Listener*)listeners.ItemAtFast(i); + listener->SeekHandled(seekFrame); + } +} + + +void Controller::_NotifyVolumeChanged(float volume) const { BList listeners(fListeners); @@ -1084,20 +1132,8 @@ void Controller::NotifyCurrentFrameChanged(int64 frame) const { - // check if we are still waiting to reach the seekframe, - // don't pass the event on to the listeners in that case - if (fSeekRequested && fSeekFrame != frame) - return; - - fSeekFrame = -1; - fSeekRequested = false; - - float position = 0.0; - double duration = (double)fDuration * fVideoFrameRate / 1000000.0; - if (duration > 0) - position = (float)frame / duration; - fPosition = (bigtime_t)(position * fDuration + 0.5); - _NotifyPositionChanged(position); + fCurrentFrame = frame; + _NotifyPositionChanged((float)_TimePosition() / fDuration); } @@ -1124,9 +1160,15 @@ void -Controller::NotifySeekHandled() const +Controller::NotifySeekHandled(int64 seekedFrame) const { - fSeekRequested = false; - fSeekFrame = -1; + if (fPendingSeekRequests == 0) + return; + + fPendingSeekRequests--; + if (fPendingSeekRequests == 0) + fSeekFrame = -1; + + _NotifySeekHandled(seekedFrame); } Modified: haiku/trunk/src/apps/mediaplayer/Controller.h =================================================================== --- haiku/trunk/src/apps/mediaplayer/Controller.h 2010-09-09 19:55:09 UTC (rev 38593) +++ haiku/trunk/src/apps/mediaplayer/Controller.h 2010-09-09 21:30:36 UTC (rev 38594) @@ -66,6 +66,7 @@ virtual void PlaybackStateChanged(uint32 state); virtual void PositionChanged(float position); + virtual void SeekHandled(int64 seekFrame); virtual void VolumeChanged(float volume); virtual void MutedChanged(bool muted); }; @@ -117,10 +118,11 @@ void VolumeUp(); void VolumeDown(); void ToggleMute(); - void SetPosition(float value); - void SetFramePosition(int32 frame); - void SetTimePosition(bigtime_t position); + int64 SetPosition(float value); + int64 SetFramePosition(int64 frame); + int64 SetTimePosition(bigtime_t position); + bool HasFile(); status_t GetFileFormatInfo( media_file_format* fileFormat); @@ -145,6 +147,8 @@ void _AdoptGlobalSettings(); uint32 _PlaybackState(int32 playingMode) const; + int64 _FrameDuration() const; + bigtime_t _TimePosition() const; void _NotifyFileChanged(PlaylistItem* item, status_t result) const; @@ -157,6 +161,7 @@ void _NotifyPlaybackStateChanged(uint32 state) const; void _NotifyPositionChanged(float position) const; + void _NotifySeekHandled(int64 seekFrame) const; void _NotifyVolumeChanged(float volume) const; void _NotifyMutedChanged(bool muted) const; @@ -172,7 +177,7 @@ virtual void NotifySpeedChanged(float speed) const; virtual void NotifyFrameDropped() const; virtual void NotifyStopFrameReached() const; - virtual void NotifySeekHandled() const; + virtual void NotifySeekHandled(int64 seekedFrame) const; VideoView* fVideoView; @@ -191,12 +196,12 @@ BList fAudioTrackList; BList fVideoTrackList; - mutable bigtime_t fPosition; + mutable int64 fCurrentFrame; bigtime_t fDuration; float fVideoFrameRate; - mutable bool fSeekRequested; - mutable int32 fSeekFrame; + mutable int32 fPendingSeekRequests; + mutable int64 fSeekFrame; ListenerAdapter fGlobalSettingsListener; Modified: haiku/trunk/src/apps/mediaplayer/ControllerObserver.cpp =================================================================== --- haiku/trunk/src/apps/mediaplayer/ControllerObserver.cpp 2010-09-09 19:55:09 UTC (rev 38593) +++ haiku/trunk/src/apps/mediaplayer/ControllerObserver.cpp 2010-09-09 21:30:36 UTC (rev 38594) @@ -134,6 +134,19 @@ void +ControllerObserver::SeekHandled(int64 seekFrame) +{ + if (!(fObserveFlags & OBSERVE_POSITION_CHANGES)) + return; + + BMessage message(MSG_CONTROLLER_SEEK_HANDLED); + message.AddInt64("seek frame", seekFrame); + + DeliverMessage(message); +} + + +void ControllerObserver::VolumeChanged(float volume) { if (!(fObserveFlags & OBSERVE_VOLUME_CHANGES)) Modified: haiku/trunk/src/apps/mediaplayer/ControllerObserver.h =================================================================== --- haiku/trunk/src/apps/mediaplayer/ControllerObserver.h 2010-09-09 19:55:09 UTC (rev 38593) +++ haiku/trunk/src/apps/mediaplayer/ControllerObserver.h 2010-09-09 21:30:36 UTC (rev 38594) @@ -25,6 +25,7 @@ MSG_CONTROLLER_PLAYBACK_STATE_CHANGED = 'cnps', MSG_CONTROLLER_POSITION_CHANGED = 'cnpc', + MSG_CONTROLLER_SEEK_HANDLED = 'cnsh', MSG_CONTROLLER_VOLUME_CHANGED = 'cnvc', MSG_CONTROLLER_MUTED_CHANGED = 'cnmc' }; @@ -60,6 +61,7 @@ virtual void PlaybackStateChanged(uint32 state); virtual void PositionChanged(float position); + virtual void SeekHandled(int64 seekFrame); virtual void VolumeChanged(float volume); virtual void MutedChanged(bool muted); Modified: haiku/trunk/src/apps/mediaplayer/MainWin.cpp =================================================================== --- haiku/trunk/src/apps/mediaplayer/MainWin.cpp 2010-09-09 19:55:09 UTC (rev 38593) +++ haiku/trunk/src/apps/mediaplayer/MainWin.cpp 2010-09-09 21:30:36 UTC (rev 38594) @@ -81,6 +81,7 @@ M_VOLUME_DOWN, M_SKIP_NEXT, M_SKIP_PREV, + M_WIND, // The common display aspect ratios M_ASPECT_SAME_AS_SOURCE, @@ -179,7 +180,8 @@ fMouseMoveDist(0), fGlobalSettingsListener(this), - fInitialSeekPosition(0) + fInitialSeekPosition(0), + fAllowWinding(true) { // Handle window position and size depending on whether this is the // first window or not. Use the window size from the window that was @@ -675,9 +677,13 @@ if (msg->FindFloat("position", &position) == B_OK) { fControls->SetPosition(position, fController->TimePosition(), fController->TimeDuration()); + fAllowWinding = true; } break; } + case MSG_CONTROLLER_SEEK_HANDLED: + break; + case MSG_CONTROLLER_VOLUME_CHANGED: { float volume; @@ -782,6 +788,32 @@ fControls->SkipBackward(); break; + case M_WIND: + { + if (!fAllowWinding) + break; + + bigtime_t howMuch; + if (msg->FindInt64("how much", &howMuch) != B_OK) + break; + + if (fController->Lock()) { + bigtime_t seekTime = fController->TimePosition() + howMuch; + if (seekTime < 0) { + fInitialSeekPosition = seekTime; + PostMessage(M_SKIP_PREV); + } else if (seekTime > fController->TimeDuration()) { + fInitialSeekPosition = 0; + PostMessage(M_SKIP_NEXT); + } else + fController->SetTimePosition(seekTime); + fController->Unlock(); + + fAllowWinding = false; + } + break; + } + case M_VOLUME_UP: fController->VolumeUp(); break; @@ -1248,6 +1280,10 @@ fHasAudio = fController->AudioTrackCount() != 0; SetTitle(item->Name().String()); + if (fInitialSeekPosition < 0) { + fInitialSeekPosition + = fController->TimeDuration() + fInitialSeekPosition; + } fController->SetTimePosition(fInitialSeekPosition); fInitialSeekPosition = 0; } @@ -1401,7 +1437,7 @@ new BMessage(M_TOGGLE_NO_INTERFACE), 'B'); fSettingsMenu->AddItem(fNoInterfaceMenuItem); fSettingsMenu->AddItem(new BMenuItem("Always on top", - new BMessage(M_TOGGLE_ALWAYS_ON_TOP), 'T')); + new BMessage(M_TOGGLE_ALWAYS_ON_TOP), 'A')); fSettingsMenu->AddSeparatorItem(); item = new BMenuItem("Settings"B_UTF8_ELLIPSIS, new BMessage(M_SETTINGS), 'S'); @@ -1872,8 +1908,8 @@ uint32 rawChar = msg->FindInt32("raw_char"); uint32 modifier = msg->FindInt32("modifiers"); - printf("key 0x%lx, rawChar 0x%lx, modifiers 0x%lx\n", key, rawChar, - modifier); +// printf("key 0x%lx, rawChar 0x%lx, modifiers 0x%lx\n", key, rawChar, +// modifier); // ignore the system modifier namespace if ((modifier & (B_CONTROL_KEY | B_COMMAND_KEY)) @@ -1923,16 +1959,28 @@ case B_RIGHT_ARROW: if ((modifier & B_COMMAND_KEY) != 0) - PostMessage(M_VOLUME_UP); - else PostMessage(M_SKIP_NEXT); + else if (fAllowWinding) { + BMessage windMessage(M_WIND); + if ((modifier & B_SHIFT_KEY) != 0) + windMessage.AddInt64("how much", 30000000LL); + else + windMessage.AddInt64("how much", 5000000LL); + PostMessage(&windMessage); + } return true; case B_LEFT_ARROW: if ((modifier & B_COMMAND_KEY) != 0) - PostMessage(M_VOLUME_DOWN); - else PostMessage(M_SKIP_PREV); + else if (fAllowWinding) { + BMessage windMessage(M_WIND); + if ((modifier & B_SHIFT_KEY) != 0) + windMessage.AddInt64("how much", -30000000LL); + else + windMessage.AddInt64("how much", -5000000LL); + PostMessage(&windMessage); + } return true; case B_PAGE_UP: @@ -1942,6 +1990,19 @@ case B_PAGE_DOWN: PostMessage(M_SKIP_PREV); return true; + + case B_DELETE: + case 'd': // d for delete + case 't': // t for Trash + if ((modifiers() & B_COMMAND_KEY) != 0) { + BAutolock _(fPlaylist); + BMessage removeMessage(M_PLAYLIST_REMOVE_AND_PUT_INTO_TRASH); + removeMessage.AddInt32("playlist index", + fPlaylist->CurrentItemIndex()); + fPlaylistWindow->PostMessage(&removeMessage); + return true; + } + break; } switch (key) { @@ -1976,19 +2037,6 @@ case 0x48: // numeric keypad left arrow PostMessage(M_SKIP_PREV); return true; - - case 0x34: // delete button - case 0x3e: // d for delete - case 0x2b: // t for Trash - if ((modifiers() & B_COMMAND_KEY) != 0) { - BAutolock _(fPlaylist); - BMessage removeMessage(M_PLAYLIST_REMOVE_AND_PUT_INTO_TRASH); - removeMessage.AddInt32("playlist index", - fPlaylist->CurrentItemIndex()); - fPlaylistWindow->PostMessage(&removeMessage); - return true; - } - break; } return false; Modified: haiku/trunk/src/apps/mediaplayer/MainWin.h =================================================================== --- haiku/trunk/src/apps/mediaplayer/MainWin.h 2010-09-09 19:55:09 UTC (rev 38593) +++ haiku/trunk/src/apps/mediaplayer/MainWin.h 2010-09-09 21:30:36 UTC (rev 38594) @@ -189,6 +189,7 @@ bool fLoopMovies; bool fLoopSounds; bigtime_t fInitialSeekPosition; + bool fAllowWinding; static int sNoVideoWidth; }; Modified: haiku/trunk/src/apps/mediaplayer/media_node_framework/NodeManager.cpp =================================================================== --- haiku/trunk/src/apps/mediaplayer/media_node_framework/NodeManager.cpp 2010-09-09 19:55:09 UTC (rev 38593) +++ haiku/trunk/src/apps/mediaplayer/media_node_framework/NodeManager.cpp 2010-09-09 21:30:36 UTC (rev 38594) @@ -83,7 +83,8 @@ float speed, uint32 enabledNodes, bool useOverlays) { // init base class - PlaybackManager::Init(videoFrameRate, loopingMode, loopingEnabled, speed); + PlaybackManager::Init(videoFrameRate, true, loopingMode, loopingEnabled, + speed); // get some objects from a derived class if (fVideoTarget == NULL) @@ -142,15 +143,18 @@ // TODO: if enabledNodes would indicate that audio or video // is no longer needed, or, worse yet, suddenly needed when // it wasn't before, then we should not return here! + PlaybackManager::Init(videoFrameRate, false, LoopMode(), + IsLoopingEnabled(), Speed(), MODE_PLAYING_PAUSED_FORWARD, + CurrentFrame()); return B_OK; } - PlaybackManager::Init(videoFrameRate, LoopMode(), IsLoopingEnabled(), - Speed(), MODE_PLAYING_PAUSED_FORWARD, CurrentFrame()); - _StopNodes(); _TearDownNodes(); + PlaybackManager::Init(videoFrameRate, true, LoopMode(), IsLoopingEnabled(), + Speed(), MODE_PLAYING_PAUSED_FORWARD, CurrentFrame()); + SetVideoBounds(videoBounds); status_t ret = _SetUpNodes(preferredVideoFormat, enabledNodes, Modified: haiku/trunk/src/apps/mediaplayer/media_node_framework/PlaybackManager.cpp =================================================================== --- haiku/trunk/src/apps/mediaplayer/media_node_framework/PlaybackManager.cpp 2010-09-09 19:55:09 UTC (rev 38593) +++ haiku/trunk/src/apps/mediaplayer/media_node_framework/PlaybackManager.cpp 2010-09-09 21:30:36 UTC (rev 38594) @@ -36,6 +36,9 @@ } +#define SUPPORT_SPEED_CHANGES 0 + + struct PlaybackManager::PlayingState { int64 start_frame; int64 end_frame; @@ -75,6 +78,7 @@ }; +#if SUPPORT_SPEED_CHANGES struct PlaybackManager::SpeedInfo { int64 activation_frame; // absolute video frame bigtime_t activation_time; // performance time @@ -82,22 +86,25 @@ // is 1.0 if not playing float set_speed; // speed set by the user }; +#endif // #pragma mark - PlaybackManager PlaybackManager::PlaybackManager() - : BLooper("playback manager"), - fStates(10), - fSpeeds(10), - fCurrentAudioTime(0), - fCurrentVideoTime(0), - fPerformanceTime(0), - fFrameRate(1.0), - fStopPlayingFrame(-1), - fListeners(), - fNoAudio(false) + : + BLooper("playback manager"), + fStates(10), + fSpeeds(10), + fCurrentAudioTime(0), + fCurrentVideoTime(0), + fPerformanceTime(0), + fPerformanceTimeEvent(NULL), + fFrameRate(1.0), + fStopPlayingFrame(-1), + fListeners(), + fNoAudio(false) { Run(); } @@ -110,19 +117,23 @@ void -PlaybackManager::Init(float frameRate, int32 loopingMode, bool loopingEnabled, - float playbackSpeed, int32 playMode, int32 currentFrame) +PlaybackManager::Init(float frameRate, bool initPerformanceTimes, + int32 loopingMode, bool loopingEnabled, float playbackSpeed, + int32 playMode, int32 currentFrame) { // cleanup first Cleanup(); // set the new frame rate fFrameRate = frameRate; - fCurrentAudioTime = 0; - fCurrentVideoTime = 0; - fPerformanceTime = 0; + if (initPerformanceTimes) { + fCurrentAudioTime = 0; + fCurrentVideoTime = 0; + fPerformanceTime = 0; + } fStopPlayingFrame = -1; +#if SUPPORT_SPEED_CHANGES // set up the initial speed SpeedInfo* speed = new SpeedInfo; speed->activation_frame = 0; @@ -130,6 +141,7 @@ speed->speed = playbackSpeed; speed->set_speed = playbackSpeed; _PushSpeedInfo(speed); +#endif // set up the initial state PlayingState* state = new PlayingState; @@ -165,15 +177,20 @@ void PlaybackManager::Cleanup() { + if (EventQueue::Default().RemoveEvent(fPerformanceTimeEvent)) + delete fPerformanceTimeEvent; + fPerformanceTimeEvent = NULL; // delete states for (int32 i = 0; PlayingState* state = _StateAt(i); i++) delete state; fStates.MakeEmpty(); +#if SUPPORT_SPEED_CHANGES // delete speed infos for (int32 i = 0; SpeedInfo* speed = _SpeedInfoAt(i); i++) delete speed; fSpeeds.MakeEmpty(); +#endif } @@ -182,9 +199,25 @@ { switch (message->what) { case MSG_EVENT: - SetPerformanceTime(TimeForRealTime(system_time())); -//TRACE("MSG_EVENT: rt: %lld, pt: %lld\n", system_time(), fPerformanceTime); + { + if (fPerformanceTimeEvent == NULL) { + // Stale event message. There is a natural race + // condition when removing the event from the queue, + // it may have already fired, but we have not processed + // the message yet. Simply ignore the event. + break; + } + +// bigtime_t eventTime; +// message->FindInt64("time", &eventTime); + bigtime_t now = system_time(); + fPerformanceTimeEvent = NULL; + + SetPerformanceTime(TimeForRealTime(now)); +//TRACE("MSG_EVENT: rt: %lld, pt: %lld\n", now, fPerformanceTime); +//printf("MSG_EVENT: et: %lld, rt: %lld, pt: %lld\n", eventTime, now, fPerformanceTime); break; + } case MSG_PLAYBACK_FORCE_UPDATE: { @@ -333,9 +366,13 @@ float PlaybackManager::Speed() const { +#if SUPPORT_SPEED_CHANGES if (!_LastState()) return 1.0; return _LastSpeedInfo()->set_speed; +#else + return 1.0; +#endif } @@ -384,8 +421,8 @@ void PlaybackManager::SetCurrentFrame(int64 frame) { - if (_LastState()->current_frame == frame) { - NotifySeekHandled(); + if (CurrentFrame() == frame) { + NotifySeekHandled(frame); return; } PlayingState* newState = new PlayingState(*_LastState()); @@ -465,6 +502,7 @@ void PlaybackManager::SetSpeed(float speed) { +#if SUPPORT_SPEED_CHANGES SpeedInfo* lastSpeed = _LastSpeedInfo(); if (speed != lastSpeed->set_speed) { SpeedInfo* info = new SpeedInfo(*lastSpeed); @@ -476,6 +514,7 @@ info->speed = 1.0; _PushSpeedInfo(info); } +#endif } @@ -676,10 +715,12 @@ int32 endIndex = _IndexForFrame(endFrame); if (startIndex < endIndex) endFrame = _StateAt(startIndex + 1)->activation_frame; +#if SUPPORT_SPEED_CHANGES startIndex = _SpeedInfoIndexForFrame(startFrame); endIndex = _SpeedInfoIndexForFrame(endFrame); if (startIndex < endIndex) endFrame = _SpeedInfoAt(startIndex + 1)->activation_frame; +#endif return endFrame; } @@ -693,10 +734,12 @@ int32 endIndex = _IndexForTime(endTime); if (startIndex < endIndex) endTime = TimeForFrame(_StateAt(startIndex + 1)->activation_frame); +#if SUPPORT_SPEED_CHANGES startIndex = _SpeedInfoIndexForTime(startTime); endIndex = _SpeedInfoIndexForTime(endTime); if (startIndex < endIndex) endTime = TimeForFrame(_SpeedInfoAt(startIndex + 1)->activation_frame); +#endif return endTime; } @@ -751,7 +794,9 @@ // be greater than necessary, but that doesn't harm. int64 startFrame = FrameForTime(startTime); int64 endFrame = FrameForTime(endTime) + 1; - SpeedInfo* info = _SpeedInfoForFrame(startFrame); +#if SUPPORT_SPEED_CHANGES + SpeedInfo* info = _SpeedInfoForFrame(startFrame)->speed; +#endif // Get the Playlist frame interval that belongs to the frame interval. int64 xStartFrame; int64 xEndFrame; @@ -769,33 +814,37 @@ // forward case 1: { -// xStartTime = PlaylistTimeForFrame(xStartFrame) -// + startTime - TimeForFrame(startFrame); -// xEndTime = xStartTime + intervalLength; - +#if SUPPORT_SPEED_CHANGES // TODO: The current method does not handle the times the same way. // It may happen, that for the same performance time different // Playlist times (within a frame) are returned when passing it // one time as a start time and another time as an end time. xStartTime = PlaylistTimeForFrame(xStartFrame) + bigtime_t(double(startTime - TimeForFrame(startFrame)) - * info->speed); + * info->speed); xEndTime = xStartTime - + bigtime_t((double)intervalLength * info->speed); + + bigtime_t((double)intervalLength * info->speed); +#else + xStartTime = PlaylistTimeForFrame(xStartFrame) + + startTime - TimeForFrame(startFrame); + xEndTime = xStartTime + intervalLength; +#endif break; } // backward case -1: { -// xEndTime = PlaylistTimeForFrame(xEndFrame) -// - startTime + TimeForFrame(startFrame); -// xStartTime = xEndTime - intervalLength; - +#if SUPPORT_SPEED_CHANGES xEndTime = PlaylistTimeForFrame(xEndFrame) - bigtime_t(double(startTime - TimeForFrame(startFrame)) - * info->speed); + * info->speed); xStartTime = xEndTime - - bigtime_t((double)intervalLength * info->speed); + - bigtime_t((double)intervalLength * info->speed); +#else + xEndTime = PlaylistTimeForFrame(xEndFrame) + - startTime + TimeForFrame(startFrame); + xStartTime = xEndTime - intervalLength; +#endif break; } // not playing @@ -805,7 +854,11 @@ xEndTime = xStartTime; break; } +#if SUPPORT_SPEED_CHANGES playingSpeed = (float)playingDirection * info->speed; +#else + playingSpeed = (float)playingDirection; +#endif } @@ -815,11 +868,10 @@ PlaybackManager::FrameForTime(bigtime_t time) const { //TRACE("PlaybackManager::FrameForTime(%lld)\n", time); -// return (int64)((double)time * (double)fFrameRate / 1000000.0); // In order to avoid problems caused by rounding errors, we check // if for the resulting frame holds // TimeForFrame(frame) <= time < TimeForFrame(frame + 1). -// int64 frame = (int64)((double)time * (double)fFrameRate / 1000000.0); +#if SUPPORT_SPEED_CHANGES SpeedInfo* info = _SpeedInfoForTime(time); if (!info) { fprintf(stderr, "PlaybackManager::FrameForTime() - no SpeedInfo!\n"); @@ -828,6 +880,10 @@ int64 frame = (int64)(((double)time - info->activation_time) * (double)fFrameRate * info->speed / 1000000.0) + info->activation_frame; + +#else + int64 frame = (int64)((double)time * (double)fFrameRate / 1000000.0); +#endif if (TimeForFrame(frame) > time) frame--; else if (TimeForFrame(frame + 1) <= time) @@ -843,19 +899,18 @@ bigtime_t PlaybackManager::TimeForFrame(int64 frame) const { -// return (bigtime_t)((double)frame * 1000000.0 / (double)fFrameRate); +#if SUPPORT_SPEED_CHANGES SpeedInfo* info = _SpeedInfoForFrame(frame); if (!info) { fprintf(stderr, "PlaybackManager::TimeForFrame() - no SpeedInfo!\n"); return 0; } -// return (bigtime_t)((double)(frame - info->activation_frame) * 1000000.0 -// / ((double)fFrameRate * info->speed)) -// + info->activation_time; -bigtime_t result = (bigtime_t)((double)(frame - info->activation_frame) * 1000000.0 -/ ((double)fFrameRate * info->speed)) + info->activation_time; -//fprintf(stderr, "PlaybackManager::TimeForFrame(%lld): %lld\n", frame, result); -return result; + return (bigtime_t)((double)(frame - info->activation_frame) * 1000000.0 + / ((double)fFrameRate * info->speed)) + + info->activation_time; +#else + return (bigtime_t)((double)frame * 1000000.0 / (double)fFrameRate); +#endif } @@ -892,11 +947,13 @@ TRACE("PlaybackManager::SetCurrentAudioTime(%lld)\n", time); bigtime_t lastFrameTime = _TimeForLastFrame(); fCurrentAudioTime = time; -// _UpdateStates(); bigtime_t newLastFrameTime = _TimeForLastFrame(); if (lastFrameTime != newLastFrameTime) { - bigtime_t eventTime = RealTimeForTime(newLastFrameTime); - EventQueue::Default().AddEvent(new MessageEvent(eventTime, this)); + if (fPerformanceTimeEvent == NULL) { + bigtime_t eventTime = RealTimeForTime(newLastFrameTime); + fPerformanceTimeEvent = new MessageEvent(eventTime, this); + EventQueue::Default().AddEvent(fPerformanceTimeEvent); + } _CheckStopPlaying(); } } @@ -917,11 +974,13 @@ TRACE("PlaybackManager::SetCurrentVideoTime(%lld)\n", time); bigtime_t lastFrameTime = _TimeForLastFrame(); fCurrentVideoTime = time; -// _UpdateStates(); bigtime_t newLastFrameTime = _TimeForLastFrame(); if (lastFrameTime != newLastFrameTime) { - bigtime_t eventTime = RealTimeForTime(newLastFrameTime); - EventQueue::Default().AddEvent(new MessageEvent(eventTime, this)); + if (fPerformanceTimeEvent == NULL) { + bigtime_t eventTime = RealTimeForTime(newLastFrameTime); + fPerformanceTimeEvent = new MessageEvent(eventTime, this); + EventQueue::Default().AddEvent(fPerformanceTimeEvent); + } _CheckStopPlaying(); } } @@ -931,11 +990,11 @@ void PlaybackManager::SetPerformanceFrame(int64 frame) { - SetPerformanceFrame(TimeForFrame(frame)); + SetPerformanceTime(TimeForFrame(frame)); } -/*! Similar to SetPerformanceTime() just with a time instead of a frame +/*! Similar to SetPerformanceFrame() just with a time instead of a frame argument. */ void PlaybackManager::SetPerformanceTime(bigtime_t time) @@ -1089,7 +1148,7 @@ void -PlaybackManager::NotifySeekHandled() const +PlaybackManager::NotifySeekHandled(int64 frame) const { [... truncated: 262 lines follow ...]