* 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
This commit is contained in:
parent
9a7463857a
commit
ab18a50229
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
@ -1057,6 +1084,13 @@ PlaybackManager::NotifyStopFrameReached() const
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PlaybackManager::NotifySeekHandled() const
|
||||
{
|
||||
// not currently implemented in PlaybackListener interface
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PlaybackManager::PrintState(PlayingState* state)
|
||||
{
|
||||
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -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);
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright 2008 Stephan Aßmus <superstippi@gmx.de>.
|
||||
* Copyright 1998 Eric Shepherd.
|
||||
* Copyright 2008, Stephan Aßmus <superstippi@gmx.de>.
|
||||
* Copyright 1998, Eric Shepherd.
|
||||
* All rights reserved. Distributed under the terms of the Be Sample Code
|
||||
* license.
|
||||
*/
|
||||
|
Loading…
Reference in New Issue
Block a user