From ab18a502299fa5a8d32768b07814836ef365380b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stephan=20A=C3=9Fmus?= Date: Mon, 16 Nov 2009 22:48:19 +0000 Subject: [PATCH] * Moved the about alert handling into the application * Simplified the handling of the first window and removed FirstWindow(), we can tell by fPlayerCount. * Both the above would fix a crash when requesting the about alert with the first window already gone. Respectively another player instance opening if fFirstWindow was reset to NULL after some recent revision. * Implemented restoring the current playlist, index and position in the file. * Devised a more robust way to solve asynchronous seeking. The Controller is now notified that a seek request has been handled with a dedicated hook. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@34079 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/apps/mediaplayer/Controller.cpp | 51 ++++- src/apps/mediaplayer/Controller.h | 8 +- src/apps/mediaplayer/MainApp.cpp | 93 ++++++-- src/apps/mediaplayer/MainApp.h | 20 +- src/apps/mediaplayer/MainWin.cpp | 50 +++-- src/apps/mediaplayer/MainWin.h | 2 + .../media_node_framework/PlaybackManager.cpp | 210 +++++++++++------- .../media_node_framework/PlaybackManager.h | 3 +- .../mediaplayer/support/SettingsMessage.cpp | 6 +- 9 files changed, 295 insertions(+), 148 deletions(-) diff --git a/src/apps/mediaplayer/Controller.cpp b/src/apps/mediaplayer/Controller.cpp index ec74a24e95..c9d7870917 100644 --- a/src/apps/mediaplayer/Controller.cpp +++ b/src/apps/mediaplayer/Controller.cpp @@ -106,8 +106,7 @@ Controller::Controller() fPosition(0), fDuration(0), fVideoFrameRate(25.0), - fSeekFrame(-1), - fLastSeekEventTime(LONGLONG_MIN), + fSeekRequested(false), fGlobalSettingsListener(this), @@ -316,6 +315,8 @@ Controller::SetTo(const PlaylistItemRef& item) const media_format& audioTrackFormat = fAudioTrackSupplier->Format(); audioFrameRate = audioTrackFormat.u.raw_audio.frame_rate; audioChannels = audioTrackFormat.u.raw_audio.channel_count; +// if (fVideoTrackSupplier == NULL) +// fVideoFrameRate = audioFrameRate; } if (InitCheck() != B_OK) { @@ -659,13 +660,33 @@ Controller::SetPosition(float value) { BAutolock _(this); - fSeekFrame = (int32)(Duration() * value); + SetFramePosition(Duration() * value); +} + + +void +Controller::SetFramePosition(int32 value) +{ +printf("Controller::SetFramePosition(%ld)\n", value); + BAutolock _(this); + + int32 seekFrame = max_c(0, min_c(Duration(), value)); int32 currentFrame = CurrentFrame(); - if (fSeekFrame != currentFrame) { - SetCurrentFrame(fSeekFrame); - fLastSeekEventTime = system_time(); - } else - fSeekFrame = -1; + if (seekFrame != currentFrame) { +printf(" adjusted seek frame\n"); + fSeekFrame = seekFrame; + fSeekRequested = true; + SetCurrentFrame(seekFrame); + } +} + + +void +Controller::SetTimePosition(bigtime_t value) +{ + BAutolock _(this); + + SetPosition((float)value / TimeDuration()); } @@ -1009,11 +1030,11 @@ Controller::NotifyCurrentFrameChanged(int32 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 ((system_time() - fLastSeekEventTime) < 1000000 - && fSeekFrame >= 0 && frame != fSeekFrame) { + if (fSeekRequested && fSeekFrame != frame) return; - } + fSeekFrame = -1; + fSeekRequested = false; float position = 0.0; double duration = (double)fDuration * fVideoFrameRate / 1000000.0; @@ -1045,3 +1066,11 @@ Controller::NotifyStopFrameReached() const _NotifyFileFinished(); } + +void +Controller::NotifySeekHandled() const +{ + fSeekRequested = false; + fSeekFrame = -1; +} + diff --git a/src/apps/mediaplayer/Controller.h b/src/apps/mediaplayer/Controller.h index 827a5b4fb4..9e99c9f245 100644 --- a/src/apps/mediaplayer/Controller.h +++ b/src/apps/mediaplayer/Controller.h @@ -115,6 +115,8 @@ public: void VolumeDown(); void ToggleMute(); void SetPosition(float value); + void SetFramePosition(int32 frame); + void SetTimePosition(bigtime_t position); bool HasFile(); status_t GetFileFormatInfo( @@ -166,6 +168,7 @@ private: virtual void NotifySpeedChanged(float speed) const; virtual void NotifyFrameDropped() const; virtual void NotifyStopFrameReached() const; + virtual void NotifySeekHandled() const; VideoView* fVideoView; @@ -187,8 +190,9 @@ private: mutable bigtime_t fPosition; bigtime_t fDuration; float fVideoFrameRate; - mutable int32 fSeekFrame; - bigtime_t fLastSeekEventTime; + + mutable bool fSeekRequested; + mutable int32 fSeekFrame; ListenerAdapter fGlobalSettingsListener; diff --git a/src/apps/mediaplayer/MainApp.cpp b/src/apps/mediaplayer/MainApp.cpp index 87e7ebfe98..e31bdbdc26 100644 --- a/src/apps/mediaplayer/MainApp.cpp +++ b/src/apps/mediaplayer/MainApp.cpp @@ -50,7 +50,6 @@ MainApp::MainApp() : BApplication(kAppSig), fPlayerCount(0), - fFirstWindow(NULL), fSettingsWindow(NULL), fOpenFilePanel(NULL), @@ -94,25 +93,12 @@ MainApp::QuitRequested() } -BWindow* -MainApp::FirstWindow() -{ - BAutolock _(this); - if (fFirstWindow != NULL) - return fFirstWindow; - return NewWindow(); -} - - -BWindow* +MainWin* MainApp::NewWindow() { BAutolock _(this); fPlayerCount++; - BWindow* window = new MainWin(fFirstWindow == NULL); - if (fFirstWindow == NULL) - fFirstWindow = window; - return window; + return new(std::nothrow) MainWin(fPlayerCount == 1); } @@ -157,7 +143,18 @@ MainApp::ReadyToRun() } // make sure we have at least one window open - FirstWindow(); + if (fPlayerCount == 0) { + MainWin* window = NewWindow(); + if (window == NULL) { + PostMessage(B_QUIT_REQUESTED); + return; + } + BMessage lastPlaylistArchive; + if (_RestoreCurrentPlaylist(&lastPlaylistArchive) == B_OK) + window->OpenPlaylist(&lastPlaylistArchive); + + window->Show(); + } // setup the settings window now, we need to have it fSettingsWindow = new SettingsWindow(BRect(150, 150, 450, 520)); @@ -175,13 +172,13 @@ MainApp::RefsReceived(BMessage* message) // ArgvReceived() but without MIME type check. // For each file we create a new window and send it a // B_REFS_RECEIVED message with a single file. - // If IsLaunching() is true, we use fFirstWindow as first - // window. printf("MainApp::RefsReceived\n"); BWindow* window = NewWindow(); - if (window) + if (window != NULL) { + window->Show(); window->PostMessage(message); + } } @@ -231,8 +228,6 @@ MainApp::MessageReceived(BMessage* message) && message->FindBool("audio only", &audioOnly) == B_OK && message->FindRect("window frame", &windowFrame) == B_OK && message->FindInt64("creation time", &creationTime) == B_OK) { - if (window == fFirstWindow) - fFirstWindow = NULL; if (audioOnly) { if (!fAudioWindowFrameSaved || creationTime < fLastSavedAudioWindowCreationTime) { @@ -245,6 +240,15 @@ MainApp::MessageReceived(BMessage* message) } } } + + // Store the playlist if there is one. Since the app is doing + // this, it is "atomic". If the user has multiple instances + // playing audio at the same time, the last instance which is + // quit wins. + BMessage playlistArchive; + if (message->FindMessage("playlist", &playlistArchive) == B_OK) + _StoreCurrentPlaylist(&playlistArchive); + // quit if this was the last player window fPlayerCount--; if (fPlayerCount == 0) @@ -340,7 +344,13 @@ MainApp::MessageReceived(BMessage* message) void MainApp::AboutRequested() { - FirstWindow()->PostMessage(B_ABOUT_REQUESTED); + BAlert* alert = new BAlert("about", NAME"\n\n Written by Marcus Overhagen " + ", Stephan Aßmus and Frederik Modéen", "Thanks"); + alert->SetFeel(B_FLOATING_ALL_WINDOW_FEEL); + // Make sure it is on top of any player windows that may have the + // floating all window feel. + alert->Go(NULL); + // asynchronous mode } @@ -508,6 +518,43 @@ MainApp::_HandleFilePanelResult(BFilePanel* panel, const BMessage* message) } +static const char* kCurrentPlaylistFilename = "MediaPlayer Current Playlist"; + + +void +MainApp::_StoreCurrentPlaylist(const BMessage* message) const +{ + BPath path; + if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) != B_OK + || path.Append(kCurrentPlaylistFilename) != B_OK) { + return; + } + + BFile file(path.Path(), B_WRITE_ONLY | B_CREATE_FILE | B_ERASE_FILE); + if (file.InitCheck() != B_OK) + return; + + message->Flatten(&file); +} + + +status_t +MainApp::_RestoreCurrentPlaylist(BMessage* message) const +{ + BPath path; + if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) != B_OK + || path.Append(kCurrentPlaylistFilename) != B_OK) { + return B_ERROR; + } + + BFile file(path.Path(), B_READ_ONLY); + if (file.InitCheck() != B_OK) + return B_ERROR; + + return message->Unflatten(&file); +} + + // #pragma mark - main diff --git a/src/apps/mediaplayer/MainApp.h b/src/apps/mediaplayer/MainApp.h index 25cc6ff967..d64d46bb67 100644 --- a/src/apps/mediaplayer/MainApp.h +++ b/src/apps/mediaplayer/MainApp.h @@ -49,6 +49,10 @@ enum { M_MEDIA_SERVER_QUIT = 'msqt' }; + +#define NAME "MediaPlayer" + + class BFilePanel; class SettingsWindow; @@ -58,8 +62,7 @@ public: MainApp(); virtual ~MainApp(); - BWindow* FirstWindow(); - BWindow* NewWindow(); + MainWin* NewWindow(); int32 PlayerCount() const; private: @@ -81,13 +84,20 @@ private: const char* defaultTitle, const char* defaultLabel); - void _HandleOpenPanelResult(const BMessage* message); - void _HandleSavePanelResult(const BMessage* message); + void _HandleOpenPanelResult( + const BMessage* message); + void _HandleSavePanelResult( + const BMessage* message); void _HandleFilePanelResult(BFilePanel* panel, const BMessage* message); + void _StoreCurrentPlaylist( + const BMessage* message) const; + status_t _RestoreCurrentPlaylist( + BMessage* message) const; + +private: int32 fPlayerCount; - BWindow* fFirstWindow; SettingsWindow* fSettingsWindow; BFilePanel* fOpenFilePanel; diff --git a/src/apps/mediaplayer/MainWin.cpp b/src/apps/mediaplayer/MainWin.cpp index 3f1538d59b..4e6320fd2e 100644 --- a/src/apps/mediaplayer/MainWin.cpp +++ b/src/apps/mediaplayer/MainWin.cpp @@ -53,7 +53,6 @@ #include "PlaylistWindow.h" #include "Settings.h" -#define NAME "MediaPlayer" #define MIN_WIDTH 250 @@ -129,7 +128,8 @@ MainWin::MainWin(bool isFirstWindow) fWidthAspect(0), fHeightAspect(0), fMouseDownTracking(false), - fGlobalSettingsListener(this) + fGlobalSettingsListener(this), + fInitialSeekPosition(0) { // Handle window position and size depending on whether this is the // first window or not. Use the window size from the window that was @@ -218,8 +218,6 @@ MainWin::MainWin(bool isFirstWindow) AddShortcut('y', B_COMMAND_KEY, new BMessage(B_UNDO)); AddShortcut('z', B_COMMAND_KEY | B_SHIFT_KEY, new BMessage(B_REDO)); AddShortcut('y', B_COMMAND_KEY | B_SHIFT_KEY, new BMessage(B_REDO)); - - Show(); } @@ -367,7 +365,7 @@ MainWin::DispatchMessage(BMessage *msg, BHandler *handler) void -MainWin::MessageReceived(BMessage *msg) +MainWin::MessageReceived(BMessage* msg) { // msg->PrintToStream(); switch (msg->what) { @@ -549,19 +547,8 @@ MainWin::MessageReceived(BMessage *msg) ShowPlaylistWindow(); break; case B_ABOUT_REQUESTED: - { - BAlert *alert; - alert = new BAlert("about", NAME"\n\n Written by Marcus Overhagen " - ", Stephan Aßmus and Frederik Modéen", "Thanks"); - if (fAlwaysOnTop) { - _ToggleAlwaysOnTop(); - alert->Go(NULL); // Asynchronous mode - _ToggleAlwaysOnTop(); - } else { - alert->Go(NULL); // Asynchronous mode - } + be_app->PostMessage(msg); break; - } case M_FILE_CLOSE: PostMessage(B_QUIT_REQUESTED); break; @@ -728,7 +715,7 @@ MainWin::QuitRequested() message.AddBool("audio only", !fHasVideo); message.AddInt64("creation time", fCreationTime); if (!fHasVideo && fHasAudio) { - // store playlist and position if this is audio + // store playlist, current index and position if this is audio BMessage playlistArchive; BAutolock controllerLocker(fController); @@ -737,6 +724,8 @@ MainWin::QuitRequested() BAutolock playlistLocker(fPlaylist); if (fPlaylist->Archive(&playlistArchive) != B_OK + || playlistArchive.AddInt32("index", + fPlaylist->CurrentItemIndex()) != B_OK || message.AddMessage("playlist", &playlistArchive) != B_OK) { fprintf(stderr, "Failed to store current playlist.\n"); } @@ -756,6 +745,29 @@ MainWin::MenusBeginning() // #pragma mark - +void +MainWin::OpenPlaylist(const BMessage* playlistArchive) +{ + if (playlistArchive == NULL) + return; + + BAutolock _(this); + BAutolock playlistLocker(fPlaylist); + + if (fPlaylist->Unarchive(playlistArchive) != B_OK) + return; + + int32 currentIndex; + if (playlistArchive->FindInt32("index", ¤tIndex) != B_OK) + currentIndex = 0; + fPlaylist->SetCurrentItemIndex(currentIndex); + + playlistLocker.Unlock(); + + playlistArchive->FindInt64("position", (int64*)&fInitialSeekPosition); +} + + void MainWin::OpenPlaylistItem(const PlaylistItemRef& item) { @@ -794,6 +806,8 @@ MainWin::OpenPlaylistItem(const PlaylistItemRef& item) fHasVideo = fController->VideoTrackCount() != 0; fHasAudio = fController->AudioTrackCount() != 0; SetTitle(item->Name().String()); + fController->SetTimePosition(fInitialSeekPosition); + fInitialSeekPosition = 0; } _SetupWindow(); } diff --git a/src/apps/mediaplayer/MainWin.h b/src/apps/mediaplayer/MainWin.h index 1a40412920..ffaeb19c7a 100644 --- a/src/apps/mediaplayer/MainWin.h +++ b/src/apps/mediaplayer/MainWin.h @@ -56,6 +56,7 @@ public: virtual bool QuitRequested(); virtual void MenusBeginning(); + void OpenPlaylist(const BMessage* playlistArchive); void OpenPlaylistItem(const PlaylistItemRef& item); void ShowFileInfo(); @@ -162,6 +163,7 @@ private: ListenerAdapter fGlobalSettingsListener; bool fCloseWhenDonePlayingMovie; bool fCloseWhenDonePlayingSound; + bigtime_t fInitialSeekPosition; static int sNoVideoWidth; }; diff --git a/src/apps/mediaplayer/media_node_framework/PlaybackManager.cpp b/src/apps/mediaplayer/media_node_framework/PlaybackManager.cpp index 56ac8f65d2..c86fed1a21 100644 --- a/src/apps/mediaplayer/media_node_framework/PlaybackManager.cpp +++ b/src/apps/mediaplayer/media_node_framework/PlaybackManager.cpp @@ -42,9 +42,32 @@ struct PlaybackManager::PlayingState { int32 play_mode; int32 loop_mode; bool looping_enabled; + bool is_seek_request; int64 current_frame; // Playlist frame int64 range_index; // playing range index of current_frame int64 activation_frame; // absolute video frame + + PlayingState() + { + } + + PlayingState(const PlayingState& other) + : + start_frame(other.start_frame), + end_frame(other.end_frame), + frame_count(other.frame_count), + first_visible_frame(other.first_visible_frame), + last_visible_frame(other.last_visible_frame), + max_frame_count(other.max_frame_count), + play_mode(other.play_mode), + loop_mode(other.loop_mode), + looping_enabled(other.looping_enabled), + is_seek_request(false), + current_frame(other.current_frame), + range_index(other.range_index), + activation_frame(other.activation_frame) + { + } }; @@ -116,6 +139,7 @@ PlaybackManager::Init(float frameRate, int32 loopingMode, bool loopingEnabled, state->play_mode = MODE_PLAYING_PAUSED_FORWARD; state->loop_mode = loopingMode; state->looping_enabled = loopingEnabled; + state->is_seek_request = false; state->current_frame = currentFrame; state->activation_frame = 0; fStates.AddItem(state); @@ -356,10 +380,13 @@ PlaybackManager::DurationChanged() void PlaybackManager::SetCurrentFrame(int64 frame) { - if (_LastState()->current_frame == frame) + if (_LastState()->current_frame == frame) { + NotifySeekHandled(); return; + } PlayingState* newState = new PlayingState(*_LastState()); newState->current_frame = frame; + newState->is_seek_request = true; _PushState(newState, false); } @@ -731,7 +758,7 @@ PlaybackManager::GetPlaylistTimeInterval(bigtime_t startTime, bigtime_t endTimeForFrame = TimeForFrame(endFrame); endTime = min(endTime, endTimeForFrame); bigtime_t intervalLength = endTime - startTime; - + // Finally determine the time bounds for the Playlist interval (depending // on the playing direction). switch (playingDirection) { @@ -741,7 +768,7 @@ PlaybackManager::GetPlaylistTimeInterval(bigtime_t startTime, // xStartTime = PlaylistTimeForFrame(xStartFrame) // + startTime - TimeForFrame(startFrame); // xEndTime = xStartTime + intervalLength; - + // 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 @@ -829,7 +856,7 @@ return result; /*! Returns the Playlist frame for an Playlist time. - It holds PlaylistTimeForFrame(frame) <= time < + It holds PlaylistTimeForFrame(frame) <= time < PlaylistTimeForFrame(frame + 1). */ int64 PlaybackManager::PlaylistFrameForTime(bigtime_t time) const @@ -1053,7 +1080,14 @@ PlaybackManager::NotifyFrameDropped() const void PlaybackManager::NotifyStopFrameReached() const { - // not currently implemented in PlaybackListener interface + // not currently implemented in PlaybackListener interface +} + + +void +PlaybackManager::NotifySeekHandled() const +{ + // not currently implemented in PlaybackListener interface } @@ -1101,95 +1135,96 @@ PlaybackManager::_PushState(PlayingState* state, bool adjustCurrentFrame) // debugger("PlaybackManager::_PushState() used before Init()\n"); TRACE("PlaybackManager::_PushState()\n"); - if (state) { - // unset fStopPlayingFrame - int64 oldStopPlayingFrame = fStopPlayingFrame; - fStopPlayingFrame = -1; - // get last state - PlayingState* lastState = _LastState(); - int64 activationFrame = max(max(state->activation_frame, - lastState->activation_frame), - NextFrame()); + if (state == NULL) + return; + + // unset fStopPlayingFrame + int64 oldStopPlayingFrame = fStopPlayingFrame; + fStopPlayingFrame = -1; + // get last state + PlayingState* lastState = _LastState(); + int64 activationFrame = max(max(state->activation_frame, + lastState->activation_frame), + NextFrame()); TRACE(" state activation frame: %lld, last state activation frame: %lld, " "NextFrame(): %lld\n", state->activation_frame, lastState->activation_frame, NextFrame()); - int64 currentFrame = 0; - // remember the current frame, if necessary - if (adjustCurrentFrame) - currentFrame = PlaylistFrameAtFrame(activationFrame); - // check whether it is active - // (NOTE: We may want to keep the last state, if it is not active, - // but then the new state should become active after the last one. - // Thus we had to replace `NextFrame()' with `activationFrame'.) - if (lastState->activation_frame >= NextFrame()) { - // it isn't -- remove it - fStates.RemoveItem(fStates.CountItems() - 1); + int64 currentFrame = 0; + // remember the current frame, if necessary + if (adjustCurrentFrame) + currentFrame = PlaylistFrameAtFrame(activationFrame); + // check whether it is active + // (NOTE: We may want to keep the last state, if it is not active, + // but then the new state should become active after the last one. + // Thus we had to replace `NextFrame()' with `activationFrame'.) + if (lastState->activation_frame >= NextFrame()) { + // it isn't -- remove it + fStates.RemoveItem(fStates.CountItems() - 1); TRACE("deleting last \n"); PrintState(lastState); - delete lastState; - } else { - // it is -- keep it - } - // adjust the new state's current frame and activation frame - if (adjustCurrentFrame) - state->current_frame = currentFrame; - int32 playingDirection = _PlayingDirectionFor(state); - if (playingDirection != 0) { - state->current_frame - = _NextFrameInRange(state, state->current_frame); - } else { - // If not playing, we check at least, if the current frame lies - // within the interval [0, max_frame_count). - if (state->current_frame >= state->max_frame_count) - state->current_frame = state->max_frame_count - 1; - if (state->current_frame < 0) - state->current_frame = 0; - } - state->range_index = _RangeFrameForFrame(state, state->current_frame); - state->activation_frame = activationFrame; - fStates.AddItem(state); + delete lastState; + } else { + // it is -- keep it + } + // adjust the new state's current frame and activation frame + if (adjustCurrentFrame) + state->current_frame = currentFrame; + int32 playingDirection = _PlayingDirectionFor(state); + if (playingDirection != 0) { + state->current_frame + = _NextFrameInRange(state, state->current_frame); + } else { + // If not playing, we check at least, if the current frame lies + // within the interval [0, max_frame_count). + if (state->current_frame >= state->max_frame_count) + state->current_frame = state->max_frame_count - 1; + if (state->current_frame < 0) + state->current_frame = 0; + } + state->range_index = _RangeFrameForFrame(state, state->current_frame); + state->activation_frame = activationFrame; + fStates.AddItem(state); PrintState(state); TRACE("_PushState: state count: %ld\n", fStates.CountItems()); - // push a new speed info - SpeedInfo* speedInfo = new SpeedInfo(*_LastSpeedInfo()); - if (playingDirection == 0) - speedInfo->speed = 1.0; - else - speedInfo->speed = speedInfo->set_speed; - speedInfo->activation_frame = state->activation_frame; - _PushSpeedInfo(speedInfo); - // If the new state is a playing state and looping is turned off, - // determine when playing shall stop. - if (playingDirection != 0 && !state->looping_enabled) { - int64 startFrame, endFrame, frameCount; - _GetPlayingBoundsFor(state, startFrame, endFrame, frameCount); - if (playingDirection == -1) - swap(startFrame, endFrame); - // If we shall stop at the frame we start, set the current frame - // to the beginning of the range. - // We have to take care, since this state may equal the one - // before (or probably differs in just one (unimportant) - // parameter). This happens for instance, if the user changes the - // data or start/end frame... while playing. In this case setting - // the current frame to the start frame is unwanted. Therefore - // we check whether the previous state was intended to stop - // at the activation frame of this state. - if (oldStopPlayingFrame != state->activation_frame - && state->current_frame == endFrame && frameCount > 1) { - state->current_frame = startFrame; - state->range_index - = _RangeFrameForFrame(state, state->current_frame); - } - if (playingDirection == 1) { // forward - fStopPlayingFrame = state->activation_frame - + frameCount - state->range_index - 1; - } else { // backwards - fStopPlayingFrame = state->activation_frame - + state->range_index; - } - _CheckStopPlaying(); + // push a new speed info + SpeedInfo* speedInfo = new SpeedInfo(*_LastSpeedInfo()); + if (playingDirection == 0) + speedInfo->speed = 1.0; + else + speedInfo->speed = speedInfo->set_speed; + speedInfo->activation_frame = state->activation_frame; + _PushSpeedInfo(speedInfo); + // If the new state is a playing state and looping is turned off, + // determine when playing shall stop. + if (playingDirection != 0 && !state->looping_enabled) { + int64 startFrame, endFrame, frameCount; + _GetPlayingBoundsFor(state, startFrame, endFrame, frameCount); + if (playingDirection == -1) + swap(startFrame, endFrame); + // If we shall stop at the frame we start, set the current frame + // to the beginning of the range. + // We have to take care, since this state may equal the one + // before (or probably differs in just one (unimportant) + // parameter). This happens for instance, if the user changes the + // data or start/end frame... while playing. In this case setting + // the current frame to the start frame is unwanted. Therefore + // we check whether the previous state was intended to stop + // at the activation frame of this state. + if (oldStopPlayingFrame != state->activation_frame + && state->current_frame == endFrame && frameCount > 1) { + state->current_frame = startFrame; + state->range_index + = _RangeFrameForFrame(state, state->current_frame); } + if (playingDirection == 1) { // forward + fStopPlayingFrame = state->activation_frame + + frameCount - state->range_index - 1; + } else { // backwards + fStopPlayingFrame = state->activation_frame + + state->range_index; + } + _CheckStopPlaying(); } TRACE("PlaybackManager::_PushState() done\n"); } @@ -1213,6 +1248,11 @@ PlaybackManager::_UpdateStates() TRACE("_UpdateStates: states removed: %ld, state count: %ld\n", firstActive, fStates.CountItems()); } + PlayingState* currentState = _StateAt(firstActive); + if (currentState != NULL && currentState->is_seek_request) { + currentState->is_seek_request = false; + NotifySeekHandled(); + } } diff --git a/src/apps/mediaplayer/media_node_framework/PlaybackManager.h b/src/apps/mediaplayer/media_node_framework/PlaybackManager.h index a580abbb67..1b779c6e96 100644 --- a/src/apps/mediaplayer/media_node_framework/PlaybackManager.h +++ b/src/apps/mediaplayer/media_node_framework/PlaybackManager.h @@ -1,4 +1,4 @@ -/* +/* * Copyright (c) 2000-2008, Ingo Weinhold , * Copyright (c) 2000-2008, Stephan Aßmus , * All Rights Reserved. Distributed under the terms of the MIT license. @@ -169,6 +169,7 @@ public: virtual void NotifySpeedChanged(float speed) const; virtual void NotifyFrameDropped() const; virtual void NotifyStopFrameReached() const; + virtual void NotifySeekHandled() const; // debugging void PrintState(PlayingState* state); diff --git a/src/apps/mediaplayer/support/SettingsMessage.cpp b/src/apps/mediaplayer/support/SettingsMessage.cpp index c3f7529128..dad98820b2 100644 --- a/src/apps/mediaplayer/support/SettingsMessage.cpp +++ b/src/apps/mediaplayer/support/SettingsMessage.cpp @@ -1,6 +1,6 @@ /* - * Copyright 2008 Stephan Aßmus . - * Copyright 1998 Eric Shepherd. + * Copyright 2008, Stephan Aßmus . + * Copyright 1998, Eric Shepherd. * All rights reserved. Distributed under the terms of the Be Sample Code * license. */ @@ -159,7 +159,7 @@ SettingsMessage::SetValue(const char* name, const BString& value) status_t -SettingsMessage::SetValue(const char* name, const BPoint& value) +SettingsMessage::SetValue(const char* name, const BPoint& value) { if (ReplacePoint(name, value) == B_OK) return B_OK;